Cam and Follower Mechanism in Matter.js
This guide explains how to construct a functional cam and follower mechanism using the Matter.js 2D physics engine to convert continuous rotational motion into linear reciprocating motion. By combining rigid bodies, pivot constraints, vertical guides, and collision dynamics, you will learn how to model an eccentric cam, configure a spring-loaded follower rod, and maintain continuous mechanical contact during simulation.
Core Mechanical Components
A standard cam and follower system in a 2D physics environment requires three main components:
- The Cam: An asymmetrical or off-center rotating body mounted to a fixed pivot point.
- The Follower: A rigid body constrained to move along a single linear axis (typically vertical).
- The Preload Force: A spring constraint or gravity that ensures the follower stays in continuous physical contact with the cam's profile as it rotates.
Step-by-Step Implementation
1. Create the Cam Body and Pivot
The cam can be modeled using an ellipse, an egg-shaped polygon, or an eccentric circle. To create an eccentric circle, create a circular body and pin it at an off-center position using a fixed constraint.
const { Engine, Render, Runner, Bodies, Composite, Constraint, Body, Events } = Matter;
const engine = Engine.create();
const world = engine.world;
// Create an eccentric cam (circular body pinned off-center)
const camRadius = 60;
const camCenter = { x: 400, y: 300 };
const camOffset = 25; // Offset from geometric center to rotation axis
const cam = Bodies.circle(camCenter.x, camCenter.y, camRadius, {
collisionFilter: { group: -1 }, // Prevent unwanted collisions if needed
friction: 0,
restitution: 0
});
// Anchor constraint acting as the axle
const axle = Constraint.create({
pointA: { x: camCenter.x, y: camCenter.y + camOffset },
bodyB: cam,
pointB: { x: 0, y: camOffset },
stiffness: 1,
length: 0
});2. Drive the Cam Rotation
To maintain consistent rotational motion without fighting natural
friction, explicitly drive the cam's rotation using the
beforeUpdate engine event.
const rotationSpeed = 0.05; // Radians per frame
Events.on(engine, 'beforeUpdate', () => {
Body.setAngle(cam, cam.angle + rotationSpeed);
Body.setAngularVelocity(cam, rotationSpeed);
});3. Create the Follower
The follower consists of a rod positioned directly above the cam. To ensure purely vertical movement, frame the follower using static guide rails or use constraints to eliminate horizontal drift and rotation.
// Follower rod
const follower = Bodies.rectangle(camCenter.x, 150, 20, 180, {
inertia: Infinity, // Prevents the follower from rotating
friction: 0,
frictionAir: 0.01,
restitution: 0
});
// Guide rails to constrain linear vertical motion
const leftGuide = Bodies.rectangle(camCenter.x - 15, 150, 10, 200, {
isStatic: true,
friction: 0
});
const rightGuide = Bodies.rectangle(camCenter.x + 15, 150, 10, 200, {
isStatic: true,
friction: 0
});4. Ensure Surface Contact (Preload)
If gravity is not strong enough to return the follower quickly at higher rotation speeds, apply an elastic preload constraint (a spring) to pull the follower downward against the cam surface.
const spring = Constraint.create({
pointA: { x: camCenter.x, y: 300 },
bodyB: follower,
pointB: { x: 0, y: 80 },
stiffness: 0.05,
damping: 0.01,
length: 80
});5. Assembly and Execution
Add all defined bodies and constraints to the world composite and initialize the renderer and runner.
Composite.add(world, [cam, axle, follower, leftGuide, rightGuide, spring]);
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);Tuning Performance
- Friction Elimination: Set
friction: 0on both the cam and the follower contact surfaces to minimize binding and prevent horizontal forces from jamming the follower against its guides. - Collision Penetration: Increase engine sub-stepping
using
engine.positionIterations = 10;andengine.velocityIterations = 10;if high rotational speeds cause the cam profile to tunnel through the follower. - Guide Friction: Setting
inertia: Infinityon the follower eliminates rotational physics calculations on that body entirely, allowing the guide rails to function purely as translational limiters without catching on edges.