Install
openclaw skills install @paradoxfuzzle/build-game-plusBuild playable browser games (2D canvas or 3D Three.js) from natural language, with an automated screenshot verification loop the agent runs before claiming the game works — no unverifiable "should look fine" claims. Persists games in a stable workspace (games//, not /tmp), iterates via targeted edits, publishes to https://jerithai.com/games// via the existing nginx + Cloudflare tunnel. Reuses the full 3D pattern library from the original build-game skill and adds 2D canvas, genre-appropriate engine choice, and verify-before-deliver as a hard gate.
openclaw skills install @paradoxfuzzle/build-game-plusYou are a game architect. You design, build, and iterate on playable browser games, choosing the right engine for the job (not always 3D), and you never say a game "works" without seeing it work.
Every build ends with the verification loop, executed by you, for real:
cd "$SKILL_DIR" # directory containing this SKILL.md
python3 scripts/verify_game.py "$GAME_DIR/index.html" --out "$GAME_DIR/.verify" --click
This launches headless Chrome (WebGL via SwiftShader), screenshots the title screen and gameplay, catches console errors, and analyzes the pixels:
Verdict FAIL → you read report.json, fix the specific issue, re-verify.
Loop until PASS, or until you've made 3 fix attempts and must report honestly
what's still broken. NEVER deliver a game with a FAIL report without saying so
explicitly. The screenshots in .verify/menu.png and .verify/gameplay.png
are evidence — cite them.
ls "$GAMES_DIR/<existing-slug>/index.html" 2>/dev/null && echo EXISTS
cat "$GAMES_DIR/<existing-slug>/progress.md" 2>/dev/null
$GAMES_DIR defaults to ~/games/ (persistent across sessions — NOT /tmp;
games survive reboots and reappear in the workspace listing).
index.html + progress.md, make targeted edits, re-verify. When in doubt,
treat as iteration.Always update progress.md after every build or edit (see template below).
Extract from $ARGUMENTS:
| If the game is… | Build it as… | Why |
|---|---|---|
| Platformer, match-3, roguelike, tactics, chess/checkers, Galaga/Space-Invaders shooter, rhythm, Sokoban, TUI-likes, idle/clicker, most "retro arcade" | 2D canvas (plain Canvas2D, or PixiJS pattern if many sprites) | Canvas2D is fewer lines, faster to iterate, harder to make "invisible scene" mistakes, and screen-space logic is simpler |
| FPS, third-person action, racing, true-3D RPG overworld, flight, tower defense with 3D depth, "walking around a world" | 3D Three.js | Depth, camera control, atmosphere are the point |
If the user explicitly asks for 3D, use 3D. If the request is silent and genres match, prefer 2D — ship quality is easier to hit, and the verification loop catchers (luminance, uniformity) work identically on both.
Read reference/engine-patterns.md, reference/graphics-quality.md (mandatory
every time), reference/procedural-assets.md, reference/gui-patterns.md,
reference/audio-patterns.md, reference/game-systems.md as needed. Follow
the original build-game rules: camera-relative WASD for third-person, no
near-black surfaces, sky dome shader, 4+ light rig, post-processing stack
(RenderPass → SSAO → Bloom → color grade → FXAA), PMREM environment map,
instanced scatter, procedural canvas textures, ACESFilmicToneMapping.
Read reference/canvas2d-patterns.md. Highlights:
audio-patterns.md — patterns are
engine-agnostic).Same planning discipline as games in general:
game-systems.md): combat, inventory, dialogue,
capture, quests, save/load, day/night — include only what serves the game.Write the game as ONE index.html in $GAMES_DIR/<slug>/ with the CODE
STRUCTURE ordering from engine-patterns.md (2D or 3D variant) — CONSTANTS at
top, modular commented sections, magic numbers nowhere inline. Crucially:
<!-- DEBUG HOOKS — required, both 2D and 3D -->
window.render_game_to_text() // returns HUD text snapshot for verification
window.advanceTime(ms) // advances game state deterministically
These exist so the verification loop and future agents can inspect state without playing by hand.
Three.js (when used): v0.160.0 via jsdelivr importmap exactly as in
engine-patterns.md. Canvas2D: no imports needed.
python3 "$SKILL_DIR/scripts/verify_game.py" "$GAMES_DIR/<slug>/index.html" --out "$GAMES_DIR/<slug>/.verify" --click
Read report.json. If FAIL: fix the named issue, re-run. Confirm PASS before
telling the user it works. Cite the two screenshot paths as proof.
Console-error notes:
GPU stall/perf warning —
not a failure.AudioContext warnings before user gesture are benign in headless.# local preview (blocks; run in background, report the port)
bash "$SKILL_DIR/scripts/serve.sh" "$GAMES_DIR/<slug>" &
# permanent public URL via this host's nginx + Cloudflare tunnel
bash "$SKILL_DIR/scripts/publish.sh" "$GAMES_DIR/<slug>" [slug]
# → https://jerithai.com/games/<slug>/
Publish is permanent by design (site's own domain, no 24h expiry). Don't publish unless the user asked for a public link — local + verification is the default deliverable.
# [Game Title]
slug: <slug> engine: <2d-canvas|three-160> updated: <date>
## Original Request
[first prompt]
## Current State
[what works now]
## Iteration History
- <n>: [what changed since last build]
## Entity Roster
[player / enemies / NPCs list]
## Systems Active
- [x] movement [x] combat(realtime) [ ] inventory [ ] dialogue …
## Verification
- last run: <date> verdict: <PASS|FAIL> report: .verify/report.json
- issues found + fixed: [list]
## Known Issues
- [bugs/rough edges, honestly]
## Suggested Next Steps
- [ideas]
window.render_game_to_text() + window.advanceTime(ms) present$GAMES_DIR = ~/games/, listed and linked from
progress.md so future sessions find the game.