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.

  1. Update the Render Dimensions: Set the new width and height directly on the render.options and the canvas DOM element.
  2. Adjust Bounds: If using custom bounds or camera views, update render.bounds.max.x and render.bounds.max.y.
  3. Recalibrate the Mouse: Call Matter.Mouse.setScale and Matter.Mouse.setOffset if viewports or CSS transformations are applied, or update mouse.pixelRatio if 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.