Constant Angular Velocity in Matter.js

This article explains how to create a continuous motor effect in Matter.js to maintain a target angular velocity. Because the Matter.js physics engine lacks a built-in motorized constraint, developers must apply manual intervention. You will learn the two primary methods to achieve continuous rotation: directly enforcing angular velocity every simulation tick for an unstoppable motor, and calculating dynamic torque for realistic physical interactions.

Method 1: Directly Setting Angular Velocity

The most reliable way to maintain a strictly constant rotational speed is to override the body’s angular velocity on every frame using the engine's beforeUpdate event. This prevents air resistance (frictionAir) and collisions from slowing the body down.

const { Engine, Events, Body } = Matter;

const engine = Engine.create();
const targetAngularVelocity = 0.05; // Radians per tick

// Target body to act as a motor
const motorBody = Bodies.rectangle(400, 300, 200, 20, {
    frictionAir: 0 // Optional: minimize damping
});

// Update the body before every physics calculation
Events.on(engine, 'beforeUpdate', () => {
    Body.setAngularVelocity(motorBody, targetAngularVelocity);
});

Why This Works

Matter.js applies damping and constraint resolution during each tick. By setting the velocity inside beforeUpdate, you ensure that the body enters the collision and integration phases with the exact desired speed, acting as an infinitely strong motor.


Method 2: Applying Dynamic Proportional Torque

If you want a realistic motor that reacts to loads—slowing down when blocked and exerting torque to catch up—use a proportional control loop (a simple P-controller) to assign torque each frame.

const targetAngularVelocity = 0.05; // Desired speed (rad/tick)
const motorStrength = 0.1;          // Proportional gain (Kp)
const maxTorque = 0.05;             // Maximum torque limit

Events.on(engine, 'beforeUpdate', () => {
    // Calculate the difference between target and current speed
    const velocityError = targetAngularVelocity - motorBody.angularVelocity;

    // Calculate torque required to correct the error
    let appliedTorque = velocityError * motorStrength;

    // Clamp the torque to a realistic maximum limit
    appliedTorque = Math.max(-maxTorque, Math.min(maxTorque, appliedTorque));

    // Apply the torque directly to the body
    motorBody.torque = appliedTorque;
});

When to Use Torque Over Velocity


Important Configuration Settings

To ensure predictable rotational behavior, adjust the following properties on your rotating body:

  1. frictionAir: Defaults to 0.01. Set this to 0 if you want zero environmental resistance, or keep it low to simulate friction within the motor's axle.
  2. inertia: If you use Method 2 (Torque), increasing the body's mass or inertia requires a correspondingly higher motorStrength to achieve the target speed within a reasonable timeframe.
  3. Pivots with Constraints: If the body needs to stay in place while spinning, anchor its center using a Constraint:
const constraint = Matter.Constraint.create({
    pointA: { x: 400, y: 300 },
    bodyB: motorBody,
    pointB: { x: 0, y: 0 },
    stiffness: 1,
    length: 0
});
Matter.World.add(engine.world, [motorBody, constraint]);