at play · case study
TIKI DASH
How a 3D endless runner gets built for the browser — product, agents, gameplay, art, and the GPU budget, from empty repo to shipped.

- role
- design & code
- stack
- Three.js · TypeScript · Vite
- built
- solo, with agents
- status
- live — free, in the browser
The product, before the polygons
An endless runner is a dopamine loop — swipe, near-miss, one more run — and the browser makes the install a link: no store, no download screen. After the first visit a service worker keeps all ~13.9 MB playable offline, installable like any app. Those two choices set the engineering bar in one sentence: as smooth as the genre's giants, on the phones people actually hold, without dimming the jungle.
A process with gates
The build follows a playful-production discipline: prove the fun first, gate every phase, let the gates say no.
- 01
- prototype — one test to pass: a stranger finishes a run and starts another, unprompted
- 02
- vertical slice — the core loop at shippable feel — the gate where the game earns production
- 03
- design macro — scope locked in writing; from here it may deepen, never grow
- 04
- alpha — feature-complete in greybox — systems before beauty
- 05
- content — river crossing, cave bore, tiki shrine, tutorial, missions
- 06
- art slice — one purchased palette, one licence audit, one shared atlas
- 07
- performance — instruments in the build, verdicts from the real phone
- 08
- ship — PWA, one build for two channels, deploy on push
Built with agents
The workforce is one person directing LLM agents. The repo carries a standing working agreement — a persona, hard mobile-performance rules, a shorthand vocabulary for recurring jobs — so every agent session starts already knowing the frame budget, the zero-allocation render loop, and the pipeline's bounds. Decisions and lessons persist in append-only project logs that agents read and write: the project's memory outlives any single session. Research runs at fan-out scale — the art-sourcing survey was a 105-agent sweep before a dollar was spent. And nothing merges on an agent's word: the phone has the last one. This page, too, was distilled from those logs by an agent.
Designing the run
Game feel is numeric, not vibes. Touch follows newest-input-wins: a jump swiped mid-slide cancels the slide instantly. Swipes chain — one touch can fire several actions, the gesture origin re-anchoring under the finger, with a chained action requiring more travel (36 px) than a first swipe (28 px) so intent stays unambiguous. Collision is a fairness contract: the hit window must stay inside the lane midline, so a player who has committed to the next lane can never be clipped by an obstacle they visually cleared —
The look, on a budget
The style is modern toon: the whole world UV-maps into one 1024² palette atlas, colored by a single toon material with a four-band ramp — one texture, one shader, one draw philosophy. The line work is a whole-scene screen-space ink outline: the scene renders offscreen, and a composite pass draws a line wherever depth breaks, tinted with the surface's own color. The bushes and grass are the palm crowns themselves — cropped and dome-squashed — so all vegetation speaks the same painted language. Even sharpness is a dial: mobile renders at pixel ratio 1.35, tuned by eye to where the flat-fill style stops gaining from more pixels. The art direction and the frame budget are the same decision seen from two sides.
Two budgets, one frame
A frame pays two bills: the CPU bill, charged per draw call, and the GPU bill, charged per triangle, per shaded pixel, per megabyte of texture touched. The frame ships when the slower bill clears — so the architecture is built to keep both small from the start.
The CPU bill is paid with instancing: hundreds of trees, rocks and collectibles render as a few instanced meshes — even the coconuts, spawning and despawning constantly, are one instanced draw fed from an object pool. The GPU bill is paid with the shared atlas, flat toon shading, and per-asset triangle budgets — ~205k triangles a frame, all instanced volume: the 72 shipped models total only ~112k in their files.
Measured on the real thing
Every performance verdict comes from the target phone, not a desktop GPU — under a standing protocol (rested, charged, nothing in the background), because thermal state alone can move a reading by ~5 fps. The build carries its own instruments: a frame-time flight recorder shipping ring-buffer logs off the device, and a bench mode that A/B-cycles render variants in interleaved segments so every comparison shares the same thermal reality. The instruments earn their keep by protecting the art: the sweep proved jungle density costs nothing on mobile — so the phone gets the full jungle — and named fill rate the one lever that matters, which is exactly where the pixel-ratio dial sits. Development instruments are stripped from public builds at compile time.
Shipping it
One build goes everywhere: relative asset paths let the same dist/ run at the root of tiki-dash.com and inside itch.io's nested CDN. The game ships as a progressive web app — 102 precached files, fully playable offline. Audio ships as 192 kbps AAC: 2.9 MB of source WAV becomes 310 KB. Licences are audited, not assumed — purchased pack, CC BY credits, CC0 audio. And deploying is a push: merging to main triggers CI, which builds once and delivers to both channels.
The spec
- 60 fps
- vsync-locked on a 2020 mid-range phone
- ~70
- draw calls per frame
- ~205k
- triangles per frame, instanced
- 1024²
- one palette atlas colors the world
- ~13.9 MB
- the whole game, offline-capable
Next
The music and ambience pass, menus and settings, the final art polish. The game is playable today — polish lands in place, because deploying is a push.