Matter.js Runner Tick Event Explained
In Matter.js, the Matter.Runner coordinates the physics
simulation loop with the browser's render cycles using
requestAnimationFrame. This article explains what the
tick event is on Matter.Runner, where it fits
within the execution lifecycle, how it differs from
Matter.Engine update events, and how to implement it to
manage frame-by-frame simulation logic.
What Is Matter.Runner?
Matter.Runner is an optional utility provided by
Matter.js that runs an animation loop. Instead of manually invoking
Engine.update(engine, delta) inside a native
requestAnimationFrame callback, the runner automatically
handles variable frame rates, fixed time steps, and execution
synchronization.
The tick Event
The tick event is triggered on the runner instance on
every iteration of the runner's game loop. It indicates that a frame
update cycle is currently taking place.
During an execution loop, Matter.Runner fires three
primary lifecycle events in this order:
beforeTick: Fires immediately at the start of a frame before any timing calculations or physics updates occur.tick: Fires during the frame processing step, right as the runner coordinates the timing and updates theMatter.Engine.afterTick: Fires at the end of the frame once all physics updates and event handling for that frame are complete.
Event Object Properties
When listening to the tick event, the event callback
receives an event object containing execution details:
timestamp: The high-resolution timestamp (typically fromperformance.now()) representing the current time of the tick.source: A reference to theMatter.Runnerinstance that dispatched the event.name: The string'tick'.
Runner
tick vs. Engine beforeUpdate /
afterUpdate
It is common to confuse runner events with engine events.
Runnerevents (tick) are tied directly to the browser's render loop and the execution of the runner instance.Engineevents (beforeUpdate,afterUpdate) are tied to the physical simulation step.
If the runner is configured to use a fixed time step or needs to
catch up due to frame drops, it may trigger multiple engine updates
inside a single runner tick, or it may skip an engine
update entirely. Using the runner's tick event is ideal
when synchronizing systems to the display refresh rate, whereas engine
events are better suited for logic that must strictly map to physics
state changes.
How to Use the tick
Event
To listen to the tick event, use the
Matter.Events.on method:
const { Engine, Runner, Events } = Matter;
// Create engine and runner
const engine = Engine.create();
const runner = Runner.create();
// Attach listener to the runner's tick event
Events.on(runner, 'tick', (event) => {
// Current frame timestamp
const currentTime = event.timestamp;
// Custom frame-based logic (e.g., input polling, custom rendering, stats tracking)
console.log(`Runner tick executed at: ${currentTime}`);
});
// Start the simulation loop
Runner.run(runner, engine);Common Use Cases
- Performance and FPS Monitoring: Tracking the interval between ticks to detect frame rate drops.
- Input Polling: Checking keyboard or gamepad states immediately before the physics engine processes interactions.
- Custom Rendering: Triggering custom WebGL or Canvas rendering loops that need to remain strictly locked to the runner cycle.