Running Multiple Matter.js Engines on One Page

Yes, you can run multiple Matter.js engines simultaneously on a single web page without conflicts. Because Matter.js uses an instance-based architecture rather than a global singleton, each physics simulation operates independently with its own world, bodies, constraints, and update loops. This allows developers to display side-by-side simulations, independent UI widgets, or isolated physics sandboxes on the same screen.

How Independent Instances Work

In Matter.js, the core modules—such as Engine, Render, Runner, and World—are instantiated as distinct objects. When you create an engine using Engine.create(), it generates a self-contained simulation state. Because no shared internal state exists between separate calls to Engine.create(), bodies added to one engine will never interact with or affect bodies in another.

Basic Implementation Setup

To run two simulations simultaneously, instantiate separate sets of components for each:

// Setup Engine 1
const engineA = Matter.Engine.create();
const renderA = Matter.Render.create({
  element: document.getElementById('canvas-container-a'),
  engine: engineA,
  options: { width: 400, height: 400, wireframes: false }
});

// Setup Engine 2
const engineB = Matter.Engine.create();
const renderB = Matter.Render.create({
  element: document.getElementById('canvas-container-b'),
  engine: engineB,
  options: { width: 400, height: 400, wireframes: false }
});

// Add bodies to their respective worlds
Matter.Composite.add(engineA.world, [
  Matter.Bodies.rectangle(200, 200, 50, 50)
]);

Matter.Composite.add(engineB.world, [
  Matter.Bodies.circle(200, 200, 25)
]);

// Start renderers
Matter.Render.run(renderA);
Matter.Render.run(renderB);

Running and Updating the Simulations

You can manage the update cycles for multiple engines in two ways:

  1. Independent Runners: Create a separate Runner for each engine using Matter.Runner.run(Matter.Runner.create(), engine). This is the simplest approach and keeps the lifecycle of each simulation fully decoupled.
  2. Unified Game Loop: Use a single requestAnimationFrame loop or a single Runner instance to update all engines sequentially. This guarantees that all physics worlds step forward synchronously at the exact same delta time:
const runner = Matter.Runner.create();

function tick() {
  Matter.Engine.update(engineA, 1000 / 60);
  Matter.Engine.update(engineB, 1000 / 60);
  requestAnimationFrame(tick);
}
tick();

Handling User Input

If your simulations require mouse or touch interaction, you must create a separate Mouse and MouseConstraint for each instance. Ensure that each Mouse.create() call targets the specific canvas element associated with that engine's renderer:

const mouseA = Matter.Mouse.create(renderA.canvas);
const mouseConstraintA = Matter.MouseConstraint.create(engineA, {
  mouse: mouseA
});
Matter.Composite.add(engineA.world, mouseConstraintA);

Failing to isolate the mouse element will cause clicks on one canvas to trigger unintended interactions in the other simulation.

Performance Considerations

Physics calculations are CPU-intensive. Running multiple instances doubles or triples the computational load on the main JavaScript thread. To maintain 60 FPS: