From 1ddf3ebc7e6522cc9987aebb95e358ea08b3bcbc Mon Sep 17 00:00:00 2001 From: Dan Date: Sat, 20 Sep 2025 08:20:06 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#73620=20[@types/ma?= =?UTF-8?q?tter.js]=20Update=20type=20definitions=20for=20Matter.Runner=20?= =?UTF-8?q?to=20reflect=20matter.js=20docs=20by=20@danstuff?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Steven Snoeijen <2750503+stevensnoeijen@users.noreply.github.com> --- types/matter-js/index.d.ts | 153 +++++++++++++++++++++++++---- types/matter-js/matter-js-tests.ts | 6 +- 2 files changed, 137 insertions(+), 22 deletions(-) diff --git a/types/matter-js/index.d.ts b/types/matter-js/index.d.ts index 12caa3e61083fed..4a67f51e87b23f5 100644 --- a/types/matter-js/index.d.ts +++ b/types/matter-js/index.d.ts @@ -2704,18 +2704,23 @@ declare namespace Matter { export interface IRunnerOptions { /** - * A `Boolean` that specifies if the runner should use a fixed timestep (otherwise it is variable). - * If timing is fixed, then the apparent simulation speed will change depending on the frame rate (but behaviour will be deterministic). - * If the timing is variable, then the apparent simulation speed will be constant (approximately, but at the cost of determininism). + * The fixed timestep size used for `Engine.update` calls in milliseconds, known as `delta`. * - * @default false - */ - isFixed?: boolean | undefined; - - /** - * A `Number` that specifies the time step between updates in milliseconds. - * If `engine.timing.isFixed` is set to `true`, then `delta` is fixed. - * If it is `false`, then `delta` can dynamically change to maintain the correct apparent simulation speed. + * This value is recommended to be `1000 / 60` ms or smaller (i.e. equivalent to at least 60hz). + * + * Smaller `delta` values provide higher quality results at the cost of performance. + * + * You should usually avoid changing `delta` during running, otherwise quality may be affected. + * + * For smoother frame pacing choose a `delta` that is an even multiple of each display FPS you target, i.e. `1000 / (n * fps)` as this helps distribute an equal number of updates over each display frame. + * + * For example with a 60 Hz `delta` i.e. `1000 / 60` the runner will on average perform one update per frame on displays running 60 FPS and one update every two frames on displays running 120 FPS, etc. + * + * Where as e.g. using a 240 Hz `delta` i.e. `1000 / 240` the runner will on average perform four updates per frame on displays running 60 FPS and two updates per frame on displays running 120 FPS, etc. + * + * Therefore `Runner.run` will call multiple engine updates (or none) as needed to simulate the time elapsed between browser frames. + * + * In practice the number of updates in any particular frame may be restricted to respect the runner's performance budgets. These are specified by `runner.maxFrameTime` and `runner.maxUpdates`, see those properties for details. * * @default 1000 / 60 */ @@ -2723,9 +2728,60 @@ declare namespace Matter { /** * A flag that specifies whether the runner is running or not. + * * @default true */ enabled?: boolean | undefined; + + /** + * The measured time elapsed between the last two browser frames in milliseconds. + * This is useful e.g. to estimate the current browser FPS using `1000 / runner.frameDelta`. + */ + frameDelta?: number | undefined; + + /** + * Enables averaging to smooth frame rate measurements and therefore stabilise play rate. + * + * @default true + */ + frameDeltaSmoothing?: boolean | undefined; + + /** + * Rounds measured browser frame delta to the nearest 1 Hz. + * This option can help smooth frame rate measurements and simplify handling hardware timing differences e.g. 59.94Hz and 60Hz displays. + * For best results you should also round your `runner.delta` equivalent to the nearest 1 Hz. + * + * @default true + */ + frameDeltaSnapping?: boolean | undefined; + + /** + * A performance budget that limits execution time allowed for this runner per browser frame in milliseconds. + * + * To calculate the effective browser FPS at which this throttle is applied use `1000 / runner.maxFrameTime`. + * + * This performance budget is intended to help maintain browser interactivity and help improve framerate recovery during temporary high CPU usage. + * + * This budget only covers the measured time elapsed executing the functions called in the scope of the runner tick, including `Engine.update` and its related user event callbacks. + * + * You may also reduce this budget to allow for any significant additional processing you perform on the same thread outside the scope of this runner tick, e.g. rendering time. + * + * See also `runner.maxUpdates`. + * + * @default 1000 / 30 + */ + maxFrameTime?: number | undefined; + + /** + * An optional limit for maximum engine update count allowed per frame tick in addition to `runner.maxFrameTime`. + * + * Unless you set a value it is automatically chosen based on `runner.delta` and `runner.maxFrameTime`. + * + * See also `runner.maxFrameTime`. + * + * @default null + */ + maxUpdates?: number | null; } /** @@ -2783,6 +2839,29 @@ declare namespace Matter { */ static start(runner: Runner, engine: Engine): void; + /** + * The fixed timestep size used for `Engine.update` calls in milliseconds, known as `delta`. + * + * This value is recommended to be `1000 / 60` ms or smaller (i.e. equivalent to at least 60hz). + * + * Smaller `delta` values provide higher quality results at the cost of performance. + * + * You should usually avoid changing `delta` during running, otherwise quality may be affected. + * + * For smoother frame pacing choose a `delta` that is an even multiple of each display FPS you target, i.e. `1000 / (n * fps)` as this helps distribute an equal number of updates over each display frame. + * + * For example with a 60 Hz `delta` i.e. `1000 / 60` the runner will on average perform one update per frame on displays running 60 FPS and one update every two frames on displays running 120 FPS, etc. + * + * Where as e.g. using a 240 Hz `delta` i.e. `1000 / 240` the runner will on average perform four updates per frame on displays running 60 FPS and two updates per frame on displays running 120 FPS, etc. + * + * Therefore `Runner.run` will call multiple engine updates (or none) as needed to simulate the time elapsed between browser frames. + * + * In practice the number of updates in any particular frame may be restricted to respect the runner's performance budgets. These are specified by `runner.maxFrameTime` and `runner.maxUpdates`, see those properties for details. + * + * @default 1000 / 60 + */ + delta: number; + /** * A flag that specifies whether the runner is running or not. * @@ -2791,22 +2870,54 @@ declare namespace Matter { enabled: boolean; /** - * A `Boolean` that specifies if the runner should use a fixed timestep (otherwise it is variable). - * If timing is fixed, then the apparent simulation speed will change depending on the frame rate (but behaviour will be deterministic). - * If the timing is variable, then the apparent simulation speed will be constant (approximately, but at the cost of determininism). + * The measured time elapsed between the last two browser frames in milliseconds. + * This is useful e.g. to estimate the current browser FPS using `1000 / runner.frameDelta`. + */ + frameDelta: number; + + /** + * Enables averaging to smooth frame rate measurements and therefore stabilise play rate. * - * @default false + * @default true */ - isFixed: boolean; + frameDeltaSmoothing: boolean; /** - * A `Number` that specifies the time step between updates in milliseconds. - * If `engine.timing.isFixed` is set to `true`, then `delta` is fixed. - * If it is `false`, then `delta` can dynamically change to maintain the correct apparent simulation speed. + * Rounds measured browser frame delta to the nearest 1 Hz. + * This option can help smooth frame rate measurements and simplify handling hardware timing differences e.g. 59.94Hz and 60Hz displays. + * For best results you should also round your `runner.delta` equivalent to the nearest 1 Hz. * - * @default 1000 / 60 + * @default true */ - delta: number; + frameDeltaSnapping: boolean; + + /** + * A performance budget that limits execution time allowed for this runner per browser frame in milliseconds. + * + * To calculate the effective browser FPS at which this throttle is applied use `1000 / runner.maxFrameTime`. + * + * This performance budget is intended to help maintain browser interactivity and help improve framerate recovery during temporary high CPU usage. + * + * This budget only covers the measured time elapsed executing the functions called in the scope of the runner tick, including `Engine.update` and its related user event callbacks. + * + * You may also reduce this budget to allow for any significant additional processing you perform on the same thread outside the scope of this runner tick, e.g. rendering time. + * + * See also `runner.maxUpdates`. + * + * @default 1000 / 30 + */ + maxFrameTime: number; + + /** + * An optional limit for maximum engine update count allowed per frame tick in addition to `runner.maxFrameTime`. + * + * Unless you set a value it is automatically chosen based on `runner.delta` and `runner.maxFrameTime`. + * + * See also `runner.maxFrameTime`. + * + * @default null + */ + maxUpdates: number | null; } /** diff --git a/types/matter-js/matter-js-tests.ts b/types/matter-js/matter-js-tests.ts index aa028a700a0c246..a2ed97f5e4ff967 100644 --- a/types/matter-js/matter-js-tests.ts +++ b/types/matter-js/matter-js-tests.ts @@ -177,8 +177,12 @@ var render = Render.create({ // Runner const runner1 = Matter.Runner.create({ delta: 1000 / 60, - isFixed: false, enabled: true, + frameDelta: 1000 / 60, + frameDeltaSmoothing: true, + frameDeltaSnapping: true, + maxFrameTime: 1000 / 30, + maxUpdates: null, }); const runner2 = Matter.Runner.create({}); const runner3 = Matter.Runner.create();