Render Matter.js with Hardware-Accelerated SVG
This guide explains how to decouple Matter.js from its default HTML5 Canvas renderer to drive Scalable Vector Graphics (SVG) directly inside the DOM. By mapping physics bodies to SVG nodes and manipulating them via CSS 3D transforms rather than redrawing geometry or updating coordinate attributes, you enable the browser’s compositor to handle rendering on the GPU for smooth, hardware-accelerated performance.
The Rendering Principle
By default, Matter.js uses an HTML5 Canvas via
Matter.Render. To use SVG, you run the Matter.js physics
engine in a headless state and handle the DOM updates manually.
Modifying SVG geometric attributes like cx,
cy, x, or y on every frame causes
the browser to recalculate layouts and re-rasterize vector paths on the
CPU. To achieve hardware acceleration:
- Render SVG elements once at origin
(0, 0). - Set their visual center as the transform origin using CSS.
- Update positions and rotations via CSS
transform: translate3d(...) rotate(...)on each engine tick. This offloads translation and rotation directly to the GPU compositor.
1. Set Up the SVG Canvas and CSS
Create an SVG container in your HTML and configure the CSS to promote SVG elements to their own GPU compositing layers:
<svg id="scene" width="800" height="600" viewBox="0 0 800 600"></svg>.physics-node {
will-change: transform;
transform-box: fill-box;
transform-origin: center center;
position: absolute;
}will-change: transformhints to the browser to assign a dedicated compositor layer.transform-box: fill-boxandtransform-origin: center centerensure rotations occur around the element's local center rather than the top-left of the entire SVG canvas.
2. Initialize the Headless Matter.js Engine
Create the Matter.js engine and runner without initializing
Matter.Render:
const { Engine, Runner, Bodies, Composite } = Matter;
const engine = Engine.create();
const world = engine.world;
const runner = Runner.create();
Runner.run(runner, engine);3. Generate Physics Bodies and Corresponding SVG Elements
When creating a body, create a corresponding SVG element. Center the
element's base geometry at (0, 0) so that translational
transforms position it accurately.
const svgContainer = document.getElementById('scene');
const bodiesMap = new Map();
function createSvgRect(body, width, height) {
const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("width", width);
rect.setAttribute("height", height);
// Center the geometry around (0, 0)
rect.setAttribute("x", -width / 2);
rect.setAttribute("y", -height / 2);
rect.setAttribute("class", "physics-node");
rect.setAttribute("fill", "#3498db");
svgContainer.appendChild(rect);
bodiesMap.set(body, rect);
return rect;
}
// Example: Create a falling rectangle
const box = Bodies.rectangle(400, 100, 60, 60);
Composite.add(world, box);
createSvgRect(box, 60, 60);
// Example: Create a static floor
const floor = Bodies.rectangle(400, 580, 800, 40, { isStatic: true });
Composite.add(world, floor);
createSvgRect(floor, 800, 40);4. Sync the Physics State with the DOM
Hook into Matter.js's afterUpdate event to synchronize
the coordinates of each body with its SVG element using CSS
transform:
Matter.Events.on(engine, 'afterUpdate', () => {
bodiesMap.forEach((element, body) => {
const { x, y } = body.position;
const angle = body.angle;
// Use translate3d to force hardware acceleration
element.style.transform = `translate3d(${x}px, ${y}px, 0) rotate(${angle}rad)`;
});
});Complex Geometries and Polygons
For complex shapes generated with
Bodies.fromVertices:
- Generate an SVG
<path>or<polygon>element. - Normalize the SVG points around the calculated center of mass
(
body.position). - Apply the exact same
translate3dandrotateCSS properties on the resulting element during theafterUpdateloop.