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.