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:

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.