How to Prevent Constraint Stretching in Matter.js

This article explains how to prevent constraints from stretching beyond their designated length in Matter.js physics simulations. By default, constraints behave like springs that can visually stretch under high loads, gravity, or fast-moving collisions. You will learn how to make constraints rigid using constraint properties, how to configure engine iteration settings for stability, and how to programmatically enforce a maximum distance cap for rope-like mechanics.

Maximize Constraint Stiffness

By default, a Matter.js constraint has a default stiffness value that creates a spring-like elasticity. To eliminate this springiness and make the link as rigid as possible, set the stiffness property explicitly to 1.

const rigidConstraint = Matter.Constraint.create({
    bodyA: bodyA,
    bodyB: bodyB,
    length: 100,
    stiffness: 1
});

Setting stiffness: 1 instructs the solver to eliminate the displacement completely in a single step, though heavy loads can still cause stretching if the solver does not run enough iterations.

Increase Engine Constraint Iterations

Even with stiffness: 1, heavy masses, high velocity, or multiple chained constraints can cause visual stretching. This occurs because the physics engine solves constraints iteratively. The default iteration count is often too low to resolve high forces completely.

To eliminate unwanted stretching under heavy loads, increase constraintIterations on the engine instance:

const engine = Matter.Engine.create({
    constraintIterations: 10 // Default is 2
});

Setting constraintIterations between 6 and 12 significantly reduces or entirely eliminates stretching under stress at the expense of a minor performance cost.

Enforce Inextensible Rope Constraints Dynamically

If your goal is to allow objects to move freely closer together while preventing them from extending beyond a fixed maximum distance (like a non-elastic rope or chain), you must dynamically limit the constraint length. Matter.js constraints natively resist both compression and extension.

To prevent stretching while allowing slack, attach a listener to the engine's beforeUpdate event to dynamically adjust the constraint's length:

const maxDistance = 150;

const ropeConstraint = Matter.Constraint.create({
    bodyA: bodyA,
    bodyB: bodyB,
    length: maxDistance,
    stiffness: 1
});

Matter.Events.on(engine, 'beforeUpdate', () => {
    const currentDistance = Matter.Vector.magnitude(
        Matter.Vector.sub(bodyA.position, bodyB.position)
    );

    // If bodies are closer than the limit, remove tension
    if (currentDistance < maxDistance) {
        ropeConstraint.length = currentDistance;
    } else {
        ropeConstraint.length = maxDistance;
    }
});

Clamp Body Velocities or Positions Manually

For extreme forces—such as sudden teleports, explosions, or infinite mass interactions—constraint solvers can occasionally fail to hold within a single frame. In these edge cases, you can clamp the distance manually right after the physics update:

Matter.Events.on(engine, 'afterUpdate', () => {
    const delta = Matter.Vector.sub(bodyB.position, bodyA.position);
    const distance = Matter.Vector.magnitude(delta);

    if (distance > maxDistance) {
        const direction = Matter.Vector.normalise(delta);
        const correctedPosition = Matter.Vector.add(
            bodyA.position,
            Matter.Vector.mult(direction, maxDistance)
        );
        Matter.Body.setPosition(bodyB, correctedPosition);
    }
});

Combining stiffness: 1 with higher constraintIterations solves standard stretching issues, while dynamic updates handle one-way rope limits and extreme forces effectively.