How to Cap the Frame Rate in Matter.js

This guide explains how to effectively limit the frame rate of a Matter.js 2D physics simulation. By default, Matter.js attempts to match the screen's refresh rate through the browser's requestAnimationFrame API, which can cause inconsistent physics behavior across displays or consume excessive system resources. You will learn how to bypass the standard runner and implement a custom loop that locks physics updates to your desired frames per second (FPS).

Why the Default Runner Cannot Be Capped Directly

The built-in Matter.Runner.run() method automatically schedules updates using requestAnimationFrame. On a 60Hz screen, this executes 60 times per second, but on high-refresh-rate displays (such as 120Hz or 144Hz), it executes far more frequently. To reliably cap the frame rate, you must avoid Matter.Runner and invoke Matter.Engine.update() manually inside a controlled loop.

Implementing a Throttled Game Loop

The most reliable way to cap the frame rate is to track elapsed time between frames using performance.now() inside a custom requestAnimationFrame loop.

Here is the complete implementation:

const engine = Matter.Engine.create();
const render = Matter.Render.create({
  element: document.body,
  engine: engine
});

Matter.Render.run(render);

// Define your target frame rate
const targetFPS = 30;
const frameInterval = 1000 / targetFPS;

let lastTime = performance.now();

function animate(currentTime) {
  requestAnimationFrame(animate);

  const delta = currentTime - lastTime;

  // Only step the physics engine if enough time has passed
  if (delta >= frameInterval) {
    // Subtract leftover time to prevent timing drift
    lastTime = currentTime - (delta % frameInterval);

    // Advance the simulation by the fixed timestep
    Matter.Engine.update(engine, frameInterval);
  }
}

// Start the custom loop
requestAnimationFrame(animate);

Best Practices for Physics Stability