Building a Polished Match-3 with an AI — Step by Step, Under Contract

A match-3 puzzle is deceptively deep: a swap engine, run detection, gravity, refills, cascades, combo scoring, juice, levels, and screens. Exactly the kind of thing that goes off the rails when you “one-shot prompt” an AI. So I built one the disciplined way: I had Claude Opus 4.8 write it across 5 governed batches, each bound by a contract it could not exceed, each validated before it could land.

This is the full tutorial — every step, every command. Then you can play it.

🎮 Play it first

Play Match-3 Under Contract — one self-contained HTML file, mobile + desktop. Swap adjacent gems (tap-tap or swipe) to line up 3+, chain cascades for combos, hit the target before you run out of moves.

Match-3 — hero

Here’s the real thing running (a headless-browser capture): distinct colour-and-shape gems, a live HUD, and an x2 COMBO mid-cascade.

Neon Match-3 gameplay

Source + the contract that governed it: github.com/ruslanmv/match-3-under-contract.

The two tools

  • Matrix Builder (mb) — turns an idea into a contract: a locked blueprint, pinned standards, an allow-list of exactly which files may change, and acceptance criteria. It also validates the result.
  • GitPilot — the coder. Pointed at Claude Opus 4.8, it writes the game, bound by each batch’s contract.

Step 0 — Install and point GitPilot at Claude

pip install agent-generator gitcopilot crewai

export GITPILOT_PROVIDER=claude
export GITPILOT_CLAUDE_MODEL=claude-opus-4-8
export ANTHROPIC_API_KEY=sk-ant-…

Step 1 — One sentence becomes a contract

mb init "A polished neon Match-3 (Bejeweled-style) gem-swap puzzle, single self-contained HTML file, mobile + desktop" \
        --quality standard --title "Match-3 Under Contract"

Steps 2–6 — Five governed batches

Each batch runs the same four commands — plan a scoped batch, render the contract-bound prompt, let Claude extend the single allowed file, validate fail-closed:

mb next "<the batch goal>"                 # plan a scoped batch (allow-list: frontend/index.html)
mb prompt --coder gitpilot                 # render the contract-bound prompt
gitpilot generate -m "$(cat coder-prompts/gitpilot.md)" -o .
mb check frontend/index.html               # approved / needs-repair / rejected

Here is exactly what each batch asked Claude to add, the resulting size, and the immutable Matrix Commit:

Batch 1 — Foundation

8×8 board, 7 gems that differ by colour and shape (colourblind-friendly), canvas render loop, a board generated with no pre-existing matches, neon styling. → 12 KB · mc-8200e9006db3 · approved

Batch 2 — Swap + match detection

Tap-to-select and swipe-to-swap adjacent gems; detect horizontal/vertical runs of 3+; a swap only sticks if it creates a match (otherwise it animates back). → 24 KB · mc-eb05dc6d6f40 · approved

Batch 3 — Clear, gravity, cascades, scoring

Remove matches, drop gems with gravity, refill from the top, then re-scan and repeat — cascade chains — with combo multipliers and 4/5-match bonuses. Reshuffle if no moves remain. → 30 KB · mc-c6326ada66b2 · approved

Batch 4 — Juice

Tween swap + falling animations, particle bursts in gem colours, screen-shake on big cascades, floating combo popups, WebAudio SFX (with a mute toggle), and a fully responsive, DPR-aware canvas with refined touch. → 41 KB · mc-ae0fc4388e80 · approved

Batch 5 — Meta + polish

Levels with a target score and limited moves, start / level-complete / game-over screens, high score in localStorage, accessibility, and the footer credit “coded by GitPilot — under a Matrix Builder contract.” → 56 KB · mc-721814e1b8c7 · approved

$ mb timeline
Match-3 Under Contract  v1.0.0
  Batch 01  Foundation                                  ✓ mc-8200e9006db3
  Batch 02  Swap and match detection                    ✓ mc-eb05dc6d6f40
  Batch 03  Clear, gravity, cascades, scoring           ✓ mc-c6326ada66b2
  Batch 04  Juice: animations, particles, sound, mobile ✓ mc-ae0fc4388e80
  Batch 05  Levels, moves, screens, high score, polish  ✓ mc-721814e1b8c7

Across all five batches, Claude wrote to only frontend/index.html — never a stray file. Every batch returned MATRIX_STATUS: approved score=100. If the model had written outside the allow-list, mb check returns needs-repair (exit 1) or rejected (exit 2) and the change is blocked.

Step 7 — Verify it actually runs

node --check on each batch wasn’t enough, so I ran the finished game in a real headless Chromium — started a level, swapped gems, triggered a cascade:

RUNTIME JS ERRORS: NONE ✓

The screenshot above is that run. Full transcript in EVIDENCE.md.

How it works — and why Matrix Builder

How it works: Matrix Builder × GitPilot × Claude, and the advantages of mb

The shift is from prompting to engineering:

  • A contract, not a prompt — a locked blueprint and pinned standards.
  • Allow-list scope — the AI edits only the files you permit.
  • Fail-closed validationmb check returns approved / needs-repair / rejected (exit 0/1/2), so it gates CI.
  • Immutable Matrix Commits — every accepted change pins the prompt, diff, and verdict.
  • Standards baked in — NIST SSDF, OWASP Top 10 & LLM Top 10, SLSA.
  • Provider-agnostic — Claude here, but OpenAI, Watsonx, or local Ollama work the same.

Five batches, one file, zero out-of-scope edits — and a genuinely fun puzzle that runs on a page, on your phone or desktop.

Reproduce it

pip install agent-generator gitcopilot crewai
export GITPILOT_PROVIDER=claude GITPILOT_CLAUDE_MODEL=claude-opus-4-8 ANTHROPIC_API_KEY=sk-ant-…
mb init "a neon Match-3 puzzle" --quality standard
# then, per batch:
mb next "the next feature" && mb prompt --coder gitpilot
gitpilot generate -m "$(cat coder-prompts/gitpilot.md)" -o .
mb check frontend/index.html

Take it for a spin

Five scoped batches, one file, and no out-of-scope edits — the same governed workflow that sits behind Matrix Builder and GitPilot. The game is simply the most enjoyable way to watch it work.

Leave a comment