Command Palette

Search for a command to run...

Hectal
Course outline
Topic 16.2Advanced ~20 min · step 2 of 6

The Fixed Timestep

In one line

Physics must step by the same amount of time every time, whatever the frame rate. An accumulator collects real time and runs as many fixed steps as fit. Steps are jumps, so fast objects can skip past thin ones; engines add tricks against that, and you still test it.

0/6 · 0%

Think of it like this

A train timetable. Trains leave every 10 minutes exactly, however long the queue at the ticket office was. If you are late, you wait for the next one; if you are very late, two trains may have left. Physics steps are the trains; frames are the queue.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

fixed timestep
Advancing physics by the same small time every step (here 1/60 s), whatever the frame rate.
accumulator
A running total of real time not yet simulated; each full step's worth is spent on one step.
interpolation alpha
The leftover time divided by the step: how far between two physics states to draw.
tunnelling
A fast object passing through a thin one because no step catches them overlapping.
CCD
Continuous collision detection: checking the path between steps, not only where a body lands.

Step by step

01Count steps per screen

Run the first example and read the three screen lines. Same one second of real time; 59 or 60 steps; up to 15 in one frame after a stall.

Count steps per screendiagram
Rendering diagram…

02Watch a hand-made step fail

The last three lines move a ball with plain arithmetic and check for overlap after each move. At 1 m/s and at 40 m/s no step lands inside the 2 cm floor.

03Ask the engine

The second example drops a 1 cm bolt onto a 2 cm shelf at 40, 200 and 1,000 m/s, with CCD off and on. It stops every time: speculative contacts catch it a step ahead.

04Decide what to protect

List your fast, small things (a thrown part, a projectile). Turn CCD on for those, then test them at their real top speed against your thinnest colliders.

Try it yourself

  1. 1

    Remove the cap

    In the first example, change Math.min(frame, 0.25) to frame. The stall line now runs 60 steps with up to 30 in one frame: on a slow phone, that one frame takes 30 times longer to compute, which makes the next frame late too.

  2. 2

    A smaller step

    In the first example, set STEP to 1 / 240. All three hand-made drops now stop (measured): a step at 40 m/s is still 0.17 m, much more than the 4 cm in which the overlap test can catch the ball, so it is luck that one lands inside. Smaller steps make it likelier, not certain; the stall line now needs up to 59 steps in one frame.

Code & diagrams

The accumulator on three screens, and a hand-made step New tab

Simulated frame times, so the counts are exact. The floating-point detail on the 144 Hz line is real JavaScript arithmetic.

Console

(nothing was printed)

Expected console output

144 Hz monitor               144 frames -> 59 physics steps (up to 1 in one frame), 16.7 ms left over, alpha 1.00
30 fps phone                  30 frames -> 60 physics steps (up to 2 in one frame), 0.0 ms left over, alpha 0.00
60 fps with one 0.5 s stall   31 frames -> 45 physics steps (up to 15 in one frame), 0.0 ms left over, alpha 0.00
hand-made step,  1 m/s: fell through, y = -5.0
hand-made step,  5 m/s: stopped at y = 0.017
hand-made step, 40 m/s: fell through, y = -44.0
A fast bolt and a thin shelf, in Rapier New tab

Rapier 0.21.0 with its default settings. Against a fixed shelf, its speculative contacts stop the bolt at every speed tried.

Console

(nothing was printed)

Expected console output

  40 m/s, CCD off: after 1 s y =   0.02 -> stopped on the shelf
  40 m/s, CCD on : after 1 s y =   0.02 -> stopped on the shelf
 200 m/s, CCD off: after 1 s y =   0.02 -> stopped on the shelf
 200 m/s, CCD on : after 1 s y =   0.02 -> stopped on the shelf
1000 m/s, CCD off: after 1 s y =   0.02 -> stopped on the shelf
1000 m/s, CCD on : after 1 s y =   0.02 -> stopped on the shelf

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Step by the frame's own time

In a render loop, call world.timestep = delta; world.step(); with each frame's delta instead of fixed steps.

terminal
$ Drop the same ball (restitution 0.9) from 0.9 m, once per step size, and run 1.5 s of simulated time
── what you'll see ──
144 Hz (1/144 s) steps 216 | first bounce peak 0.710 m | y at 1.5 s 0.553
60 Hz (1/60 s) steps 90 | first bounce peak 0.734 m | y at 1.5 s 0.552
30 fps (1/30 s) steps 45 | first bounce peak 0.726 m | y at 1.5 s 0.499
Measured in Rapier 0.21.0 with `world.timestep` set to each value. Three screens, three slightly different worlds. A stack or a fast object shows much bigger differences, and on a stalled frame delta can be half a second.

Myth vs fact

Myth

Turning on CCD makes tunnelling impossible.

Fact

CCD helps a lot for fast bodies against static geometry, but has limits: measured here, a small bolt at 200 m/s still passed a thin moving plate with CCD on. Test your real cases at their real speeds.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Physics in a Web Worker keeps a heavy simulation off the main thread; you send inputs in and poses out each step (Topic 17.6). Rapier's WebAssembly runs in workers too.

  • ▸

    Pausing a background tab stops requestAnimationFrame, so the accumulator would get a huge delta on return: the 0.25 s cap (or three.js's Timer with connect(document), Phase 3) keeps the return smooth.

Remember this

  1. 1

    The problem this solves: if physics stepped by each frame's own time, a 144 Hz monitor and a 30 fps phone would run different simulations: jumps would reach different heights and stacks would behave differently. Larger steps are also less stable. A fixed step makes the simulation the same everywhere.

  2. 2

    The accumulator. Each frame, add the frame's time to an accumulator; while it holds at least one step (1/60 s), run a step and subtract it. The first example runs one simulated second on three screens: the 30 fps phone runs 60 steps, two per frame; the 144 Hz monitor runs 59 with 16.7 ms left over, because 144 additions of 1/144 add up to a hair less than one second in floating point, and the next frame takes the 60th step. A 0.5 s stall (a background tab, a slow load) is capped at 0.25 s, so one frame runs 15 steps instead of 30: otherwise a slow device falls further behind every frame (the "spiral of death").

  3. 3

    Interpolation. What is left in the accumulator, divided by the step, is alpha (0 to 1): how far the real time is between the last step and the next. Drawing each mesh at lerp(previous, current, alpha) removes the small stutter you see when a 144 Hz screen shows the same physics state for two or three frames. The build skips it to stay short; games with fast motion use it.

  4. 4

    Tunnelling. A step is a jump. Hand-written physics that moves an object and then checks for overlap misses a thin floor whenever a step jumps over it: the first example's own physics lets a ball through at 1 m/s and at 40 m/s, and stops it at 5 m/s only because one step happened to land inside the floor. Engines do better: measured here, Rapier stopped a 1 cm bolt dropped at 1,000 m/s onto a 2 cm fixed shelf, with or without CCD, because it predicts contacts one step ahead (speculative contacts).

  5. 5

    CCD, and testing. Continuous collision detection (CCD, RigidBodyDesc.setCcdEnabled(true)) sweeps a body along its motion instead of checking only where it lands. Turn it on for small, fast bodies such as projectiles. But measure your own case: in a test for this topic, a 1 cm bolt at 200 m/s passed through a thin moving plate in Rapier 0.21 with CCD on as well as off, while at 20 m/s it was caught. Fast, small, moving objects are where engines are weakest: cap speeds, thicken colliders, or use a raycast for bullets.

Explain it without notes

01

Why does physics use a fixed timestep, and how does the accumulator make it work at any frame rate?

02

What is tunnelling, and what can you do about it?

Practice

01

Write createFixedStepper(step, onStep) returning { tick(delta) } with the accumulator and the cap.

02

Extend it to return alpha from tick for interpolation.

Done when you can

  • You step physics by a fixed amount with an accumulator and a cap

  • You can explain alpha and interpolation

  • You can explain tunnelling and when to turn on CCD

  • You test fast objects at their real speed