Create a Slider Prismatic Joint in Matter.js
This guide explains how to implement a slider (prismatic) joint in Matter.js. Because Matter.js lacks a native prismatic joint class like Box2D, creating a slider mechanism requires constraining an object's movement along a single linear axis while eliminating unwanted degrees of freedom. You will learn the standard approach combining locked rotation with an engine update constraint to create a smooth, functional linear slider.
The Challenge with Native Constraints
Matter.js provides Matter.Constraint, which acts as a
distance-based spring or pin joint (revolute joint). It does not
natively support 1-degree-of-freedom prismatic joints that allow free
translation along an axis while restricting rotation and perpendicular
translation.
To create an effective slider, you must:
- Prevent the sliding body from rotating.
- Clamp the body's movement to a single axis (horizontal, vertical, or angled).
- Optionally define travel boundaries (minimum and maximum displacement).
Method: Axis-Locked Simulation Using Engine Events
The most stable and common way to achieve a prismatic joint in Matter.js is by disabling rotation on the sliding body and fixing its secondary coordinate during the simulation's update cycle.
1. Create the Bodies
Set the inertia of the slider body to
Infinity to prevent it from rotating upon collision or
applied forces.
const { Engine, Render, Runner, Bodies, Composite, Events } = Matter;
const engine = Engine.create();
const world = engine.world;
// Fixed track or base
const trackY = 300;
const minX = 150;
const maxX = 650;
// Slider body (constrained to move along X)
const slider = Bodies.rectangle(400, trackY, 60, 40, {
inertia: Infinity, // Disables rotation
friction: 0.05,
frictionAir: 0.01,
restitution: 0.2
});
Composite.add(world, slider);2. Lock the Axis and Set Travel Limits
Attach a callback to the beforeUpdate event. This hook
continuously locks the slider to the specified linear track
(trackY) and clamps the linear travel distance between
minX and maxX.
Events.on(engine, 'beforeUpdate', () => {
// Lock the vertical position and vertical velocity
Matter.Body.setPosition(slider, {
x: slider.position.x,
y: trackY
});
Matter.Body.setVelocity(slider, {
x: slider.velocity.x,
y: 0
});
// Clamp within the horizontal bounds
if (slider.position.x < minX) {
Matter.Body.setPosition(slider, { x: minX, y: trackY });
Matter.Body.setVelocity(slider, { x: Math.max(0, slider.velocity.x), y: 0 });
} else if (slider.position.x > maxX) {
Matter.Body.setPosition(slider, { x: maxX, y: trackY });
Matter.Body.setVelocity(slider, { x: Math.min(0, slider.velocity.x), y: 0 });
}
});Alternative: Physical Guide Rails
If you prefer a purely rigid-body collision approach without manual coordinate overrides, you can place two static rectangular bodies above and below the slider to form a physical groove.
- Create a top and bottom boundary with
isStatic: true. - Set
friction: 0on both the static rails and the slider body to prevent binding. - Set
inertia: Infinityon the slider body to prevent rotation inside the channel.
While simpler to visualize, this approach is slightly more
computationally expensive and can occasionally cause jitter at high
velocities compared to the programmatic beforeUpdate
lock.