Using PixiJS Ticker for Frame‑Rate Independent Updates
Learn how PixiJS’ shared Ticker supplies a delta time for frame‑rate independent updates, with a code example, limits, and common pitfalls.
26 May 2026, 12:39 UTC

Using PixiJS Ticker for Frame‑Rate Independent Updates
PixiJS exposes a shared Ticker object that runs on requestAnimationFrame. Each tick supplies a delta value – the elapsed time in seconds since the previous frame – so you can move objects at a constant speed regardless of the actual FPS.
Worked example
// 1. Create the PixiJS application
const app = new PIXI.Application({ width: 800, height: 600, backgroundColor: 0x1099bb });
document.body.appendChild(app.view);
// 2. Add a simple sprite (replace with your own texture)
const sprite = PIXI.Sprite.from('https://pixijs.download/examples/assets/bunny.png');
sprite.x = app.screen.width / 2;
sprite.y = app.screen.height / 2;
sprite.anchor.set(0.5);
app.stage.addChild(sprite);
// 3. Register an update listener that uses the supplied delta
const MAX_DELTA = 0.1; // clamp to 100 ms to avoid huge jumps after a tab freeze
app.ticker.add((delta) => {
// delta is seconds; clamp it
const step = Math.min(delta, MAX_DELTA);
// move 150 pixels per second
sprite.x += 150 * step;
// wrap around the screen
if (sprite.x > app.screen.width + sprite.width) {
sprite.x = -sprite.width;
}
});
// 4. Clean up when the application is destroyed (optional but recommended)
function destroy() {
app.ticker.remove((delta) => {
const step = Math.min(delta, MAX_DELTA);
sprite.x += 150 * step;
if (sprite.x > app.screen.width + sprite.width) {
sprite.x = -sprite.width;
}
});
app.destroy(true);
}
// Call destroy() when you no longer need the stage, e.g., on page unload.
The listener receives delta directly from the ticker, so the sprite advances 150 × delta pixels each frame. Whether the browser renders at 60 fps or 30 fps, the distance covered per second stays the same.
How the ticker works
- PixiJS creates a single
Tickerinstance shared by allApplicationobjects. - The ticker schedules a callback via
requestAnimationFrame. - Before invoking user‑added listeners, it measures the time elapsed since the last call and passes that value (in seconds) as the
deltaargument. - If the page is hidden or the browser throttles
requestAnimationFrame, the ticker pauses, and no callbacks fire until the tab regains focus.
Limits and practical considerations
- Pause on visibility change: When the user switches tabs or minimizes the window, the ticker stops. Game logic that depends on the ticker will also pause, which is usually desirable for rendering but may break simulations that expect continuous time.
- Large delta spikes: After a long pause (e.g., a 2‑second freeze caused by a heavy script), the first delta can be several seconds. Without clamping, objects may “tunnel” through barriers or jump unrealistically far. A common safeguard is to clamp delta to a maximum step (e.g., 0.1 s) as shown in the example.
- Not a fixed‑step timer: The ticker provides variable step sizes. For physics or networking that requires deterministic updates, run a separate fixed‑step loop and use the ticker only for rendering.
- Garbage‑collection pressure: Capturing large objects inside the ticker closure creates a new reference each frame, which can increase GC work. Keep closures lightweight or bind methods to the object directly.
Common mistakes to avoid
- Using
Date.now()orperformance.now()instead of the supplieddelta. This duplicates the timing work and can drift if the ticker is paused. - Performing expensive synchronous work (e.g., large loops, JSON parsing) inside the ticker callback. Such work can drop frames and cause the observed FPS to fall below the monitor’s refresh rate.
- Neglecting to remove listeners when a sprite, container, or the whole application is destroyed. Orphaned callbacks keep references alive, leading to memory leaks.
- Assuming the ticker runs at a constant 60 fps. Always rely on the
deltavalue for time‑based calculations.
How to verify the behavior
- Open the example in a browser, open DevTools → Performance, and record a short run while throttling the CPU to 30 fps. Observe that the sprite moves smoothly and covers the same distance per second as when running at 60 fps.
- Hide the tab or minimize the window. The sprite should stop moving; when you return, it resumes from the same position without a sudden jump.
- Simulate a freeze by adding
setTimeout(() => {}, 2000)inside a long‑running script. Notice the delta value spike in the console; after applying the clamp (Math.min(delta, 0.1)) the sprite’s position change stays bounded.
By using the ticker’s delta and applying a sensible maximum step, you get frame‑rate independent motion that works reliably across typical browsing conditions while staying aware of the ticker’s inherent limitations.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.