Building an HTML5 game with no engine and no framework
· 3 min read
Six of the nine games on our originals page ship with no dependency of any kind. No engine, no framework, no build-time library. The smallest, Reefhold, is 63 KB on disk — the whole game, art included. The three newest deliberately break the rule, and it is worth saying why in both directions.
What "no engine" actually means
In practice it is three things: a <canvas> element, a loop driven by
requestAnimationFrame, and every shape on screen drawn by code rather than
loaded as an image. There is no scene graph, no entity-component system, no
asset pipeline. A sprite is a function that takes a context and some numbers
and calls fillRect a few times.
That sounds primitive because it is. It is also the reason Reefhold loads before you have finished reading its title.
The three things you end up writing yourself
An engine hands you these for free. Without one, they are the first three files you write, and they are the same three files in every game:
- A fixed-timestep loop.
requestAnimationFramegives you a wall-clock delta, not a tick. If you move things by that delta directly, the game runs differently on a 60 Hz laptop and a 144 Hz monitor, and physics that felt right in testing goes strange in the wild. The fix is to accumulate real time and step the simulation in fixed slices, rendering an interpolation between the last two. - Input that is the same on touch and keyboard. Half the traffic is
phones. A game that reads
keydownand nothing else is unplayable for those people, and one that special-cases touch everywhere is twice the code. The trick is to normalise both into one small "intent" object — a direction and a set of held actions — and let the rest of the game read only that. - Audio that survives autoplay policy. A browser will not let a sound
play until the user has interacted with the page. If you create your
AudioContexton load it starts suspended and never recovers. Create it on the first pointer or key event instead, and gate every later sound on that.
That is roughly 150 lines, shared verbatim across the games that use it.
What it buys
- A bundle a portal never questions. Curated portals have hard size limits and reject over them without appeal. A 63 KB game is not a conversation.
- A first load that is instant, which on mobile data is the difference between a player and a bounce.
- Nothing to license. When someone asks to license one of these games, there is no third-party licence to read them, no attribution file, no "well, it depends on Phaser and Phaser is MIT but".
Where the line is
Scrapforge, ScaleSling and Husktide are built on Phaser, and that was the right call for all three. Scrapforge and ScaleSling need a real physics solver, and a 2D constraint solver is not something worth writing again badly. Husktide puts hundreds of entities on screen at once and leans on a texture atlas and a tuned renderer to do it.
The pattern is clear enough in hindsight: the pure approach scales to games about placement and timing — most puzzles, most idle games, most arcade-score games. It stops scaling the moment you need many interacting bodies or a physics model with corners. At that point an engine is not overhead, it is the thing keeping the bundle smaller than the hand-rolled version would end up.
The per-game sizes are all published on the licensing page, if you want the actual numbers.
Filed under gamedev, javascript, canvas.
