How to Export Matter.js Levels to JSON Maps
Exporting user-generated levels from a Matter.js canvas into a downloadable JSON file requires serializing physics objects into lightweight structural data, filtering out unnecessary runtime properties, and generating a browser download link. This guide walks through selecting the essential body attributes, formatting the level schema, and converting the resulting data into an exportable JSON file using standard web APIs.
1. Identify Essential Body Properties
Matter.js body objects contain circular references, runtime vectors,
and internal engine calculations that cannot be stringified directly
with JSON.stringify(). You must extract only the persistent
properties necessary to recreate the level layout:
- Position:
body.position.x,body.position.y - Rotation:
body.angle - Dimensions: Width and height for rectangles, or radius for circles.
- Physical State:
body.isStatic,body.density,body.restitution,body.friction - Custom Attributes: Identifying tags, sprite
textures, or gameplay labels (e.g.,
body.label).
2. Extract and Serialize Scene Data
Use Matter.Composite.allBodies(engine.world) to retrieve
every active object in your simulation. Map through these bodies to
construct a clean JavaScript object representing your level schema.
function extractLevelData(engine) {
const bodies = Matter.Composite.allBodies(engine.world);
const levelData = {
version: "1.0",
createdAt: new Date().toISOString(),
objects: bodies
.filter((body) => body.label !== "Mouse Constraint") // Exclude UI/system bodies
.map((body) => {
const isCircle = Boolean(body.circleRadius);
return {
id: body.id,
label: body.label,
isStatic: body.isStatic,
position: {
x: Math.round(body.position.x),
y: Math.round(body.position.y)
},
angle: Number(body.angle.toFixed(4)),
shape: isCircle ? "circle" : "rectangle",
dimensions: isCircle
? { radius: body.circleRadius }
: {
width: Math.round(body.bounds.max.x - body.bounds.min.x),
height: Math.round(body.bounds.max.y - body.bounds.min.y)
},
physics: {
restitution: body.restitution,
friction: body.friction
}
};
})
};
return levelData;
}3. Generate the Downloadable JSON File
Once the data is formatted, convert the object to a string with
indentation for human readability. Use the Blob API and
create a temporary object URL to trigger a native file download in the
user's browser.
function exportLevelToJSON(engine, filename = "custom-level.json") {
const data = extractLevelData(engine);
const jsonString = JSON.stringify(data, null, 2);
const blob = new Blob([jsonString], { type: "application/json" });
const downloadUrl = URL.createObjectURL(blob);
const anchor = document.createElement("a");
anchor.href = downloadUrl;
anchor.download = filename;
document.body.appendChild(anchor);
anchor.click();
// Cleanup temporary DOM element and object URL
document.body.removeChild(anchor);
URL.revokeObjectURL(downloadUrl);
}4. Integration
Attach the exportLevelToJSON function to an interface
element, such as an "Export Level" button:
const exportButton = document.getElementById("export-btn");
exportButton.addEventListener("click", () => {
exportLevelToJSON(engine, "user-level-1.json");
});This pipeline produces a compact, standard JSON map that separates level design data from physics engine internals, allowing users to save, share, and reload their custom maps into any Matter.js instance.