ONESHOTGEMS

For game developers

A game loop that stays predictable across displays

A browser game loop coordinates simulation, drawing, and input, but those jobs should not be fused into an assumption that every screen produces the same number of frames per second. A callback may run at different refresh rates, pause in a hidden tab, or arrive late when the main thread is busy. Keep the simulation based on elapsed time and let the browser schedule presentation. That split makes movement easier to reason about and gives you a place to control what happens after a stall.

Separate state changes from drawing

Use requestAnimationFrame for the next visual update, then pass its timestamp into a small loop coordinator. Update positions, timers, and rules from elapsed time; draw the current state after updates. The renderer should not decide whether a collision happened, and a collision check should not depend on whether a sprite happened to be painted.

For a small platform test, move a marker horizontally at a chosen number of world units per second. Run the same route on a 60 Hz display and a high-refresh display. If the marker travels farther in the same wall-clock interval on one screen, some movement is still being applied per callback instead of per unit of time.

Choose a recovery policy for late frames

A long pause can produce an enormous elapsed interval. Clamp the elapsed value for a casual real-time game so a returning player does not see a character teleport through several obstacles. For deterministic simulations, use a fixed update step with an accumulator, run a bounded number of catch-up updates, and render between simulation states if interpolation is useful.

Record the longest callback gap during a repeatable obstacle course, then inspect the game after switching away and back. Decide whether the game should pause, catch up a little, or resume from the last state; make that choice explicit instead of letting a single delayed frame determine it.

Questions about browser game loop

Should I use setInterval for drawing?

Use requestAnimationFrame for visual work because it is scheduled near repaint and is commonly paused for hidden documents. A timer can still schedule nonvisual tasks, but it should not be treated as a display clock.

Where does the frame timestamp come from?

The requestAnimationFrame callback supplies a high-resolution timestamp. MDN documents its timing and one-shot behavior; use that timestamp to calculate progress rather than counting callbacks.

Sources and further reading

Report a correction · How these guides are made

Follow your curiosity