This guide follows that second effort from a one-sentence idea to a small static build we could run, inspect, and package. The sample is deliberately modest: Lantern Relay asks you to collect three light seeds, avoid one moth, and return to the lantern before 35 seconds run out. Its job is not to impress you with content volume. Its job is to make every important game state easy to reach and understand.

Choose the smallest stack that can carry the idea

AI makes overbuilding dangerously easy. Ask for a browser game and you may receive a bundler, component framework, physics library, asset pipeline, and server before the character can move. Every dependency gives the agent more API surface to misunderstand and gives you more code to own after the conversation ends.

Start by choosing the rendering and authoring layer that matches the first complete loop, not the game you might build in a year:

Starting pointUse it whenWhat you still own
Plain Canvas + JavaScriptThe game is a compact 2D scene and a few files are enough.Scenes, collision, loading, camera behavior, and accessible HTML around the bitmap.
PhaserA 2D game needs reusable scenes, asset loading, animation, input, or physics helpers.Your rules, content structure, framework upgrades, and release testing.
Three.jsThe idea genuinely depends on 3D rendering or custom WebGL/WebGPU work.The game layer around the scene, camera, renderer, interaction, and assets.
Godot WebYou want an editor-led 2D/3D project or a shared project that may also target native platforms.Export size and a web host configured for the engine's browser constraints.

These are different trade-offs, not a quality ranking. The Canvas API is widely available and can draw game graphics directly, but canvas pixels do not provide semantic information to accessibility tools; important controls and status still need real HTML. Phaser provides a browser-focused 2D framework with Canvas and WebGL renderers. A basic Three.js setup begins with a scene, camera, and renderer, which is why it is a rendering foundation rather than a complete set of game rules. A Godot web export adds engine conveniences but can also add hosting requirements, especially for threaded exports.

We chose plain Canvas for Lantern Relay because one screen, circles, lines, and a deterministic update loop were enough. If your project is a visual 3D scene rather than a small game, our inspectable browser scene guide goes deeper on camera, selection, and rendering state.

Turn the game idea into verbs and states

“Make a cozy firefly game” describes a mood, not a system. We rewrote the idea as five player verbs: move, collect, avoid, return, restart. Each verb had to cause a state change that a person could see and a test could read.

Player verbRule-bearing changeQuestion we can answer
MoveThe player's coordinates change.Do keyboard and touch reach the same movement system?
CollectA seed leaves the active list; the counter increases once.Can all three seeds be collected without double-counting?
AvoidContact with the moth changes PLAYING to LOST.Is the reason for losing visible, and can the player restart?
ReturnLantern contact after three seeds changes the phase to WON.Does the win require the whole loop rather than a shortcut?
RestartAll rule-bearing values return to a known baseline.Can the same path be tried again without reloading the page?

That translation does two useful things. It exposes missing design decisions before they become code, and it gives the coding agent a definition of done that is harder to satisfy with a decorative mock-up. We also named the four top-level phases—READY, PLAYING, WON, and LOST—so menus, input, animation, and tests could refer to the same vocabulary.

Do this on one page. If you need a long design document to explain the first loop, the first loop is probably too large.

Give the agent one checkpoint, not the whole dream

A useful build request combines creative intent with operational limits. It tells the agent what the player should experience, what may change, what must stay untouched, how success will be checked, and where human permission is still required. Here is the compact version we would use for a new project after completing Lantern Relay:

Outcome
Build one complete browser-game loop: start, move, progress,
lose, win, and restart. Keep the first version intentionally small.

Player promise
Guide one firefly, collect three seeds, avoid one moth,
and return to the lantern before 35 seconds expire.

Constraints
- Use plain HTML, CSS, Canvas, and JavaScript in the existing folder.
- Use owned geometric placeholders; add no network dependency.
- Preserve unrelated files. Do not publish anything.

Observable rules
- Phases: READY, PLAYING, WON, LOST.
- Arrow/WASD and visible touch controls share one input model.
- Restart restores the documented baseline.
- Expose a versioned state snapshot and preset win/loss scenes.

Acceptance
- Test one real keyboard path plus win, collision, timeout, restart,
  mobile layout, desktop layout, and browser-console health.
- Save exact check names, results, and failure details.
- Stop before adding levels or polish. List the human checks left open.

This is a post-build template, not the original PaperRoute prompt or a reconstruction of it. The downloadable kit includes an editable version with deliverables and stop rules. For broader prompting choices—especially source priority and authority boundaries—see the GPT-6 Astra prompting guide.

Build a gray-box loop before adding art

Diagram showing game rules and visual design developing in parallel before joining for release
Rules and presentation can develop in parallel, but they come together around the same playable loop before release. Credit: Original diagram by Grow AI Skills. Open full-size image.

Our first real milestone was not “the garden looks finished.” It was “one complete attempt works with simple shapes.” The opening screen explained the goal. Enter started the game. A visible object could be collected. Touching the moth caused a loss. Returning with all seeds caused a win. The reset button restored the same positions and timer.

That thin slice is the most valuable moment to separate two kinds of work:

  • The rules track owns state, input, collision, timing, loading, reset, and test hooks.
  • The presentation track owns silhouette, palette, motion, sound, camera, asset provenance, and framing.

They are not isolated forever. A wider character changes collision feel; a heavy model changes start-up time; a brighter particle effect may hide an objective. But keeping the responsibilities visible lets you ask a precise question when something feels wrong. Is the rule unfair, the collision box inaccurate, the feedback weak, or the asset obscuring the playfield?

Resist generating ten levels while that answer is still unclear. Content multiplies whatever is already present, including confusion. If you are coding by feel and need a safer iteration routine, the vibe-coding safety guide covers small diffs, tests, and rollback habits.

Make the hardest moments easy to inspect

A screenshot is useful for layout and art, but weak at proving rules. Two glowing circles can overlap while their collision shapes remain far apart. A counter can display “3” even though an internal list still contains a seed. To see the actual game, Lantern Relay exposes a deliberately small state snapshot:

window.__LANTERN_RELAY__.getState()
// phase, collected count, remaining time,
// player and moth positions, active seed IDs,
// current preset scene, reduced-motion preference

We paired that read-only snapshot with four test-only preset scenes. baseline resets the world. near-win puts the player just outside the lantern with all seeds collected. collision overlaps the player and moth. timeout leaves eight milliseconds on the clock. The test can advance simulation time directly, so a timeout check does not spend 35 seconds waiting.

This technique does not prove that a game feels good. It answers narrower questions: did the intended transition happen, did it happen for the expected reason, and can another person reproduce it? OpenAI's Astra game-building case describes a much larger project using repeatable generation tests and browser automation while the author continued judging the experience. That division scales down surprisingly well.

Keep inspection code bounded. A versioned snapshot is less brittle than exposing every internal variable. Clearly mark mutation helpers as test-only, and remove or protect them if they reveal information or abilities you do not intend to ship.

What broke on our first test run

The surrounding test setup failed before it could give us a trustworthy result. Those failures were useful because they showed how easily a team can confuse a broken harness with a broken game—or ignore the harness until release day.

Observed failureCauseChange we kept
The Node test could not import Playwright even though the package was available through NODE_PATH.ES module resolution did not use that path the way our command assumed.The script now creates a CommonJS-compatible require inside the ES module and loads Playwright through it.
The console-health check failed before any game action.The browser requested /favicon.ico; the tiny local server returned 404.The page declares a small data-URL favicon, removing an irrelevant network error from the signal.
The release gate failed after we added a tenth browser check.It expected the old hard-coded total of nine.The gate now compares the exact required check names and then requires every one to pass.
Article QA initially called the second image broken.The image was lazy-loaded and the test inspected it before scrolling it into view.The page test scrolls to the image, waits for loading, and only then checks its natural dimensions.

None of these was a dramatic AI failure. That is precisely the point. Most production friction is ordinary: module resolution, a stray request, stale assumptions, or timing. A credible workflow records what was observed and fixes the smallest cause. It does not rewrite every failure as proof that the model is brilliant or useless.

Add art through a manifest, not by dragging files around

Once the loop survived, we treated every visual or audio file as a tracked input. The included manifest records path, purpose, origin, license, dimensions, and a performance note for each owned asset. “Generated by AI” is not a rights record, and “downloaded from the web” is not a source.

The PaperRoute article that inspired this guide describes a more ambitious Blender workflow: scripted generation, multiple rendered angles, checkpoints, and separate visual experiments. If you use that pattern, freeze the Blender version, keep the script beside the source file, export to a known path, fail on Python exceptions, and save a small review set. Front, side, rear, material, scale, and action views can reveal different mistakes before the asset reaches the game. Blender's command-line documentation also notes that background execution is available and that argument order matters.

Then inspect the asset inside the actual build. Check scale, axes, texture paths, names, collision proxies, file size, load time, and framing. A clean render only proves that the render succeeded. It does not prove that the asset reads well in motion or fits the performance budget.

Measure play, performance, and cost separately

These three questions are often collapsed into one vague claim that the build “worked.” Keep them separate.

  • Play: Can a person understand the goal, control the character, recover from failure, and want another attempt?
  • Performance: Do start-up, input response, frame pacing, memory, and network behavior meet a budget on representative devices?
  • Production cost: How much human attention, agent runtime, tool usage, and actual money did this version consume?

Lantern Relay's automated run covers state transitions, two layouts, and console health. It does not contain a physical-device frame-time study or accessibility conformance audit. Browser JavaScript can also look fine in a recording while a long main-thread task delays input; web.dev's long-task guidance explains why breaking up work can let interactions run sooner. Measure on the devices you promise to support.

Use the same care with project accounting. The PaperRoute devlog separates human-active intervals, agent runtime, token activity, and repriced API value, and warns that overlapping intervals are not wall-clock duration. That is a good reporting habit, but its numbers are not a forecast for your game. Concurrency, caching, scope, model routing, art quality, and the amount of human correction can change the result completely.

Package the build, publish it, then test the public URL

Download the AI Browser Game Build Ledger

The ZIP contains the complete Lantern Relay source, the project and agent briefs, stack decision note, six-milestone ledger, asset manifest, human checklist, browser test, two screenshots, machine-readable results, static-hosting checklist, and a Python verifier. Unpack it and start a web server from the kit's root:

python3 -m http.server 8773
# open http://127.0.0.1:8773/game/

With Node.js, Playwright, and Google Chrome available, run:

node test-game.mjs
python3 release-gate.py

Our September 13 run passed twelve named checks at 1440 × 900 and a simulated-touch 390 × 844 viewport, both with reduced motion. It exercised keyboard and on-screen touch movement, reset, three preset outcomes, layout, and console health. A real release still needs pointer, touch, sound, contrast, assistive-technology, and performance work on representative hardware. Canvas content in particular needs accessible HTML for essential controls and status.

For a static host, publish the directory containing the entry HTML and every referenced asset. Verify exact filename case and content types. Use HTTPS. If your engine uses threaded workers, confirm its cross-origin isolation requirements before launch; Godot's documentation, for example, specifies additional headers for threaded web exports. Audio, fullscreen, and pointer capture may also require a real player gesture.

Finally, open the exact public URL in a fresh session. Start a game, move, win or lose, restart, refresh, and inspect both the console and network panel. Repeat on the promised devices. A successful local build and an uploaded folder are two different events; the public smoke test is where you learn whether hosting changed the result.

This guide began with the public PaperRoute build article and its dated devlog, but the Lantern Relay code, prompt template, tests, diagrams, and workflow are original. The source headline says “GPT 5.6 Astra”; the current official OpenAI catalog names GPT-6 Astra, so we use the documented name without guessing at the mismatch. More importantly, we do not treat either project as a model benchmark. The durable lesson is smaller and more useful: give the agent a narrow loop, make the rules visible, test the awkward states, and keep human judgment in the release.