How to Create Conveyor Belts in Matter.js

Simulating conveyor belt mechanics in Matter.js requires applying a continuous tangential force or velocity modification to bodies in contact with the belt surface. Because Matter.js lacks a native "surface velocity" property like some other 2D physics engines, this behavior is achieved by detecting collisions between dynamic objects and the conveyor body using collision events, calculating the surface tangent vector, and applying directional force to the interacting bodies on each physics step.

Creating the Conveyor Body

Start by defining the conveyor belt as a static body within your Matter.js world. Set its friction high enough to prevent contacting objects from sliding freely without interacting with the belt surface.

const conveyorBelt = Matter.Bodies.rectangle(400, 500, 300, 20, {
    isStatic: true,
    friction: 0.8,
    angle: 0 // Can be angled to support inclined belts
});

Matter.Composite.add(engine.world, conveyorBelt);

Detecting Active Collisions

To exert a continuous tangential force, listen to the collisionActive event emitted by the Matter.Engine. This event fires on every tick for any bodies that are currently touching, allowing you to filter for collisions involving your conveyor belt.

Matter.Events.on(engine, 'collisionActive', (event) => {
    const pairs = event.pairs;

    for (let i = 0; i < pairs.length; i++) {
        const { bodyA, bodyB } = pairs[i];

        if (bodyA === conveyorBelt || bodyB === conveyorBelt) {
            const movingObject = bodyA === conveyorBelt ? bodyB : bodyA;

            if (!movingObject.isStatic) {
                applyConveyorForce(conveyorBelt, movingObject);
            }
        }
    }
});

Calculating and Applying Tangential Force

The tangential force must align with the orientation of the conveyor belt. Use the conveyor body's angle property to compute the unit tangent vector, scale it by your desired force magnitude, and apply it to the contacting body using Matter.Body.applyForce.

function applyConveyorForce(belt, targetBody) {
    const beltSpeed = 0.005; // Force magnitude scaled to object mass

    // Calculate the tangent vector parallel to the belt surface
    const tangentX = Math.cos(belt.angle);
    const tangentY = Math.sin(belt.angle);

    // Apply the tangential force directly at the center of mass
    Matter.Body.applyForce(targetBody, targetBody.position, {
        x: tangentX * beltSpeed * targetBody.mass,
        y: tangentY * beltSpeed * targetBody.mass
    });
}

Multiplying the force by targetBody.mass ensures that objects of differing masses accelerate along the conveyor belt at a consistent rate.

Alternative: Velocity Clamping for Consistent Belt Speed

If using Body.applyForce results in objects constantly accelerating beyond the intended belt speed, you can instead adjust the body's velocity directly or clamp it along the tangent axis:

function applyConveyorVelocity(belt, targetBody) {
    const targetSpeed = 3; // Desired belt speed in pixels/step
    const tangentX = Math.cos(belt.angle);
    const tangentY = Math.sin(belt.angle);

    // Project current velocity onto the tangent vector
    const currentTangentSpeed = (targetBody.velocity.x * tangentX) + (targetBody.velocity.y * tangentY);

    if (currentTangentSpeed < targetSpeed) {
        // Accelerate object toward target speed along the surface
        const speedDifference = targetSpeed - currentTangentSpeed;
        const forceMagnitude = Math.min(speedDifference * 0.01, 0.05);

        Matter.Body.applyForce(targetBody, targetBody.position, {
            x: tangentX * forceMagnitude * targetBody.mass,
            y: tangentY * forceMagnitude * targetBody.mass
        });
    }
}

This velocity-aware approach mimics real-world conveyor systems by accelerating bodies until they match the linear speed of the belt, preventing runaway acceleration while maintaining stable friction-based physics interactions.