Limit Maximum Angular Velocity in Matter.js

This article explains how to restrict the maximum angular velocity of a rigid body in Matter.js to prevent objects from spinning uncontrollably. Matter.js does not feature a built-in property to hard-cap rotational speed automatically, but you can achieve this by listening to the physics engine's update cycle and clamping the velocity value manually. Below is the direct method to implement this using the beforeUpdate engine event.

Clamping Angular Velocity with beforeUpdate

The standard approach to capping rotational speed is to evaluate the body's angularVelocity on every tick before the physics calculations are resolved. If the absolute value of the angular velocity exceeds your designated limit, you clamp it back to the maximum allowed threshold using Matter.Body.setAngularVelocity.

Here is the complete implementation:

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

// Create an engine and a world
const engine = Engine.create();
const world = engine.world;

// Create a body
const box = Bodies.rectangle(400, 200, 80, 80);
Composite.add(world, box);

// Define your maximum angular velocity (in radians per step)
const MAX_ANGULAR_VELOCITY = 0.1;

// Intercept the engine before each physics update
Events.on(engine, 'beforeUpdate', () => {
    const currentAngularVelocity = box.angularVelocity;

    if (Math.abs(currentAngularVelocity) > MAX_ANGULAR_VELOCITY) {
        // Preserve the direction of rotation while capping the magnitude
        const clampedVelocity = Math.sign(currentAngularVelocity) * MAX_ANGULAR_VELOCITY;
        Body.setAngularVelocity(box, clampedVelocity);
    }
});

Applying the Limit to All Bodies in a Scene

If your simulation requires all dynamic bodies to adhere to an angular speed limit, you can iterate over all composite bodies within the same event listener:

Events.on(engine, 'beforeUpdate', () => {
    const bodies = Composite.allBodies(engine.world);
    const MAX_ANGULAR_VELOCITY = 0.15;

    for (let i = 0; i < bodies.length; i++) {
        const body = bodies[i];

        // Skip static bodies
        if (body.isStatic) continue;

        if (Math.abs(body.angularVelocity) > MAX_ANGULAR_VELOCITY) {
            Body.setAngularVelocity(
                body,
                Math.sign(body.angularVelocity) * MAX_ANGULAR_VELOCITY
            );
        }
    }
});

Alternative: Adjusting frictionAir

If a hard clamp causes unnatural visual snapping in your simulation, an alternative is to increase the frictionAir property on the body. While frictionAir does not establish a strict maximum limit, it introduces rotational drag that naturally prevents bodies from sustaining extreme rotational speeds:

const box = Bodies.rectangle(400, 200, 80, 80, {
    frictionAir: 0.05 // Default is 0.01
});

For strict physics boundaries, combining the beforeUpdate clamping logic with appropriate air friction provides both stability and realistic movement.