Matter.js Detect Mouse Movement Without Dragging

This article explains how to capture continuous mouse movement across a Matter.js canvas without requiring a click or drag action. By default, Matter.js tracks pointer coordinates internally, but developers often mistake the MouseConstraint module as strictly a drag-and-drop tool. By accessing the underlying Mouse instance and listening to Matter.js events, you can passively detect the cursor's exact coordinates across the simulation space at any time.


Step 1: Initialize the Mouse and MouseConstraint

To capture mouse data in Matter.js, you must create a Mouse instance linked to your renderer's canvas and attach it to a MouseConstraint.

const { Engine, Render, Runner, Bodies, Composite, Mouse, MouseConstraint, Events } = Matter;

const engine = Engine.create();
const render = Render.create({
    element: document.body,
    engine: engine,
    options: {
        width: 800,
        height: 600,
        wireframes: false
    }
});

// Create mouse controller linked to the canvas
const mouse = Mouse.create(render.canvas);
const mouseConstraint = MouseConstraint.create(engine, {
    mouse: mouse,
    constraint: {
        stiffness: 0.2,
        render: { visible: false }
    }
});

Composite.add(engine.world, mouseConstraint);
render.mouse = mouse;

Step 2: Listen for the mousemove Event

The MouseConstraint emits a mousemove event whenever the cursor moves over the canvas element, regardless of whether a mouse button is pressed.

Events.on(mouseConstraint, 'mousemove', function(event) {
    const mousePosition = event.mouse.position;
    console.log(`Mouse X: ${mousePosition.x}, Mouse Y: ${mousePosition.y}`);
});

The coordinates in event.mouse.position automatically account for canvas scaling and pixel ratios handled by Matter.js.


Step 3: Track Movement Passively Without Body Interaction

If you want to track mouse movement but prevent the mouse from grabbing or dragging any physical bodies in the world, disable the collision filter on the MouseConstraint:

const passiveMouseConstraint = MouseConstraint.create(engine, {
    mouse: mouse,
    collisionFilter: {
        mask: 0x0000 // Disables interaction with all collision categories
    }
});

Composite.add(engine.world, passiveMouseConstraint);

Events.on(passiveMouseConstraint, 'mousemove', function(event) {
    const { x, y } = event.mouse.position;
    // Perform actions based on coordinates without dragging bodies
});

Alternative: Polling Coordinates Inside the Update Loop

If an event-driven approach is not required, you can directly query mouse.position inside Matter.js's beforeUpdate or afterUpdate engine lifecycle events:

Events.on(engine, 'afterUpdate', function() {
    const currentX = mouse.position.x;
    const currentY = mouse.position.y;

    // Use current coordinates in real-time updates
});

This method reads the latest cursor position on every tick of the physics engine without relying on separate input event listeners.