// education / guide
How to Build a Browser Game From Scratch
Ember Keep is a complete tower-defense game — waves, bosses, an economy, four upgradeable towers, sound — running live on this site. There is no game engine underneath it. No Unity, no Phaser, not even a <canvas>. Just React, SVG elements moved by hand, and sound synthesized from raw oscillators. This guide takes it apart, layer by layer, from the highest-level architecture down to single-attribute DOM writes.
Who this is for
You write software or run infrastructure for a living, but game programming feels like a foreign country: people there say sprite, game loop and scene graph like everyone was born knowing them. This guide assumes zero game-dev background. Every term is defined the moment it appears, and wherever a game concept has a backend or DevOps cousin — and it usually does — the analogy is spelled out. A game loop, it turns out, is just a reconciliation loop with better sound effects.
Why this codebase makes a good textbook
ZombieTowerDefense.js and a handful of support files implement the whole game with no game engine and no audio files — every sound is synthesized live from the Web Audio API. The first shipped version didn't even use image files: all art was inline SVG shapes. Later, AI-painted PNG artwork was layered on top without touching the engine — and that upgrade path is itself one of the best lessons in here (part 2). Building this unusually means every chapter also has to explain what a "normal" game would do instead — so you learn the general vocabulary and one concrete implementation at the same time.
The route
What are the moving pieces of a game, and how do they talk to each other?
The game loop, why React alone can’t animate 50 zombies, and how one frame of gameplay actually happens — with DevOps analogies throughout.
How does a zombie go from “artwork” to “a moving thing with a health bar”?
Sprites, the anchor point (the one idea worth really understanding), a real coordinate-math bug, and how AI-painted art was layered on later without breaking anything.
Was DOM/SVG the right call? What would Canvas, PixiJS or Godot change?
The whole renderer landscape in one map — and the surprising answer to how much of the game is portable because it never touches rendering at all.
The cast of files
You'll meet these over and over. One file is the engine — the code that enforces the rules and draws the world. Everything else is data it reads:
| File | Role |
|---|---|
ZombieTowerDefense.js | The engine. One React component holding the game loop, the renderer, input handling and the HUD — everything else on this list exists to be read or called by it. |
td-config.js | All gameplay tuning: tower stats, zombie stats, the wave generator, the economy. Balance changes happen here and nowhere else — like a config file your service reads at startup. |
td-sprites.js | Generated SVG artwork: one markup string per sprite plus its anchor metadata. Header says "do not hand-edit" — it’s a build artifact, like a generated API client. |
td-sprites-elements.js | The painted-art layer: AI-generated PNG illustrations that override the generated sprites at runtime, keeping the same size/anchor contract. |
td-sfx.js | A synthesizer, not an audio player: arrows, cannons and zombie squelches built from Web Audio oscillators and noise at play time. Zero audio assets. |
zombie-tower-defense.css | Page-scoped styling for the HUD, plus CSS keyframe animations for ambient effects (mist, embers) that run without any JavaScript per frame. |
Ready? Start with the architecture — the one diagram that makes everything else in the game make sense.