PixiJS Ticker delta time spikes during tab backgrounding
0 reputation · 19 Oct 2021, 21:07 UTC
0 reputation · 19 Oct 2021, 21:07 UTC
The PixiJS Ticker utilizes requestAnimationFrame to manage the update loop, calculating a delta value to ensure frame-rate independent movement. This mechanism relies on the browser's high-resolution timestamp to maintain synchronization between logic updates and rendering.
A specific challenge arises when the browser tab is backgrounded. Because the browser throttles or pauses requestAnimationFrame, the elapsed time between the last frame before suspension and the first frame upon refocusing can result in an exceptionally high delta value.
In physics-heavy simulations, these spikes can lead to "tunneling," where objects move so far in a single frame that they bypass collision boundaries entirely.
Ticker.delta to prevent physics instability after a tab refocus?35275 reputation · 20 Oct 2021, 03:20 UTC
Clamp the delta value to a maximum (e.g., 50 ms) or use the built‑in minFPS setting, and pause the ticker while the tab is hidden.
Ticker derives deltaMS from the timestamp difference between successive requestAnimationFrame callbacks.requestAnimationFrame to ~1 fps, so the elapsed time can jump to ~1000 ms, producing a delta spike.The spike occurs because the ticker continues to accumulate real‑world time while the render loop is paused; the first frame after refocus reports the whole pause as a single delta.
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
ticker.stop(); // halts the render loop
} else {
ticker.start(); // resumes normal RAF‑driven updates
}
});
// Set a minimum FPS (e.g., 30) → max delta ≈ 33 ms
ticker.minFPS = 30;
// Or manually clamp inside the tick listener
ticker.add((deltaMS) => {
const clamped = Math.min(deltaMS, 50); // 50 ms ≈ 20 fps cap
// use clamped for physics updates
});
Are you using the ticker’s default auto‑start loop (ticker.autoStart === true) or manually calling ticker.update() with your own timestamp? The stop()/start() approach only works when the ticker drives its own loop.
Use comments to ask for clarification. Post a solution as an answer.
35,275 reputation · 20 Oct 2021, 00:43 UTC
The Ticker.delta value is unit‑less (frames per target frame time), while the tick callback receives deltaMS in milliseconds. Setting ticker.minFPS internally clamps the incoming deltaMS to 1000 / minFPS before it is turned into delta, so the clamping happens at the millisecond level. If you prefer to stop the ticker entirely while the tab is hidden, remember that stop()/start() only affect the internal RAF‑driven loop when autoStart === true; with a manual loop you must skip calling ticker.update() instead.