Matter.js Constraint Tension on Skipped Updates

In Matter.js, constraints define physical relationships such as springs, ropes, and rigid joints between bodies by applying corrective impulses during each simulation step. When an Engine.update call is skipped, the iterative constraint-solving phase does not execute, causing active constraint tensions to freeze at their last calculated values. The physical consequences of this interruption depend entirely on whether the simulation resumes with a standard fixed time step or an accumulated, elongated delta time, which can trigger severe solver instability or violent corrective snapping.

Immediate State of Constraint Tension

Matter.js resolves constraints discretely within the Constraint.solveAll and Engine.update cycles using an iterative relaxation algorithm. It does not compute or store continuous tension forces over continuous time; instead, it corrects positional errors (the difference between the current distance of the bodies and the constraint's resting length) and modifies velocities frame by frame.

When an engine update is skipped:

Behavior on the Subsequent Update

The behavior of active constraint tension when updates resume is dictated by how the time delta (\(\Delta t\)) is handled on the next invocation of Engine.update(engine, delta):

Fixed Timestep (Engine Paused or Regulated)

If an update was skipped due to a paused state or an explicit fixed-step accumulator, and the engine resumes with a standard step (such as 16.67ms for 60 FPS), the constraint solver resumes normally. The tension recalculates from the current positions using the regular damping and stiffness parameters, producing a smooth continuation with no erratic behavior.

Variable Timestep or Elapsed Delta (Delta Spike)

If the game loop tracks real-world wall-clock time and passes a large elapsed \(\Delta t\) into the next Engine.update to compensate for the skipped frame, the physics engine can become unstable:

Preventing Constraint Breakdown

To maintain stable constraint tension when frames or engine updates might be dropped:

  1. Clamp the Delta Parameter: Never pass an uncapped real-world elapsed time directly to Engine.update. Enforce an upper boundary (for example, Math.min(delta, 1000 / 30)) to prevent sudden distance spikes across constraints.
  2. Use a Fixed Timestep Accumulator: Use Matter.Runner or a custom sub-stepping loop that consumes accumulated time in fixed slices (such as 16.66ms per step), updating constraints multiple times in sequence rather than once with a bloated delta.
  3. Warm-Starting and Iteration Tuning: If constraints regularly carry high tension, increase engine.constraintIterations (e.g., from 2 to 4 or 8) to allow the solver more relaxation passes per step to settle residual tension smoothly.