Differential Torque in Matter.js Car Simulation

Simulating realistic vehicle dynamics in Matter.js requires distributing rotational drive force unevenly between wheels based on turning angles, traction, and wheel speeds. This article explains how to model differential torque across drive wheels—such as an open or limited-slip differential (LSD)—in a 2D Matter.js environment by monitoring wheel angular velocities and dynamically distributing torque values on every physics engine update tick.


Understanding Differential Types in 2D Physics

In a vehicle, the differential allows the driven wheels to rotate at different speeds while supplying power. In a 2D physics engine like Matter.js, vehicles are typically modeled either in a side-profile view (front and rear axles) or a top-down view (left and right wheels).


Step-by-Step Implementation

1. Setup the Drive Wheels

Define your driven wheels as standard circular rigid bodies and attach them to the chassis using revolute constraints or stiff distance constraints.

const wheelA = Matter.Bodies.circle(x1, y1, radius, { friction: 0.8 });
const wheelB = Matter.Bodies.circle(x2, y2, radius, { friction: 0.8 });

2. Listen to the Engine's Pre-Update Loop

All torque computations must occur inside the beforeUpdate event listener to ensure forces are applied immediately before the solver executes collision resolution and position integration.

Matter.Events.on(engine, 'beforeUpdate', () => {
    applyDifferentialTorque(wheelA, wheelB, throttleInput);
});

3. Calculate Angular Velocities

Query the current rotational speed (angularVelocity) of both wheels directly from their Matter.js body properties:

const omegaA = wheelA.angularVelocity;
const omegaB = wheelB.angularVelocity;
const deltaOmega = omegaA - omegaB;

4. Compute Torque Allocation

Open Differential Model

For an open differential, base torque is split evenly. If speed matching is desired to prevent runaway free-spinning, dampening can be applied to the faster wheel:

function applyOpenDifferential(wheelA, wheelB, throttle) {
    const totalTorque = throttle * MAX_TORQUE;
    const halfTorque = totalTorque / 2;

    wheelA.torque += halfTorque;
    wheelB.torque += halfTorque;
}
Limited-Slip Differential (LSD) Model

An LSD redistributes torque from the slipping wheel back to the traction-bearing wheel using a stiffness coefficient (\(K_{lsd}\)):

function applyLimitedSlipDifferential(wheelA, wheelB, throttle) {
    const totalTorque = throttle * MAX_TORQUE;
    const baseTorque = totalTorque * 0.5;
    
    // Determine differential speed
    const deltaOmega = wheelA.angularVelocity - wheelB.angularVelocity;
    
    // Transfer torque proportional to the difference in rotational speed
    const kLsd = 0.05; // LSD bias factor
    const transferTorque = Math.max(-baseTorque, Math.min(baseTorque, deltaOmega * kLsd));

    // Wheel A loses torque if spinning faster; Wheel B gains it
    const torqueA = baseTorque - transferTorque;
    const torqueB = baseTorque + transferTorque;

    wheelA.torque += torqueA;
    wheelB.torque += torqueB;
}

Top-Down Vehicle Considerations

For top-down vehicles, rotational torque alone applied to the wheels will not propel the vehicle forward. In this case, torque translates to linear forward force applied at the wheel’s contact patch.

Compute the forward vector of each wheel and apply force using Matter.Body.applyForce:

function applyTopDownDriveForce(wheel, torqueValue) {
    const angle = wheel.angle;
    const forceMagnitude = torqueValue / wheel.circleRadius;

    const forceVector = {
        x: Math.cos(angle) * forceMagnitude,
        y: Math.sin(angle) * forceMagnitude
    };

    Matter.Body.applyForce(wheel, wheel.position, forceVector);
}

By substituting raw body torque with vector forces distributed according to the LSD or open differential logic, top-down vehicles will accurately display understeer, oversteer, and power-sliding characteristics depending on traction states.