Skip to content

How Modern Browsers Actually Run a Game

B
Bethany

A plain-English walkthrough of what happens between a user clicking a thumbnail and a game appearing on screen. The modern web has more game-ready plumbing than most people realise.

A Browser Is a Surprisingly Good Game Console

A modern web browser is a strange piece of software. It started life as a document viewer in the early 1990s, was incrementally repurposed for interactive applications through the 2000s, and is now a full-featured runtime that can execute games shipped from anywhere in the world, on demand, with no install step.

Most people who use browsers daily have no idea what the browser is doing when a game runs. This post is a walkthrough of the stack — what every modern browser game uses, in plain English, with as little jargon as the subject permits.

The Path From Click to Play

When you open a game on a browser-game portal, here is what happens in the first few seconds:

Step 1: The browser fetches the game's HTML page. This is the entry point. The page contains a <canvas> element where the game will be drawn, plus a script tag pointing at the game's code.

Step 2: The browser fetches the game's script. Usually a single JavaScript file (the Three.js games on YoyoArena ship about half a megabyte of JavaScript in total, before compression), often containing the game engine, the game logic, and the asset metadata. In modern browser games, this script may have a WebAssembly module attached, which is a compiled, optimised version of the same logic running at near-native speed.

Step 3: The browser fetches the game's assets. Sprites, sounds, level data — the actual content of the game. Modern games are usually structured so the smallest assets needed for the first interaction load first, with the rest streaming in while you play.

Step 4: The script initialises the game. It sets up the canvas, loads the assets it has so far, starts a game loop.

Step 5: The game loop begins running. Sixty times a second (or 120, on a high-refresh-rate display), the browser asks the game to draw a new frame. The game responds with new pixel data. The browser flushes that to the screen.

That whole sequence, from click to playable, typically takes one to three seconds on a modern mid-range device. Twenty years ago this would have been a multi-minute install. Five years ago it would have been ten seconds of loading screen.

What's Doing the Heavy Lifting

The pieces of the modern browser that game developers actually care about:

The JavaScript engine. Every major browser has a heavily-optimised JavaScript engine — V8 in Chrome and Edge, SpiderMonkey in Firefox, JavaScriptCore in Safari. These engines have decades of compiler work behind them and can run game logic at a substantial fraction of native speed for typical workloads. That used to be unimaginable; for casual games it is now plenty.

WebAssembly. Where JavaScript is not fast enough — physics simulations, audio processing, large game engines — WebAssembly (Wasm) fills in. Wasm is a binary format that compiled languages (C, C++, Rust, AssemblyScript) target. The browser runs Wasm at close to native speed. Modern game engines like Godot and Unity ship to the web by compiling their C++ runtimes to Wasm.

WebGL and WebGPU. These are the rendering APIs. WebGL has been the standard since around 2011; WebGPU is the newer, more powerful replacement: Chrome and Edge have shipped it since 2023, and Safari and Firefox followed in 2025 with partial support. Both let games talk directly to the GPU, which is the only way to draw thousands of sprites or full 3D scenes at 60 frames per second. The shift from CPU-only drawing (the Flash era) to GPU-accelerated drawing is the single biggest reason browser games look good now.

Canvas2D. The lower-tech option, for games that do not need 3D or massive sprite counts. Canvas2D is older and simpler, with a small performance ceiling but easier authoring. Most casual puzzle games use Canvas2D.

Web Audio API. The audio counterpart to WebGL. Lets games schedule sound effects precisely, manipulate audio in real time, layer music and effects. Older browsers had a single "play sound" function with timing as a suggestion; modern Web Audio is studio-quality.

Pointer Events and Gamepad API. The input layer. Pointer Events normalised the differences between mouse, touch, and stylus input. Gamepad API exposes connected controllers when present. Together, these let a single game support every input type without writing input-handling code three times.

LocalStorage and IndexedDB. Save state. Local browser-side storage that persists across sessions. Most casual games use LocalStorage for high scores and player progress; bigger games use IndexedDB for larger save data. This is what makes "the game remembers your progress" work without a server account.

Service Workers. A modern feature that lets a page register a background script that runs even when the page is closed. For games, the main use is enabling offline play — service workers can cache the game's assets so the player can come back without internet and still play.

What YoyoArena's Own Games Use

The list above covers everything a browser offers. The 23 games in the YoyoArena library show how little of it a casual game actually touches. The figures below come from the games' own source code and production builds. The draw-call counts come from a test run in headless Chrome in a phone-sized 480 by 854 window; draw calls are counted on the CPU side, so they do not depend on the graphics card, which is why they are the only performance numbers quoted here.

Three ways to draw. Eleven of the games render with Three.js on WebGL, three use the Phaser engine, and nine are written straight against the Canvas 2D API with no engine at all.

Download size follows the engine, not the game. The Three.js games ship 480 to 520 KB of JavaScript, which is 121 to 132 KB after gzip compression (the production nginx configuration compresses scripts). The Phaser games ship 1.5 to 1.7 MB, about 350 to 385 KB compressed. The Canvas 2D games ship 11 to 35 KB, or 4 to 12 KB compressed, and load their whole first screen as three files totaling 18 to 46 KB.

Snake is about 19.5 KB of its own code sitting next to a 460 KB copy of Three.js. For a small studio the engine is the biggest load-time decision, and it is made before the first line of game code is written.

Version floors are real. Three.js dropped WebGL 1 support in release r163, and the Three.js games use r170, so they need WebGL 2, which Safari only enabled by default in version 15 in 2021. The Canvas 2D games have no such floor.

Draw calls vary more than a hundredfold. On their first screens the Three.js games issued anywhere from 2 to about 325 draw calls per frame. Snake issued 5 on its start screen and 9 once a three-segment snake and the first food were on the board, because every object (the grid, four border bars, each snake segment, the food) is its own mesh and therefore its own draw call. Cube Jump issued 81 and Rollout, a 3D sky road, about 325. It is one of the first numbers worth checking when a game stutters on a phone.

What the games leave out. None of the 23 uses WebAssembly, WebGPU, IndexedDB or the Gamepad API. Twenty-two use LocalStorage, for best scores, level progress and settings. Seventeen make their sound with the Web Audio API, generating it with oscillators, and none ships an audio file; the other six have no sound at all.

For input, 15 listen for Pointer Events, 13 for raw touch events, 19 for the keyboard and 6 for the mouse, and many use more than one. The working toolkit for this kind of game is a JavaScript engine, a canvas, a frame loop, a little synthesized audio, local storage and some input handlers. That is a much shorter list than the one above.

What's Hard in a Browser

To be fair to the browser, not every game ships smoothly to it. The hard cases:

Anything that needs raw CPU performance. AAA physics simulations, large-scale procedural generation, scientific computation. Browsers run code in sandboxes for security; the sandbox has overhead. WebAssembly closes most of the gap, but not all of it.

Anything that needs to write files. Game engine creation tools, mod managers, anything that wants to install or modify files on the user's system. The browser sandbox forbids this by design, which is good for users and bad for tools.

Latency-sensitive multiplayer. Real-time competitive games where every millisecond matters. WebSockets and WebRTC handle most of the use cases, but a tight FPS on a competitive ladder is still better on a native socket.

Memory-intensive content. Browsers limit how much memory a single tab can use. Most games are well below the limit, but anything that wants to load gigabytes of high-resolution assets at once will struggle.

For everything else — and that "everything else" is most of the casual gaming market — the browser is a remarkably capable runtime.

Why This Matters to a Player

If you are a player rather than a developer, none of this directly affects you. You click the game and it works. That is the point. The plumbing should be invisible.

But the plumbing affects your experience in concrete ways. A game that loads in two seconds (because the developer used modern code splitting and asset streaming) gives a better first impression than a game that takes twelve seconds (because the developer hasn't kept up with current practice). A game that runs at 60 frames per second on your phone (because the developer used WebGL appropriately) feels better than a game that stutters at 25 frames (because the developer is drawing pixel-by-pixel on Canvas2D when they shouldn't be).

Players and portals can both tell the difference. Slow loads, stuttery frame rates, memory leaks, jank — these are signals that a developer has not done the work, and the player notices even when they cannot articulate why.

Why This Matters for the Web in General

Browser games are the canary in the coal mine for what the web platform can do. Games push the browser harder than almost any other application — they need consistent frame rates, low input latency, large but fast asset delivery, and reliable cross-platform behaviour.

When browsers improve for games, they improve for everything else too. The WebGL work that made browser games viable also enables data visualisation libraries, mapping tools, and interactive design software. The WebAssembly work that brought C++ game engines to the web also brought CAD tools, statistical packages, and scientific applications. The audio API work that enabled real-time game audio also enabled music production tools.

Every era of web platform investment is downstream of someone pushing the browser hard. Right now, that someone is the game development community. It will keep pushing, and the web will keep getting better as a result.

A Note on the Next Few Years

The current trajectory of the browser as a runtime is toward more native-feeling games. WebGPU is rolling out broadly. WebAssembly's ecosystem is maturing. Mobile browsers are catching up to desktop ones in raw capability.

The browser games of 2030 are likely to be quite different from the browser games of 2020. They will look more like native mobile games. They will load faster, run at higher resolutions, and use the full hardware capabilities of the device the player is on. They will mostly continue to be short, sessionable, and ad-supported — but the gap between "browser game" and "real game" will narrow further.

The plumbing is ready. The interesting work is mostly above it.

Sources

  • WebGL 2.0 support tables (caniuse): the first browser versions with WebGL 2, among them Chrome 56, Firefox 51 and Safari 15.
  • Three.js Migration Guide: the r162 to r163 entry, "WebGLRenderer no longer supports WebGL 1."
  • WebGPU support tables (caniuse): Chrome and Edge from version 113, Safari from 26 and Firefox from 141, the last two with partial support.
  • Service Worker API (MDN): service workers are meant, among other things, to enable offline experiences.