How to Build a Telescopic Piston in Matter.js

This guide explains how to construct a rigid, linear telescopic piston joint in Matter.js by combining dual parallel constraints with custom length actuation. Because Matter.js lacks a native prismatic or slider joint, creating a stable linear actuator requires preventing rotational flex and tuning solver iterations. Below is a direct, step-by-step breakdown of how to configure the rigid bodies, constrain their motion to a single axis, and programmatically drive expansion and contraction.

1. The Core Architecture

A single Matter.js constraint functions like a distance joint, allowing connected bodies to rotate freely around their anchor points. To create a rigid telescopic joint that moves exclusively along one axis without bending, you must:

  1. Connect two bodies using two parallel constraints spaced across the width of the piston.
  2. Set the constraint stiffness to maximum (1.0).
  3. Increment or decrement the target length of both constraints simultaneously to simulate pneumatic or hydraulic stroke.
  4. Increase engine solver iterations to eliminate sponginess.

2. Setting Up the Bodies

Create a stationary base (or parent body) and the extending rod. Set collision filters so the piston rod does not snag on the base body if they overlap.

const { Engine, Render, Runner, Bodies, Composite, Constraint, Events } = Matter;

// Piston base (cylinder housing)
const base = Bodies.rectangle(400, 300, 60, 100, {
  isStatic: true,
  collisionFilter: { group: -1 }
});

// Extending rod
const rod = Bodies.rectangle(400, 200, 40, 100, {
  collisionFilter: { group: -1 }
});

3. Creating Dual Parallel Constraints

To prevent lateral wobble and rotation, place two identical constraints parallel to the axis of movement, offset along the X-axis.

const spacing = 15; // Offset from center
const initialLength = 100;

const constraintLeft = Constraint.create({
  bodyA: base,
  pointA: { x: -spacing, y: 0 },
  bodyB: rod,
  pointB: { x: -spacing, y: 0 },
  stiffness: 1.0,
  damping: 0.1,
  length: initialLength
});

const constraintRight = Constraint.create({
  bodyA: base,
  pointA: { x: spacing, y: 0 },
  bodyB: rod,
  pointB: { x: spacing, y: 0 },
  stiffness: 1.0,
  damping: 0.1,
  length: initialLength
});

Composite.add(world, [base, rod, constraintLeft, constraintRight]);

4. Actuating Linear Expansion and Contraction

To extend and retract the piston, adjust the length property of both constraints synchronously inside the beforeUpdate event loop.

let targetLength = initialLength;
let extending = true;
const minLength = 60;
const maxLength = 220;
const speed = 2;

Events.on(engine, 'beforeUpdate', () => {
  if (extending) {
    targetLength += speed;
    if (targetLength >= maxLength) extending = false;
  } else {
    targetLength -= speed;
    if (targetLength <= minLength) extending = true;
  }

  constraintLeft.length = targetLength;
  constraintRight.length = targetLength;
});

5. Tuning for Absolute Stiffness

By default, Matter.js allows slight constraint stretching under heavy loads. To make the piston completely rigid: