Problem
Time.update (src/common/time/Time.ts) clamps deltaTimeInMilliseconds to a max of 1000/15 (~66.7ms) to prevent a large delta after a frame hitch/stall from causing instability — most concretely, physics bodies tunneling/flinging apart when a huge single-step integration is applied from a stale state (see the Newton's Cradle fix in commit c70a2bf).
This clamp lives on the shared Time class, so every consumer (physics, timers, particles, anything reading deltaTimeInMilliseconds/deltaTimeInSeconds) inherits it, not just physics. The side effect: during a real hitch, simulated time falls behind wall-clock time and everything runs in slow motion until it "catches up" tick by tick, rather than the sim catching up in the same frame.
Idiomatic fix
Adopt a fixed-timestep accumulator (see Glenn Fiedler's "Fix Your Timestep!") scoped to physics/simulation systems: accumulate real elapsed time and run integration/collision resolution in one or more fixed-size substeps per frame until the accumulator drains, clamping the accumulator itself (not the raw delta) to bound worst-case substeps per frame. This preserves physics stability without the global slow-motion side effect on unrelated systems (timers, particles, etc.), and gives real catch-up behavior after a hitch instead of stretched-out simulated time.
Scope
- Introduce a fixed-timestep loop (accumulator + substep count clamp) around physics integration/collision resolution, likely in the physics module's system(s) or a new stepping layer above them.
- Revisit whether
Time's oversized-delta clamp is still needed for other consumers once physics no longer depends on it, or whether it should stay as a coarser global safety net.
- Architectural — decouples physics tick rate from render tick rate; worth a design pass before implementation.
Problem
Time.update(src/common/time/Time.ts) clampsdeltaTimeInMillisecondsto a max of1000/15(~66.7ms) to prevent a large delta after a frame hitch/stall from causing instability — most concretely, physics bodies tunneling/flinging apart when a huge single-step integration is applied from a stale state (see the Newton's Cradle fix in commit c70a2bf).This clamp lives on the shared
Timeclass, so every consumer (physics, timers, particles, anything readingdeltaTimeInMilliseconds/deltaTimeInSeconds) inherits it, not just physics. The side effect: during a real hitch, simulated time falls behind wall-clock time and everything runs in slow motion until it "catches up" tick by tick, rather than the sim catching up in the same frame.Idiomatic fix
Adopt a fixed-timestep accumulator (see Glenn Fiedler's "Fix Your Timestep!") scoped to physics/simulation systems: accumulate real elapsed time and run integration/collision resolution in one or more fixed-size substeps per frame until the accumulator drains, clamping the accumulator itself (not the raw delta) to bound worst-case substeps per frame. This preserves physics stability without the global slow-motion side effect on unrelated systems (timers, particles, etc.), and gives real catch-up behavior after a hitch instead of stretched-out simulated time.
Scope
Time's oversized-delta clamp is still needed for other consumers once physics no longer depends on it, or whether it should stay as a coarser global safety net.