How to Build a Matter.js Seesaw with Ground Stoppers
This guide explains how to construct a functional seesaw (teeter-totter) physics simulation using Matter.js. You will learn how to create the balance plank, bind it to a fixed central pivot point using constraints, and place static ground stoppers to restrict the plank's maximum rotation angle for realistic behavior.
1. Setting Up the Matter.js Environment
Before creating the seesaw, initialize the core Matter.js modules: the engine, renderer, runner, and world composite.
const { Engine, Render, Runner, Bodies, Composite, Constraint, Mouse, MouseConstraint } = 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);
const runner = Runner.create();
Runner.run(runner, engine);2. Creating the Seesaw Plank
The plank is a dynamic rectangular body. Its dimensions define the length and thickness of the teeter-totter.
const plankX = 400;
const plankY = 350;
const plankWidth = 400;
const plankHeight = 20;
const plank = Bodies.rectangle(plankX, plankY, plankWidth, plankHeight, {
density: 0.002,
friction: 0.5,
render: {
fillStyle: '#3498db'
}
});3. Adding the Central Pivot Constraint
To make the plank pivot around its center, attach it to a fixed point
in the world using a revolute constraint. Setting length: 0
ensures the plank rotates around the anchor without sliding.
const pivot = Constraint.create({
pointA: { x: plankX, y: plankY },
bodyB: plank,
pointB: { x: 0, y: 0 },
stiffness: 1,
length: 0,
render: {
visible: true,
lineWidth: 3,
strokeStyle: '#2c3e50'
}
});4. Positioning the Ground and Stoppers
Without stoppers, the plank will rotate 360 degrees when pushed. Place two static rectangular bodies underneath the ends of the plank to act as ground stops.
// Base floor
const ground = Bodies.rectangle(400, 580, 810, 40, {
isStatic: true,
render: { fillStyle: '#7f8c8d' }
});
// Left and right stoppers
const stopperY = 400;
const stopperWidth = 30;
const stopperHeight = 80;
const leftStopper = Bodies.rectangle(plankX - 160, stopperY, stopperWidth, stopperHeight, {
isStatic: true,
render: { fillStyle: '#e74c3c' }
});
const rightStopper = Bodies.rectangle(plankX + 160, stopperY, stopperWidth, stopperHeight, {
isStatic: true,
render: { fillStyle: '#e74c3c' }
});Adjusting the stopperY or the height of the stoppers
directly controls the tilt limit of the seesaw.
5. Adding Interactivity and Objects
To interact with the seesaw, add dynamic test objects and enable mouse controls.
// Falling test weights
const weight1 = Bodies.circle(300, 100, 25, { density: 0.004, render: { fillStyle: '#f1c40f' } });
const weight2 = Bodies.rectangle(500, 100, 40, 40, { density: 0.002, render: { fillStyle: '#2ecc71' } });
// Mouse control
const mouse = Mouse.create(render.canvas);
const mouseConstraint = MouseConstraint.create(engine, {
mouse: mouse,
constraint: {
stiffness: 0.2,
render: { visible: false }
}
});
// Add all bodies to the world
Composite.add(world, [
plank,
pivot,
ground,
leftStopper,
rightStopper,
weight1,
weight2,
mouseConstraint
]);
render.mouse = mouse;When you run this script, the weights land on opposite ends of the plank, tilting the structure until it makes physical contact with the static stoppers.