When a browser game is slow, the instinct is to look at the code. It is nearly always the wrong place.
Our largest build is twenty megabytes. The code in it, all of it, engine and game logic and interface, is a fraction of one per cent. Everything anybody waits for is pictures.
The proportions, honestly
Three builds, measured rather than estimated.
The smallest is a hundred and four kilobytes and contains no image files and no audio files at all. Everything in it is drawn in code and every sound is generated. It loads instantly on anything.
The middle one is 3.3 megabytes: fifty images, no audio files.
The largest is twenty megabytes: five hundred and two images and eighteen audio files.
The code in all three is comparable. The difference between a hundred kilobytes and twenty megabytes is entirely artwork, and that relationship is worked through properly in why one game is 104KB and another is 20MB.
Which means load time is an art direction decision. It is decided when somebody chooses painted scenes over drawn-in-code graphics, not when somebody writes a loop.
The failure that is not about size
There is one category of slowness that has nothing to do with how big anything is, and it is worth knowing because it produces the worst outcome available: a page that shows nothing at all.
Our chess build pulled two typefaces from a font service using an ordinary stylesheet link. A stylesheet loaded that way blocks the first paint: the browser will not draw anything until it has resolved the address, completed a handshake, made a round trip to somebody else's server and received the file.
On a good connection that costs a few hundred milliseconds. On a slow mobile connection, or a corporate network that filters that host, or a country where it is blocked, it costs everything. The game rendered completely blank, and the cause was not in the game.
The fix is to load the stylesheet in a way that cannot block, and let the fallback typefaces carry the first paint. The text appears immediately in a system font and swaps when the real one arrives. Three lines, and the difference between a game that always works and a game that works on the developer's network.
The general lesson is larger than fonts: anything fetched from a server you do not control is a dependency on somebody else's uptime, and if it blocks rendering it is a single point of failure for the whole thing.

One file or many
Our builds embed everything in a single document, which is a trade rather than a free win. It is set out in putting an entire game in one file.
The relevant part for loading: one request rather than hundreds, nothing that can go missing, works offline. But nothing appears until enough of the file has arrived, so a large single file has no way to show a first screen early.
For a game opened from a link that has finished downloading, that is fine and the game starts instantly. For a game embedded in a web page it is not fine at all, which is why the play pages on this site do not load the game with the page. They show a still, and fetch the game on the first press of the play button.
That is the single most effective loading optimisation available and it is not an optimisation at all, it is a decision not to do the work. A reader who never presses play never downloads a game.
What to actually do about images
Assuming the pictures have to exist, they can be much smaller than they usually are.
Use a modern format. The same painting in AVIF is routinely half the size of the same painting as a PNG, at a quality nobody can distinguish. Every image on this site is served that way, with an older format underneath for anything that cannot decode it.
Do not ship more pixels than are displayed. An image shown at eight hundred pixels wide does not need to be three thousand. This is the most common and most wasteful mistake, and it is invisible because the picture looks perfect.
Decode up front, not during play. An image that is first drawn during a frame pays its decoding cost in that frame, which shows up as a stutter at exactly the wrong moment. Our builds create every image as the file opens, before play begins, so no frame during play pays it.
Measure on the right machine
The reason performance problems ship is that they are invisible on the machine they were built on.
A development laptop on office broadband loads a twenty megabyte file in under a second and decodes five hundred images without noticing. A phone on a poor mobile connection at a party is a completely different machine, and it is the machine that matters.
Every build we ship is opened on a real phone before it goes out. Not simulated, not resized in a browser window. That is where the touch controls turned out to be overlapping, where a blank screen showed up, and where the difference between a comfortable file and an uncomfortable one becomes obvious.
What this means for a commission
Load time is an art budget conversation. Fewer distinct scenes, or drawn-in-code rather than painted, and the number falls dramatically. It is a real trade with real losses on both sides.
Nothing from anybody else's server should be able to stop the game. That includes fonts, analytics and anything convenient.
And twenty megabytes is not automatically wrong. For a family opening a keepsake on a link at home it is completely fine. For a game embedded in a page a stranger is skimming, it is not, and that difference is about context rather than about the number.



