Build a Matter.js Ferris Wheel with Hanging Cars
This article demonstrates how to construct an interactive, physics-driven Ferris wheel using the Matter.js 2D physics engine. By combining a central revolving wheel, revolute constraints, and top-mounted pivot points on passenger cabins, you will learn how to assemble a continuously rotating structure where the cars naturally stabilize and remain upright due to gravity.
Core Mechanics of the Ferris Wheel
To create a realistic Ferris wheel, the simulation requires three primary components:
- A central wheel or rotor: A body pinned to a fixed coordinate in the world so it can rotate around its center.
- Passenger cars (cabins): Individual bodies attached to the outer rim of the wheel.
- Revolute constraints: Pivot connections that allow free rotation between the cabins and the wheel rim. Placing the pivot connection near the top edge of each cabin ensures that gravity naturally pulls the cabin's center of mass downward, keeping it upright as the wheel turns.
Step 1: Setting Up the Wheel and Axle
First, initialize your standard Matter.js modules
(Engine, Render, Runner,
Bodies, Composite, Constraint,
Body).
Create a circular body or multi-spoke frame for the main wheel and secure it to a static coordinate in the world using a rigid constraint.
const wheelRadius = 180;
const centerX = 400;
const centerY = 300;
// Central wheel body (non-colliding)
const wheel = Bodies.circle(centerX, centerY, wheelRadius, {
collisionFilter: { group: -1 }
});
// Fixed axle constraint
const axle = Constraint.create({
pointA: { x: centerX, y: centerY },
bodyB: wheel,
pointB: { x: 0, y: 0 },
stiffness: 1,
length: 0
});Setting a negative collisionFilter.group prevents parts
of the wheel assembly from colliding with one another.
Step 2: Creating and Attaching the Passenger Cars
Calculate the positions of the cabins around the perimeter using basic trigonometry. For each cabin:
- Create a rectangular body representing the cabin.
- Connect the cabin to the wheel rim using a
Constraint. - Set the constraint's connection point on the cabin
(
pointB) near its top edge (a negative Y offset relative to the cabin's center). This creates a pendulum effect, allowing gravity to stabilize the cabin without requiring manual angle corrections.
const cabinCount = 8;
const cabins = [];
const cabinConstraints = [];
for (let i = 0; i < cabinCount; i++) {
const angle = (i / cabinCount) * Math.PI * 2;
const rimX = centerX + wheelRadius * Math.cos(angle);
const rimY = centerY + wheelRadius * Math.sin(angle);
const cabinWidth = 40;
const cabinHeight = 50;
// Create the cabin body
const cabin = Bodies.rectangle(rimX, rimY + 15, cabinWidth, cabinHeight, {
collisionFilter: { group: -1 },
frictionAir: 0.05, // Dampens swinging motion
density: 0.002
});
// Pin the top of the cabin to the rim of the wheel
const cabinPin = Constraint.create({
bodyA: wheel,
pointA: {
x: wheelRadius * Math.cos(angle),
y: wheelRadius * Math.sin(angle)
},
bodyB: cabin,
pointB: { x: 0, y: -cabinHeight / 2 },
stiffness: 1,
length: 0
});
cabins.push(cabin);
cabinConstraints.push(cabinPin);
}Step 3: Motorizing the Wheel
To rotate the wheel, enforce a steady angular velocity on the central
wheel body within the engine's update loop. Listening to the
beforeUpdate event provides smooth, constant motion.
Matter.Events.on(engine, 'beforeUpdate', () => {
Matter.Body.setAngularVelocity(wheel, 0.008);
});Step 4: Adding Everything to the World
Finally, add the wheel, axle, cabins, and constraints to the Matter.js composite:
Composite.add(engine.world, [
wheel,
axle,
...cabins,
...cabinConstraints
]);By adjusting the frictionAir property of the cabins, you
can control how much they sway as the wheel turns. The top-mounted
constraint guarantees that gravity keeps the passenger cabins oriented
right-side up throughout the entire rotation cycle.