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:
- The Escape Wheel: A toothed gear driven by a constant clockwise or counterclockwise torque (simulating a hanging weight or coiled spring).
- The Pendulum and Anchor Assembly: A pendulum connected rigidly to an anchor with two pallets (entry and exit). As the pendulum swings, the pallets alternately lock and release the teeth of the escape wheel. During each release, the tooth slides along the impulse face of the pallet, pushing it and transferring enough kinetic energy to the pendulum to overcome friction.
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.
- Compound Geometry: Generate an array of angled
teeth using
Matter.Bodies.rectangleorMatter.Bodies.fromVertices, positioned radially around a central hub. - Combine into a Single Body: Use
Matter.Body.create({ parts: [...] })to bind the hub and teeth into one rigid body. - Pin the Wheel: Fasten the wheel to the canvas with
a zero-length
Matter.Constraintwith 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.
- Pendulum Structure: Build a long rod and a dense
bob using
Matter.Bodies.rectangleandMatter.Bodies.circle. - 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.
- Unified Body: Combine the anchor, rod, and bob into
a single body using
Matter.Body.create(). - 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
- Restitution (Bounciness): Set
restitution: 0.0or 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. - Friction: Keep static and kinetic friction low
(
0.01to0.05) between the pallets and the teeth to prevent the escape wheel from binding. - 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; - 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.