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:
- Independent Runners: Create a separate
Runnerfor each engine usingMatter.Runner.run(Matter.Runner.create(), engine). This is the simplest approach and keeps the lifecycle of each simulation fully decoupled. - Unified Game Loop: Use a single
requestAnimationFrameloop or a singleRunnerinstance 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:
- Reduce the iteration counts for constraints and position solvers
(
engine.positionIterationsandengine.velocityIterations) if high precision is not required. - Pause or stop engines that scroll out of the viewport using the Intersection Observer API.
- Limit the total number of active rigid bodies across all simultaneous worlds.