Why Browser Games Feel Smooth: Canvas and Frame Timing
By JingPublished Updated 8 min read1,392 words
In this guide
HTML5 canvas game performance is not mysterious, and it is not mostly about hardware. A smooth browser game does a fixed amount of work in a fixed amount of time, once per screen refresh, and draws in step with the display. A stuttering one breaks one of those three rules. This article explains the loop, the budget and the tools that measure them, and then describes what happens in the one situation every player creates: leaving the game in a tab they are not looking at.
The reference points are public and stable. Mozilla documents the function that drives the loop, web.dev documents the frame budget and the stages of drawing, and Chrome's developer tools measure both on any page. The facts about this site's game come from its code and are stated as such.
The loop: one frame per screen refresh
A canvas game is a loop. Each pass reads input, updates the state, clears the canvas and draws the new state, then waits for the next pass. The waiting is the part that decides smoothness, and browsers provide one function for it. Mozilla describes requestAnimationFrame as a method that tells the browser you wish to perform an animation. It requests the browser to call a user-supplied callback function before the next repaint.
The key word is repaint. The display refreshes on its own schedule, and a game that draws between refreshes wastes work or shows a half-drawn frame. Scheduling the draw just before the repaint means every frame the screen shows is a complete one. The same page notes that the frequency of calls generally matches the display refresh rate, most commonly sixty per second, with 75, 120 and 144 hertz displays also common, so a game written this way automatically runs faster on a faster screen.
The older alternative, a timer that fires every so many milliseconds, drifts against the refresh and is why early browser games felt uneven. Arrow Escape uses requestAnimationFrame for drawing and a one-second timer for the clock, which is the right split: the countdown does not need to be smooth, and the arrows sliding off the board do.
The budget: sixteen milliseconds, of which you get ten
At sixty frames per second each frame has 16.66 milliseconds. Paul Lewis's rendering performance guide on web.dev makes the practical point that the browser needs some of that for itself: the browser has 16.66 milliseconds to produce each frame. In reality, though, the browser has its own overhead for each frame, so all of your work needs to be completed inside 10 milliseconds. Miss the budget and the frame is late; the screen repeats the previous one, and the player sees a hitch.
The same guide names the five stages every frame can pass through: JavaScript, style calculations, layout, paint and composite. A canvas game mostly avoids the middle three, because it is not changing the page's elements, only the pixels inside one element. That is a large part of why canvas games feel responsive on modest hardware: the frame is JavaScript plus paint, and the browser has less to recompute than it would for a page that moves its layout around.
What eats the budget in a puzzle game is not drawing but thinking done at the wrong time. Checking whether an arrow's line is clear is cheap. Recomputing the whole board's state every frame is not, and neither is allocating new objects each pass so that the garbage collector interrupts the loop. Arrow Escape computes occupancy once per level and updates it when an arrow leaves, so each frame draws a known state rather than rederiving it.
| Stage | What it is | Cost in a canvas game |
|---|---|---|
| JavaScript | Game logic and drawing calls | The main cost; must stay well under 10 ms |
| Style | Working out CSS for elements | Near zero; the canvas is one element |
| Layout | Positioning elements | Near zero unless the page resizes |
| Paint | Filling pixels | The canvas drawing itself |
| Composite | Combining layers for the screen | Small; larger with many overlapping layers |
Sharp pixels: the device pixel ratio
A canvas has two sizes: the number of pixels it holds, and the size it is displayed at in CSS. On a phone whose screen packs two or three physical pixels into each CSS pixel, a canvas sized naively is upscaled and looks soft. Mozilla's canvas optimization guide gives the fix: scale the canvas size up and down simultaneously using its attributes, styling and its context's scale, by multiplying by the device pixel ratio and scaling the drawing context to match.
The same guide lists the other habits that keep a canvas fast: pre-render repeated shapes to an offscreen canvas rather than redrawing them each frame, use whole-number coordinates because sub-pixel positions force the browser to blend edges, and drive the loop with requestAnimationFrame rather than a timer. None of these are exotic. They are the difference between a game that looks crisp on a new phone and one that looks like a photograph of itself.
Arrow Escape sizes its canvas by the device pixel ratio on every resize, which is why the thin arrow bodies stay sharp when a player zooms into a dense board. The zoom itself is a scale factor applied before drawing, not a resize of the canvas, so pinching in does not trigger a relayout of the page around the game.
What happens in a background tab
Every player eventually switches tabs mid-level, and what the game does then follows from the loop. Mozilla's documentation is explicit: requestAnimationFrame() calls are paused in most browsers when running in background tabs or hidden iframes, in order to improve performance and battery life. The drawing stops. Nothing is rendered that nobody can see.
Timers are treated differently and less uniformly. Browsers slow them in background tabs rather than stopping them, so a countdown driven by a one-second timer generally keeps counting, if less precisely. In Arrow Escape that means a level left in a hidden tab keeps losing time on its clock while its board is not redrawn, and the player returns to a frozen picture and a lower number. The game does not pause itself on tab switch; level 1, which has no clock, is the only level where leaving costs nothing.
This is worth knowing for two reasons. The practical one is not to leave a timed level in a background tab. The technical one is that the game's correctness does not depend on frames being drawn: the state lives in the script, the canvas only shows it, and the next frame after the tab returns draws the true state. A game built the other way round, where the drawing is the state, would break every time the browser paused it.
Measuring it yourself
None of this needs to be taken on faith, because Chrome ships the instrument. Its developer tools include a Performance panel that, in the documentation's words, captures performance metrics as the page runs, and shows the frame rate over time; whenever you see a red bar above FPS, it means that the framerate dropped so low that it's probably harming the user experience. The same panel flags long tasks, the stretches of JavaScript that overrun the budget.
Recording a few seconds of any browser game there answers the question this article opened with. A smooth game shows a steady frame rate and short, regular slices of script time. A stuttering one shows red bars, and the flame chart underneath shows what was running when the frame was missed. It is the same tool the site uses to check its own games, and it is free to anyone with the browser.
What to read next
The reason a loaded game needs no server for the rest of a session, and what that means for playing offline, is in do HTML5 games work offline?.
The performance costs a site chooses to add, in particular advertising that shifts the layout or competes for the main thread, are part of how free browser games make money, which is the honest account of why a free game is not free of trade-offs. To feel the loop rather than read about it, play Arrow Escape and tap a free arrow: it starts moving on the next repaint, and that gap, a sixtieth of a second on most screens, is what this article has been about.
Play the game
Frequently asked questions
- Why do some browser games stutter and others feel instant?
- A smooth game finishes each frame's work inside the time the display gives it, about sixteen milliseconds at sixty frames per second, and draws in step with the screen using requestAnimationFrame. A stuttering game either does too much per frame or draws out of step, so frames are skipped or repeated.
- Does a browser game keep running in a background tab?
- Its drawing stops, because the browser pauses animation callbacks in tabs you cannot see. Timers may keep running at a reduced rate. In Arrow Escape the board is not redrawn while hidden, and the countdown continues, so a level with a clock should not be left in a background tab.
- Why do lines look blurry in some canvas games on a phone?
- Because the canvas was sized in CSS pixels on a screen with more physical pixels per CSS pixel. The fix is to scale the canvas by the device pixel ratio and scale the drawing context to match, which is what MDN's canvas optimization guide recommends and what this game does.
Sources
- Window: requestAnimationFrame() method — MDN Web Docs (Accessed September 15, 2026)
- Rendering performance — web.dev (Paul Lewis) (Accessed September 15, 2026)
- Analyze runtime performance — Chrome for Developers (Accessed September 15, 2026)
External links are provided for reference and are not endorsements.