How a whole game fits in a single web page
A tour of what a browser hands you for free, why canvas and requestAnimationFrame are enough to build on, and the four places this approach genuinely runs out.
By Aayush Kumar · How it works · 9 min read
The smallest game on this site is Peacock Glide, at just under 24 kB. The largest is Atlas Globe at 150 kB, and most of that is coastline data for a spinning world built from real Natural Earth outlines. A single photograph off a modern phone is ten times the size of either. That gap is the thing worth explaining, because it is not a trick and it is not compression.
What the browser already gives you
A game needs, at minimum, four things: a surface to draw on, a clock that ticks in time with the display, a way to read input, and somewhere to keep a high score. Every browser written in the last decade ships all four, and they cost nothing to use.
The surface is <canvas>, a rectangle of pixels you can draw shapes and text onto with about thirty function calls. The clock is requestAnimationFrame, which asks the browser to call your function immediately before it next paints the screen — 60 times a second on most phones, 120 on some, and zero times a second when the tab is in the background, which is exactly the behaviour you want. Input arrives as pointer events that treat a mouse, a finger and a stylus as the same kind of thing. And localStorage is a small key-value store, private to that page, that survives closing the tab.
Put those together and the shape of every game here is the same:
let last = null;
function frame(ts) {
const dt = last === null ? 0 : Math.min(0.05, (ts - last) / 1000);
last = ts;
update(dt);
draw();
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
The clamp on the second line is the detail that separates a game that works from one that does not. dt is how many seconds passed since the last frame, and everything in the simulation is multiplied by it so that movement is measured in units per second rather than units per frame. If the phone drops a frame — a notification arrives, the browser garbage-collects, someone opens the notification shade — dt could come back as 0.4 seconds, and a ball travelling at 30 units per second would jump 12 units in one step, straight through a wall it should have bounced off. Clamping to 50 milliseconds means the game briefly runs in slow motion instead of teleporting. Slow motion is recoverable. Tunnelling through a wall is not.
Where the bytes actually go
A 40 kB game file is not a compressed asset bundle. It is text: a few hundred lines of CSS, a few thousand lines of JavaScript, and the markup for whatever buttons and panels sit over the canvas. There are no image files because nothing is a photograph — a paper boat in Boat Tagger is a handful of filled paths, and the mint checkerboard in Pixel Snake is two nested loops filling rectangles. Drawing a shape in code is usually shorter than storing a picture of it, and it scales to any screen size for free.
Sound works the same way. Every game here builds its audio with the Web Audio API rather than loading sound files: an oscillator, an envelope, a filter, and you have a coin pickup in about eight lines. A single short MP3 would outweigh the entire game. The trade is that this style of synthesis suits blips, thuds and sweeps and is hopeless for anything that needs a recorded voice or a piece of music — which is why Housie, which needs to call out numbers aloud, uses the browser's own speech synthesis instead of shipping ninety recordings.
What is left is logic, and logic is cheap. The rules of Chess — castling through attacked squares, en passant appearing for exactly one move, threefold repetition that folds castling rights into the position it hashes — are fiddly to get right and take up almost no space once written.
Why nothing needs installing
An installed app is a bundle of code that has to be signed, reviewed, distributed through a store, granted permissions on your device, and updated separately on every device you own. A web page is a file a server hands you when you ask for it. Your browser has already done the hard part — it has a sandbox, a renderer, a JavaScript engine and a graphics path — and it will not let the page out of that sandbox, which is why it can run a stranger's code without asking your permission first.
That is the whole reason there is no install step. The game is not being installed; it is being read, the way an article is read. Close the tab and nothing remains except whatever it put in localStorage, which for these games is a best score, a difficulty preference and sometimes a win-loss record — a few dozen bytes. Carrom Clash uses it to keep a rivalry alive between visits. Nothing is uploaded, because there is nowhere to upload it to.
function save(key, value) {
try { localStorage.setItem('carrom:' + key, value); }
catch (e) { /* private mode, quota, disabled — just carry on */ }
}
The try matters. Private browsing windows and locked-down devices can make localStorage throw on access rather than simply return nothing. A game that assumes it works will crash on load for a fraction of visitors and there is no error report coming, because there is no server involved.
The honest limits
This approach genuinely runs out, and it is worth being precise about where.
Large assets are off the table. Anything that needs gigabytes of textures, motion-captured animation or an orchestral score is not going to arrive over a mobile connection in the two seconds you have before someone loses interest. The games here are short by design, but they are also small by necessity, and those two constraints happen to agree with each other.
Some of them do load one external file. Twenty-five of the 78 games are 3D, and those pull the Three.js rendering library from a public CDN rather than embedding it. Tennis 3D, Voxel Peak Climb and the rest of that group need a working connection on first load in a way the 2D games do not. The game's own code is still one file; the renderer underneath it is shared. That is a deliberate trade — embedding a copy of a 600 kB library in each of twenty-five files would make every one of them worse — but it is a real dependency and pretending otherwise would be dishonest.
There is no filesystem. A page cannot write a save file to your device, scan your folders, or leave anything behind that another page can read. For a game that stores one integer this is irrelevant. For anything with a real save system it is a wall. It also means clearing your browser data clears your best scores, with no cloud copy, because there is no account.
Battery and heat are real. A canvas redrawing 60 times a second is genuine work, and a phone will warm up. The mitigations are all the same shape: stop drawing when nobody is looking. Every game here listens for visibilitychange and pauses when the tab goes to the background, and the 3D games clamp their pixel ratio rather than rendering at the full native resolution of a high-density display, which is the single biggest saving available on a phone. The frame-rate question on mid-range Android deserves its own treatment.
Audio will not start by itself. Browsers refuse to let a page make noise until the user has touched it, which is a good rule that makes the first tap in every game slightly special: it is also the moment the audio context wakes up.
The thing that is easy to miss
Because it all runs on your device, nothing about how you play leaves it. Your Perfect Circle score is not compared against a global leaderboard, because there is no leaderboard and no request being made. The percentage is computed by resampling your stroke, working out the centre and average radius from the points, and measuring how much the radius wandered — several hundred lines of arithmetic running on the phone in your hand, finishing before you have lifted your finger.
That also means the games keep working when the connection does not. Once a 2D game's page has loaded, the network is irrelevant to it: Spinout does not care whether the train has gone into a tunnel. It is the same property that makes an image finish loading even as the signal drops, applied to something that can be played.
None of this is new technology. Canvas has been in browsers since 2005 and requestAnimationFrame since 2011. What has changed is that phones got fast enough that a scripting language drawing shapes into a 2D context is entirely sufficient for a game you play for four minutes — and that, having got fast enough, nobody needed the installer any more. The interesting engineering moved elsewhere: into what the computer opponent is actually doing, and into making a touchscreen feel like a controller.
More from ARTHIS.space
- Game AI How the AI in these games actually works, and how to beat it Four genuinely different approaches to computer opponents, the numbers behind each one, and the specific weakness every approach hands you.
- Board games Chess, Ludo, Carrom and the rules people argue about The six classic boards here all had rule decisions to make, and most of those decisions are the ones your family has been arguing about for years.
- Short games Twelve games you can finish in the time it takes to boil a kettle Twelve games that start instantly, end cleanly and do not ask for a second session — plus four that look short and are not.