Matter.js MouseConstraint Canvas Resize Issues
Resizing an HTML5 canvas while running a Matter.js simulation
disrupts the interaction coordinates of a MouseConstraint,
causing the physical drag points to detach from the visual cursor. This
article explains why this coordinate drift occurs, the specific
rendering and physics issues it causes, and how to properly recalibrate
the mouse inputs during window or container resize events.
The Coordinate Drift Problem
A MouseConstraint relies on an internal
Matter.Mouse instance that tracks DOM mouse and touch
events relative to the canvas element. When the canvas size changes, the
mapping between the browser's viewport pixels and the physics
simulation's internal coordinate space falls out of sync.
If you resize the canvas via CSS or update its HTML attributes
(width and height) without updating the
physics engine's properties, the simulation will continue using the
initial dimensions. As a result, the cursor must click significantly
off-target to grab an object, or interaction might cease entirely if the
cursor falls outside the initial boundary area.
What Happens Under Different Resize Methods
The specific failure depends on how the canvas is resized:
1. Resizing via CSS Only
If the canvas element's display size changes purely through CSS (such
as width: 100%), the underlying coordinate system stretches
or squashes. The physics world remains at its original pixel resolution.
The MouseConstraint receives DOM events based on the
stretched layout, causing an increasing offset between where the user
clicks and where the physics body reacts. The further the cursor moves
from the origin (top-left corner), the worse the offset becomes.
2. Updating Canvas Attributes Without Updating Matter.js
Directly changing canvas.width and
canvas.height clears the canvas drawing buffer and updates
its physical resolution. However, Matter.Render and
Matter.Mouse maintain their own internal records of
dimensions, pixel ratios, and view bounds. Failing to synchronize these
internal values causes the visual bodies to render at the new scale
while the MouseConstraint continues querying the physics
world using the old scale factors.
How to Fix Mouse Misalignment on Resize
To keep the MouseConstraint accurate during a resize,
you must update the canvas element, the renderer, and the mouse scale in
a coordinated sequence.
- Update the Render Dimensions: Set the new width and
height directly on the
render.optionsand the canvas DOM element. - Adjust Bounds: If using custom bounds or camera
views, update
render.bounds.max.xandrender.bounds.max.y. - Recalibrate the Mouse: Call
Matter.Mouse.setScaleandMatter.Mouse.setOffsetif viewports or CSS transformations are applied, or updatemouse.pixelRatioif the device pixel ratio changes.
A standard implementation inside a resize event listener involves updating both the renderer and the mouse tracking:
window.addEventListener('resize', () => {
const newWidth = window.innerWidth;
const newHeight = window.innerHeight;
// Update canvas element dimensions
render.canvas.width = newWidth;
render.canvas.height = newHeight;
// Update render options
render.options.width = newWidth;
render.options.height = newHeight;
// Update mouse bounds and scale
Matter.Mouse.setScale(mouseConstraint.mouse, { x: 1, y: 1 });
Matter.Mouse.setOffset(mouseConstraint.mouse, { x: 0, y: 0 });
});If CSS scaling is used instead of direct pixel matching, you must
calculate the ratio between the rendered CSS dimensions and the internal
canvas dimensions, then pass that ratio to
Matter.Mouse.setScale.