Skyfall's entire game world is one <canvas> element, and that canvas has to look sharp whether it's filling a 13-inch laptop screen or a cramped phone browser with three times the pixel density. Getting that right takes a bit more than setting a width and height once — canvas has a quirk where its logical size and its actual pixel buffer are two separate numbers, and mixing them up is the single most common way to end up with a blurry game.

Two sizes, not one

Every time the window resizes — including the very first load — Skyfall measures its container in CSS pixels and stores that as its logical width and height. But it doesn't hand those numbers straight to the canvas. It also reads window.devicePixelRatio, which tells you how many actual screen pixels are packed into each CSS pixel — 1 on a standard monitor, often 2 or 3 on a modern phone — and multiplies the canvas's actual pixel buffer by that ratio while leaving the element's on-screen CSS size alone. The drawing context is then scaled by that same ratio, so every coordinate you write in game code (bird positions, the crosshair, score popups) still lines up with normal, unscaled pixels — the browser handles turning that into a denser buffer.

Skip that step and a high-density phone screen will happily stretch a low-resolution canvas across more physical pixels than it has data for, and everything — birds, text, the crosshair — comes out visibly soft.

Why the ratio is capped at 2: some devices report a device pixel ratio of 3 or higher. Rendering at true 3x resolution on every frame is a real GPU and CPU cost for a game that's already redrawing birds, particles, and a gradient sky sixty times a second, and the visual gain past 2x is minor on a game with no fine text or photographic detail. Capping the ratio keeps frame times consistent on lower-end phones without a visible sharpness trade-off.

Resizing live, not just on load

The same measurement routine runs again on every window resize event, not only once at startup. That matters for anyone who rotates a tablet mid-session, resizes a browser window, or opens dev tools next to the game — the canvas recalculates its logical size, reapplies the pixel-ratio scale, and the game keeps rendering at the correct sharpness without a reload. Nothing about bird positions or game state depends on absolute pixel coordinates staying fixed, so a mid-round resize doesn't need any special-case handling beyond redrawing at the new dimensions on the very next frame.

More from the blog: read Mouse and touch, one input path for how the same canvas handles input across devices, or head back to the Blog index for the rest of our dev notes.