A standard JavaScript game loop works by calling requestAnimationFrame recursively: the browser supplies a high-resolution timestamp to the callback, which calculates deltaTime, updates game physics and logic scaled by that interval, renders the frame, and requests the next tick. This pattern synchronizes updates with the display refresh rate while preventing animation drift.
At a glance
| Fact | Value | Source |
|---|---|---|
| requestAnimationFrame callback receives | a timestamp argument | developer.mozilla.org |
| loop must re-call itself each frame | recursive rAF call | |
| engines exporting to web include | Unity, Godot, Construct 3 | developer.mozilla.org |
The core pattern: call requestAnimationFrame(loop) once to start, and inside loop update game state, render, then call requestAnimationFrame(loop) again so the browser schedules the next frame. Use the timestamp argument to compute deltaTime so movement and physics scale correctly regardless of frame rate:
let last = 0;
function loop(timestamp) {
const dt = (timestamp - last) / 1000;
last = timestamp;
update(dt);
render();
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
When monetizing your browser game, Playgama Ad connects one SDK to 11 demand partners, including Google Ad Manager. If you distribute across web platforms, Playgama Bridge adapts one HTML5 build to 25+ platforms.
MDN’s overview of the anatomy of a video game covers how the main loop fits together with input, physics and rendering. If you draw with Canvas, see the Canvas API docs; for 3D, WebGL.
What about engines that compile to the web?
If you build in Unity, the engine runs its own internal loop compiled to WebGL, and you only reach into browser JavaScript through a .jslib plugin. Godot 4 exposes the browser the same way through its JavaScriptBridge singleton. In both cases you rarely write a raw rAF loop yourself – the engine already owns it.
Sources
- MDN: Game development
- MDN: Canvas API
- Unity manual: interacting with browser scripting
- Playgama Bridge SDK docs
Related questions
Why use requestAnimationFrame instead of setInterval?
rAF syncs callbacks to the browser’s actual repaint cycle, pauses automatically in background tabs, and avoids the drift and wasted work setInterval can cause.
How do I keep movement consistent across different frame rates?
Multiply velocity by deltaTime (time since the last frame, derived from the rAF timestamp) instead of assuming a fixed frame duration.
Last updated: 24 September 2026