Clock Pendulum Escapement Simulation in Matter.js

This guide explains how to model and simulate a functional clock escapement mechanism driven by a swinging pendulum using Matter.js. You will learn how to construct the escape wheel, assemble the rigid pendulum-anchor body, apply continuous driving torque, and tune collision parameters to maintain sustained periodic oscillation without jamming.


1. Conceptual Architecture

A mechanical clock escapement consists of two primary interacting components:

In Matter.js, achieving this requires rigid-body compounding, pin constraints, collision filtering, and continuous torque application.


2. Creating the Escape Wheel

The escape wheel needs distinct, asymmetrical teeth that can push against the anchor pallets.

  1. Compound Geometry: Generate an array of angled teeth using Matter.Bodies.rectangle or Matter.Bodies.fromVertices, positioned radially around a central hub.
  2. Combine into a Single Body: Use Matter.Body.create({ parts: [...] }) to bind the hub and teeth into one rigid body.
  3. Pin the Wheel: Fasten the wheel to the canvas with a zero-length Matter.Constraint with high stiffness (stiffness: 1) to act as a central axle.
const wheelRadius = 100;
const teethCount = 12;
const teethParts = [Matter.Bodies.circle(centerX, centerY, wheelRadius * 0.8)];

for (let i = 0; i < teethCount; i++) {
    const angle = (i / teethCount) * Math.PI * 2;
    const x = centerX + Math.cos(angle) * wheelRadius;
    const y = centerY + Math.sin(angle) * wheelRadius;
    
    const tooth = Matter.Bodies.rectangle(x, y, 10, 25, {
        angle: angle + 0.4 // slant the teeth to create an impulse face
    });
    teethParts.push(tooth);
}

const escapeWheel = Matter.Body.create({
    parts: teethParts,
    friction: 0.05,
    restitution: 0.0
});

const wheelAxle = Matter.Constraint.create({
    pointA: { x: centerX, centerY },
    bodyB: escapeWheel,
    pointB: { x: 0, y: 0 },
    stiffness: 1,
    length: 0
});

3. Assembling the Pendulum and Anchor

The anchor and pendulum must move as a unified rigid unit around a single pivot located directly above the escape wheel.

  1. Pendulum Structure: Build a long rod and a dense bob using Matter.Bodies.rectangle and Matter.Bodies.circle.
  2. Anchor Pallets: Attach two curved or angled arms extending across the top of the escape wheel. The geometry must ensure that when the left pallet clears a tooth, the right pallet catches another.
  3. Unified Body: Combine the anchor, rod, and bob into a single body using Matter.Body.create().
  4. Pivot Point: Anchor the assembly slightly above the escape wheel with a revolute constraint.
const pivotX = centerX;
const pivotY = centerY - 120;

// Pallet arms spanning the wheel
const leftPallet = Matter.Bodies.rectangle(pivotX - 50, pivotY + 40, 12, 35, { angle: -0.6 });
const rightPallet = Matter.Bodies.rectangle(pivotX + 50, pivotY + 40, 12, 35, { angle: 0.6 });
const pendulumRod = Matter.Bodies.rectangle(pivotX, pivotY + 150, 6, 300);
const pendulumBob = Matter.Bodies.circle(pivotX, pivotY + 300, 30, { density: 0.05 });

const pendulumAssembly = Matter.Body.create({
    parts: [leftPallet, rightPallet, pendulumRod, pendulumBob],
    friction: 0.05,
    restitution: 0.0
});

const pendulumPivot = Matter.Constraint.create({
    pointA: { x: pivotX, y: pivotY },
    bodyB: pendulumAssembly,
    pointB: { x: 0, y: -150 }, // relative offset to pivot position
    stiffness: 1,
    length: 0
});

4. Driving the Mechanism

A standard physics simulation quickly loses momentum due to numerical damping and friction. To keep the clock running, you must simulate the clockwork drive force.

Use the beforeUpdate engine event to apply continuous torque to the escape wheel:

Matter.Events.on(engine, 'beforeUpdate', () => {
    // Apply constant rotational drive to the escape wheel
    escapeWheel.torque = 0.15; 
});

When the wheel's tooth slides across the pallet, this torque delivers a mechanical impulse directly to the pendulum.


5. Critical Tuning Parameters

  1. Restitution (Bounciness): Set restitution: 0.0 or near-zero on both the wheel teeth and the anchor pallets. High restitution causes the anchor to bounce erratically off the teeth, causing phase errors or jams.
  2. Friction: Keep static and kinetic friction low (0.01 to 0.05) between the pallets and the teeth to prevent the escape wheel from binding.
  3. Engine Iterations: In complex high-speed contacts, vertices can tunnel through thin geometry. Increase simulation fidelity to prevent the teeth from passing through the pallets:
    engine.positionIterations = 12;
    engine.velocityIterations = 10;
  4. Pendulum Periodicity: The swing period (\(T\)) relies primarily on the distance between the pivot and the center of mass of the pendulum assembly, governed by the pendulum equation \(T \approx 2\pi\sqrt{L/g}\). Adjust the length of the pendulum rod and the bob's mass to control the beat rate of your clock.