Custom Canvas Graphics Using Matter.js afterRender
Matter.js provides a built-in 2D canvas renderer that displays rigid
bodies, constraints, and collisions automatically, but complex games and
simulations often require custom visuals like trails, health bars, or
textured overlays. By listening to the afterRender event on
the Render module, you can access the underlying HTML5
Canvas 2D context immediately after Matter.js finishes drawing the
physics scene. This allows you to draw your own shapes, text, or sprites
directly on top of the physics bodies without interfering with the
simulation.
Accessing the Canvas Context
To draw custom elements, attach an event listener to your
Render instance using Matter.Events.on().
Within the callback, retrieve the 2D rendering context from
render.context.
const { Engine, Render, Runner, Bodies, Composite, Events } = Matter;
// Create engine and renderer
const engine = Engine.create();
const render = Render.create({
element: document.body,
engine: engine,
options: {
width: 800,
height: 600,
wireframes: false
}
});
Render.run(render);
Runner.run(Runner.create(), engine);
// Listen to the afterRender event
Events.on(render, 'afterRender', () => {
const ctx = render.context;
// Custom drawing routines go here
});Drawing Relative to Physics Bodies
When rendering elements that follow physical bodies—such as
nameplates, health bars, or rotating indicators—reference the body's
position and angle properties. Always use
context.save() and context.restore() to
prevent style and coordinate transformations from leaking into
subsequent frames.
const circle = Bodies.circle(400, 300, 30, { restitution: 0.8 });
Composite.add(engine.world, circle);
Events.on(render, 'afterRender', () => {
const ctx = render.context;
ctx.save();
// Translate and rotate to match the body's transform
ctx.translate(circle.position.x, circle.position.y);
ctx.rotate(circle.angle);
// Draw a custom visual element centered on the body
ctx.fillStyle = '#ff4757';
ctx.fillRect(-15, -15, 30, 30);
ctx.restore();
// Draw an overlay above the body (without rotation)
ctx.save();
ctx.fillStyle = '#ffffff';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.fillText('Player 1', circle.position.x, circle.position.y - 45);
ctx.restore();
});Handling Renderer Bounds and Zoom
If you enable camera panning or zooming by modifying
render.bounds, canvas coordinates will not map 1:1 to
physics space. In this scenario, transform the canvas context by the
camera offset before drawing, or compute screen-space coordinates by
subtracting render.bounds.min.x and
render.bounds.min.y from the target positions.