Build a Rube Goldberg Machine in Matter.js
This article explains how to design and build a multi-stage Rube Goldberg machine using the Matter.js 2D physics engine. You will learn how to configure the physics environment, build diverse mechanical components such as domino runs, pendulums, seesaws, and release latches, and chain them together sequentially. The guide also covers crucial physics-tuning techniques—including mass ratios, collision filtering, constraints, and solver iterations—to ensure each mechanical trigger activates reliably.
Setting Up the Environment
To start, initialize the Matter.js engine, world, renderer, and runner. A Rube Goldberg machine relies on consistent gravity and deterministic physical updates to ensure chain reactions behave identically on each run.
const { Engine, Render, Runner, Bodies, Composite, Constraint, Events } = Matter;
const engine = Engine.create({
positionIterations: 10,
velocityIterations: 10
});
const render = Render.create({
element: document.body,
engine: engine,
options: {
width: 1200,
height: 800,
wireframes: false
}
});
Render.run(render);
Runner.run(Runner.create(), engine);Increasing positionIterations and
velocityIterations prevents fast-moving objects from
clipping through tracks or thin walls (tunneling).
Constructing Distinct Mechanical Actions
A compelling Rube Goldberg machine chains fundamentally different types of physics interactions. Below are the key mechanisms to build.
1. The Domino Run
Dominoes convert small lateral impulses into sequential tipping motions.
function createDominoes(startX, startY, count, spacing) {
const dominoes = [];
for (let i = 0; i < count; i++) {
const domino = Bodies.rectangle(startX + i * spacing, startY, 10, 60, {
friction: 0.4,
restitution: 0.1,
density: 0.002
});
dominoes.push(domino);
}
Composite.add(engine.world, dominoes);
}Tip: Keep restitution (bounciness) low so
dominoes don't bounce backward, and keep friction moderate
so the base pivots rather than slips.
2. The Seesaw (First-Class Lever)
A seesaw transfers a downward impact on one side into an upward launch or trigger on the other.
const plank = Bodies.rectangle(400, 500, 200, 15, { density: 0.003 });
const fulcrum = Constraint.create({
pointA: { x: 400, y: 500 },
bodyB: plank,
pointB: { x: 0, y: 0 },
stiffness: 1,
length: 0
});
Composite.add(engine.world, [plank, fulcrum]);3. The Newton's Pendulum / Wrecking Ball
A pendulum gathers potential energy and releases kinetic energy upon collision to bridge large physical gaps.
const pendulumBob = Bodies.circle(600, 300, 25, { density: 0.05 });
const pendulumRope = Constraint.create({
pointA: { x: 550, y: 150 },
bodyB: pendulumBob,
stiffness: 0.9,
length: 150
});
Composite.add(engine.world, [pendulumBob, pendulumRope]);4. Triggered Trapdoors and Dynamic Releases
Not all chains rely solely on raw momentum transfer. You can use Matter.js collision events to act as electronic or mechanical tripwires that dissolve constraints or drop gates.
const trapdoor = Bodies.rectangle(800, 400, 120, 10, { isStatic: true });
const sensor = Bodies.rectangle(750, 380, 20, 20, {
isSensor: true,
isStatic: true
});
Composite.add(engine.world, [trapdoor, sensor]);
Events.on(engine, 'collisionStart', (event) => {
event.pairs.forEach((pair) => {
if (pair.bodyA === sensor || pair.bodyB === sensor) {
// Release the trapdoor
Matter.Body.setStatic(trapdoor, false);
}
});
});Chaining Diverse Actions Sequentially
To successfully pass energy from one module to the next, layout and momentum budgeting are critical:
- Stage 1 (Initial Release): A heavy ball drops onto an inclined plane and accelerates toward the domino chain.
- Stage 2 (Momentum Transfer): The ball strikes the first domino. The final domino falls off its platform onto the high side of the seesaw.
- Stage 3 (Leverage): The falling domino drives the seesaw down, catapulting a light payload upward into the pendulum bob.
- Stage 4 (Swing & Trip): The pendulum swings forward, contacting the sensor block.
- Stage 5 (Trapdoor Finale): The sensor event removes the static property of the trapdoor, allowing a heavy weight to drop onto the final objective button.
Fine-Tuning for Deterministic Execution
- Mass Balancing: If a falling object fails to push a
lever, increase its
densityrather than its scale to maintain layout proportions. - Friction Air: Set
frictionAir: 0or a very low value on rolling spheres to preserve rolling distance along long ramps. - Sleeping Bodies: For complex machines with dozens
of elements, enable
enableSleeping: trueon the engine so inactive downstream mechanisms do not drift or jitter before they are triggered. - Chamfering Edges: Use
chamfer: { radius: 2 }on sliding components or domino edges to prevent sharp visual corners from snagging on flat surfaces.