How to Import Saved Matter.js State
Restoring a physics simulation to a previous state in Matter.js
requires saving the key properties of your bodies to a serializable
format like JSON and reconstructing them inside the physics world.
Because Matter.js instances contain internal functions and circular
references, native serialization methods like
JSON.stringify(engine) fail. This article demonstrates how
to structure, parse, and import serialized body states back into a
Matter.js engine.
Why Manual State Deserialization is Required
The Matter.Engine and Matter.Composite
objects maintain complex references, cache structures, and event
listeners that cannot be serialized directly. To restore a simulation,
you must reconstruct the bodies from a snapshot containing essential
geometric and physical values: position, angle, velocity, angular
velocity, and custom dimensions or collision options.
Structure of a Saved State
A reliable saved state consists of a clean array of plain objects containing only the required simulation parameters:
[
{
"type": "rectangle",
"x": 400,
"y": 200,
"width": 80,
"height": 80,
"angle": 0.45,
"velocity": { "x": 1.2, "y": -0.5 },
"angularVelocity": 0.02,
"isStatic": false
}
]Implementing the Import Function
To import and apply this data, first clear the existing simulation
bodies using Composite.clear(). Then, iterate through the
saved data to recreate the bodies with Matter.Bodies, apply
their physical states, and add them back to the world.
import Matter from 'matter-js';
const { Composite, Bodies, Body } = Matter;
function importSavedState(engine, savedData) {
// Clear existing bodies and constraints from the world
Composite.clear(engine.world, false);
const newBodies = savedData.map((data) => {
let body;
// Reconstruct the geometry based on type
if (data.type === 'rectangle') {
body = Bodies.rectangle(data.x, data.y, data.width, data.height, {
isStatic: data.isStatic
});
} else if (data.type === 'circle') {
body = Bodies.circle(data.x, data.y, data.radius, {
isStatic: data.isStatic
});
}
// Apply rotation and dynamic physics properties
if (body) {
Body.setAngle(body, data.angle || 0);
Body.setVelocity(body, data.velocity || { x: 0, y: 0 });
Body.setAngularVelocity(body, data.angularVelocity || 0);
}
return body;
}).filter(Boolean);
// Add the reconstructed bodies to the physics engine
Composite.add(engine.world, newBodies);
}Restoring Constraints and Joints
If your state includes constraints (such as pins, springs, or ropes),
save unique identifiers (id) for each body during the
export step. During the import process:
- Map each recreated body to its original
id. - Iterate through a saved
constraintsarray. - Use
Matter.Constraint.create()withbodyAandbodyBassigned via the mapped identifiers. - Add the resulting constraints to
engine.worldusingComposite.add().
Handling Collision Groups and Masks
To ensure physical behaviors remain identical after importing,
include collisionFilter data (group,
category, and mask) in your export payload.
When reconstructing the bodies, pass these options into the body
creation parameters so that collision rules remain intact.