Build an Arcade Claw Machine with Matter.js
This guide explains how to construct a functional arcade claw machine simulation using the Matter.js 2D physics engine. You will learn how to configure the physics world, assemble a multi-part mechanical claw using rigid bodies and constraints, implement responsive closing mechanics, and calibrate physics parameters to allow the prongs to reliably grab and lift prize objects.
Initializing the World and Machine Boundaries
Start by setting up the standard Matter.js modules:
Engine, Render, Runner,
Bodies, Composite, and
Constraint. Define the physical play area by creating
static rectangular bodies for the floor and side walls, leaving the top
open or wide enough for the claw trolley to traverse.
const { Engine, Render, Runner, Bodies, Composite, Constraint, Body, Vector } = Matter;
const engine = Engine.create();
const world = engine.world;
const render = Render.create({
element: document.body,
engine: engine,
options: { width: 800, height: 600, wireframes: false }
});
Render.run(render);
Runner.run(Runner.create(), engine);
// Boundaries
const ground = Bodies.rectangle(400, 590, 800, 20, { isStatic: true });
const leftWall = Bodies.rectangle(10, 300, 20, 600, { isStatic: true });
const rightWall = Bodies.rectangle(790, 300, 20, 600, { isStatic: true });
Composite.add(world, [ground, leftWall, rightWall]);Populating the Prize Pit
Spawn a cluster of dynamic bodies at the bottom of the machine to serve as prizes. A mixture of circles and rounded rectangles with varying masses and high friction values provides an authentic arcade experience.
for (let i = 0; i < 25; i++) {
const x = 300 + Math.random() * 200;
const y = 500 + Math.random() * 50;
const prize = Bodies.circle(x, y, 20, {
friction: 0.8,
restitution: 0.2,
density: 0.002
});
Composite.add(world, prize);
}Building the Mechanical Claw Assembly
A functional claw requires a central carriage (base) and two or more articulated prongs. Each prong consists of an upper arm and an angled lower tip to hook beneath objects.
- Carriage Base: Create a kinematic or light dynamic body to act as the central hub.
- Prongs: Construct the left and right prongs.
Combine parts using
Body.create({ parts: [...] })to create curved or angled shapes, or use single angled rectangles. - Pivots: Connect each prong to the base using
revolute constraints (
Constraint.createwith zero length).
const clawBase = Bodies.rectangle(400, 100, 60, 20, { isStatic: true });
// Left Prong
const leftProng = Bodies.rectangle(370, 150, 12, 80, {
friction: 0.9,
angle: 0.2
});
// Right Prong
const rightProng = Bodies.rectangle(430, 150, 12, 80, {
friction: 0.9,
angle: -0.2
});
// Pivot Constraints
const leftPivot = Constraint.create({
bodyA: clawBase,
pointA: { x: -25, y: 10 },
bodyB: leftProng,
pointB: { x: 0, y: -35 },
stiffness: 1,
length: 0
});
const rightPivot = Constraint.create({
bodyA: clawBase,
pointA: { x: 25, y: 10 },
bodyB: rightProng,
pointB: { x: 0, y: -35 },
stiffness: 1,
length: 0
});
Composite.add(world, [clawBase, leftProng, rightProng, leftPivot, rightPivot]);Implementing the Closing and Opening Mechanism
To open and close the claw, use an elastic closing constraint connecting the bottom tips of the prongs, or apply rotational torque directly to the prongs.
An elastic spring constraint creates a natural gripping action that yields against solid prizes without destabilizing the physics simulation:
// Actuator constraint between the lower portions of the arms
const closingActuator = Constraint.create({
bodyA: leftProng,
pointA: { x: 0, y: 20 },
bodyB: rightProng,
pointB: { x: 0, y: 20 },
stiffness: 0.05,
length: 80, // Default open length
render: { visible: false }
});
Composite.add(world, closingActuator);
function closeClaw() {
// Shrink target distance to pull prongs inward
closingActuator.length = 15;
closingActuator.stiffness = 0.08;
}
function openClaw() {
// Expand target distance to push prongs outward
closingActuator.length = 80;
closingActuator.stiffness = 0.05;
}Alternatively, apply direct angular torque inside the game loop using
Body.setAngularVelocity or leftProng.torque
until the arms hit mechanical stops or grab a prize.
Controlling Machine States and Carriage Motion
Manage the claw through a state machine: IDLE, DROPPING, GRABBING, RETRACTING, and RELEASING.
Move the clawBase directly by altering its position
using Body.setPosition:
let clawState = 'IDLE';
function updateClawMovement() {
if (clawState === 'DROPPING') {
Body.setPosition(clawBase, { x: clawBase.position.x, y: clawBase.position.y + 3 });
if (clawBase.position.y >= 420) {
clawState = 'GRABBING';
closeClaw();
setTimeout(() => { clawState = 'RETRACTING'; }, 1000);
}
} else if (clawState === 'RETRACTING') {
Body.setPosition(clawBase, { x: clawBase.position.x, y: clawBase.position.y - 3 });
if (clawBase.position.y <= 100) {
clawState = 'IDLE';
// Optional: Move to chute and call openClaw()
}
}
}
Matter.Events.on(engine, 'beforeUpdate', updateClawMovement);Optimizing Friction and Grip Stability
Physics engines often suffer from slippery surfaces when lifting dynamic objects. To ensure successful grabs:
- Set the
frictionparameter of both the prize bodies and prong bodies to high values (between0.8and1.0). - Add custom hook tips to the prongs angled inward at 45 to 90 degrees using compound bodies to physically trap shapes rather than relying purely on frictional forces.
- Keep the solver iterations sufficiently high by setting
engine.positionIterations = 10andengine.velocityIterations = 10to prevent prongs from passing through prizes under tension.