# Gameforge

> Orchestrator skill that turns a one-line description into a runnable Phaser 3 game. Coordinates eight sub-skills (game-designer, world-architect, sprite-artist, tile-artist, bg-artist, codesmith, playtester, refiner) into a deterministic-where-possible, LLM-where-necessary pipeline. Image generation uses GPT Image 2 (gpt-image-2) at low quality by default. Use when the user wants to generate, refine, or test a 2D HTML5 game from natural language.

- Skill: `ar9av/gameforge` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add ar9av/gameforge`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ar9av/gameforge/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: Ar9av (https://skillmd.com/u/ar9av)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ar9av/gameforge

---


# Gameforge — Game Generation Orchestrator

Drives the full game-creation pipeline. The host agent (you) is the one calling LLM-bearing sub-skills; this skill describes the pipeline shape, the shared state file, validation gates, and halt conditions. All image generation goes through **GPT Image 2** (`gpt-image-2`) at `quality: low` by default.

## When to use

- "Make me a game where …"
- "Generate a Phaser game called …"
- "Refine the QA failures from the last run"
- Any request involving an 8-bit / pixel-art / 2D HTML5 game described in natural language

## Pipeline

```
description
    ↓
game-designer  →  GDD + style.palette + levelHints
    ↓
world-architect  →  levels.json
    ↓
┌──────────────┬──────────────┬──────────────┬──────────────┐
sprite-artist   tile-artist    bg-artist      audio-composer  ← parallel
└──────────────┴──────────────┴──────────────┴──────────────┘
    ↓
palette-enforcer  ← quantize all PNGs to chosen 8-bit palette
    ↓
codesmith  →  src/scenes/Game.js  (imports AudioManager when state.audio is set)
    ↓
manifest-auditor   →  catches anim/texture key mismatches (fast, no browser)
mobile-compat-checker --fix  →  auto-patches roundPixels + image-rendering CSS
    ↓
parallel-qa-orchestra  →  4 workers concurrently:
  ├── static (BFS reachability, border, jump arcs)
  ├── golden-path (boot, walk, jump, attack, win scenarios)
  ├── fuzzer (stuck, spawn-trap, no-progress, NaN)
  └── physics-debug (hitbox alignment)
    ↓
VLM intent gate  ← host agent reviews screenshot vs original description
    ↓ pass
  Ship  ←— refiner (loop, max 3) ←— fail
```

1. **game-designer** turns prompt → GDD JSON (includes `style.palette` auto-selection by genre).
2. **world-architect** turns GDD → `levels.json` (tile-based level layouts).
3. **sprite-artist** turns GDD entities → sprite sheets + manifest. Uses **GPT Image 2** (`gpt-image-2`) by default at `quality: low`.
4. **tile-artist** turns GDD tile palette → `tiles.png` + tile metadata.
5. **bg-artist** generates a parallax background image. Optional — skipped for top-down-adventure, abstract puzzle.
6. **audio-composer** generates `sfx.json`, `music.json`, and `AudioManager.js` from genre presets. Runs in parallel with art stages 3–5.
7. **palette-enforcer** quantizes all generated PNGs to a named 8-bit palette (e.g. pico8, sweetie-16, endesga-32) for visual coherence.
8. **codesmith** turns GDD + levels + manifest → `src/scenes/Game.js`. Imports `AudioManager` and calls `AudioManager.init(this)` in `create()` when `state.audio` is set.
9. **manifest-auditor** cross-references every animation/texture key in Game.js against manifest.json. Feeds mismatches to refiner before any browser is opened.
10. **mobile-compat-checker** (with `--fix`) auto-patches `roundPixels: true` and `image-rendering: pixelated` CSS; flags touch-input and audio-unlock gaps for refiner.
11. **parallel-qa-orchestra** replaces the serial playtester→gap-checker chain. Runs 4 workers concurrently; merges into one failure list for the refiner.
12. **refiner** consumes failures + current source → patched files. Loop back to parallel-qa-orchestra. Cap at 3 iterations.

Stages 3, 4, 5, 6 can run in parallel (independent inputs). Stage 7 is a fan-in (all art must be done first). Stages 9 and 10 are fast linting passes (no browser).

## Shared state — `game-state.json`

Single source of truth at the project root. Every sub-skill reads/writes it. Schema:

```jsonc
{
  "version": 1,
  "name": "<project-name>",
  "prompt": "<original user description>",
  "genre": "top-down-adventure | platformer | shoot-em-up | puzzle | dungeon-crawler | top-down-rpg",
  "createdAt": "<ISO timestamp>",
  "gdd":     <output from game-designer or null>,
  "levels":  [<output from world-architect>],
  "assets": {
    "sprites": [<manifest entries from sprite-artist>],
    "tiles":   <manifest from tile-artist or null>
  },
  "code":  { "entryPoint": "src/main.js", "scenes": ["Boot","Preload","Game"] },
  "qa":    [<last 5 reports from playtester>]
}
```

Validate with `scripts/validate_state.mjs <project-dir>` after every mutation. Reject any change that breaks the schema.

## Project layout (per generated game)

```
<project>/
├── game-state.json           # shared state
├── package.json              # phaser + vite
├── vite.config.mjs
├── index.html
├── public/
│   ├── assets/
│   │   ├── entities.png      # from sprite-artist (one or more)
│   │   ├── tiles.png         # from tile-artist
│   │   └── manifest.json     # row/col labels per sheet
│   └── data/
│       └── levels.json       # from world-architect
└── src/
    ├── main.js               # Phaser bootstrap (template, never edit)
    ├── config.js             # game config: pixelArt, FIT, RND seed
    └── scenes/
        ├── Boot.js           # template, never edit
        ├── Preload.js        # builds anims from manifest, never edit
        └── Game.js           # codesmith-written
```

`Boot.js` and `Preload.js` are **fixed across every game** — they read manifest.json, build animations as `<ENTITY_ID>-<state>` (lowercased state), and stash levels + manifest on `this.registry`. Codesmith's Game.js consumes by name only.

## Animation key convention

Every animation is `<ENTITY_ID>-<state-lowercase>`, e.g. `KNIGHT-walk`, `SLIME-hurt`, `BULLET-idle`. Frame index = `row * cols + col`, where row is the entity's index in the sheet's `rows[]` and col is the state's index in the sheet's `cols[]`. Codesmith MUST look these up via the manifest, never hard-code.

## Workflow when invoked

### Path A — fresh project from a description

1. Ask user for project name (or accept arg). Run `scripts/init_project.mjs <name>` to scaffold.
2. Invoke **game-designer** with the user's description. Save GDD into `game-state.json`. Validate.
3. Invoke **world-architect** with the GDD. Save levels. Validate.
4. In parallel:
   - Invoke **sprite-artist** (default: GPT Image 2 at `quality: low`; `--placeholder` for free iteration).
   - Invoke **tile-artist** (`generateTilesetGPT()` via `src/lib/sprites.js` — one GPT Image 2 call per tile type, 512×512 → 32×32; auto-falls back to solid-color if no FAL_KEY).
   - Invoke **bg-artist** (`generate_bg.mjs --theme <theme>`). Skip when genre is top-down-adventure or abstract puzzle.
5. Write `public/assets/manifest.json` and `public/data/levels.json` from state (the asset skills merge into the manifest as they go).
6. Invoke **codesmith** with GDD + levels + manifest. Writes `src/scenes/Game.js` (and optional helpers under `src/`). Codesmith reads `manifest.bg` and adds the parallax-background pattern when present.
7. Invoke **playtester**. If failures, invoke **refiner**. Loop max 3.
8. Report final status: passed / failed / partial. If passed, tell user to `cd <project> && npm run dev`.

### Refine an existing project

1. Read `game-state.json` and the latest QA report (`qa/qa-report.json`).
2. If `passed === true`, stop.
3. Invoke **refiner** with failures + current source files. Apply edits.
4. Invoke **playtester**. Loop until passed or 3 iterations.

## Halt conditions

- **Schema validation failure** at any stage → halt, surface to user with the validation error. Do not loop.
- **3 refiner iterations without pass** → halt, surface failures. Do not silently mark complete.
- **`FAL_KEY` and `OPENAI_API_KEY` both missing** when an asset skill wants GPT Image 2 → fall back to procedural sprites/tiles and skip bg-artist.
- **User cancels** (SIGINT) → exit 130.

## Optional: multiplayer

Add multiplayer to any generated game via the **multiplayer** skill:

```bash
# After game is generated and running:
node skills/multiplayer/scripts/init_server.mjs <project-dir>   # Colyseus WebSocket server
node skills/multiplayer/scripts/patch_game.mjs <project-dir>    # patches Game.js for network sync

# Optional extras:
node skills/multiplayer/scripts/init_server.mjs <project-dir> --voice   # PeerJS voice/video
node skills/multiplayer/scripts/init_server.mjs <project-dir> --lobby   # React lobby frontend
```

Supports up to 4 players, 20 Hz tick rate, TypeScript shared schemas. See `skills/multiplayer/SKILL.md`.

## References

- `references/pipeline.md` — detailed stage interfaces and data flow
- `references/state-schema.md` — full JSON schema with examples
- `references/phaser-cookbook.md` — Phaser 3 patterns the codesmith MUST follow

## Scripts

- `scripts/init_project.mjs <name> [--dir path]` — scaffold from `templates/phaser-game/`
- `scripts/validate_state.mjs <project-dir>` — schema check + invariant verification
- `scripts/run_pipeline.mjs <project-dir>` — invoke the full pipeline (host agent drives all LLM sub-skills; no separate API key needed)

