| name | cube_asset-builder |
| description | Stage 3 component of the WowCube pipeline, invoked by cube_orchestrator — not a standalone user entry point. Use only when the orchestrator routes to asset generation because the manifest exists but packed assets and _ids.h do not. Generates AI sprite PNGs (from each sprite's gen_prompt) and synthesised WAV sounds, pauses for user review, then packs them into `assets/packed/`, `assets/wav/`, and `src/app_<game>_ids.h`. |
WowCube Asset Builder
This skill is Stage 3 of the cube_orchestrator pipeline. The orchestrator invokes it (via the Skill tool) when the asset manifest exists but assets/packed/ / src/app_<game>_ids.h do not. It is not a user-facing entry point — the user enters through cube_orchestrator, which routes here.
Drive the asset pipeline from a structured manifest. This skill never writes
game code and never creates prompts — it exists solely to turn a validated
<game>_assets.json into a runnable set of packed sprites and sound files that
cube_orchestrator's coder agents can reference. The packed assets are the
Stage 3 artifact; cube_orchestrator checkpoints them with the user and then
runs Stage 4 (implementation).
Sprites are generated by AI: each sprite's gen_prompt (written by
technical_prompter, Step 4a) is sent to the OpenRouter image model via
scripts/genimg.py, then resized to the manifest's exact size. Sounds are
deterministic synthesised placeholders written as mono PCM16 WAV (no
external encoder). AI sprite output is not reproducible across runs; sounds
are byte-identical across runs.
Core principle: every asset name that appears in a prompt must exist as a
file after this skill runs. The manifest is the contract. No placeholder text
like "requires asset: X" is ever produced here; either the asset is in the
manifest and gets generated, or the user is asked to fix the manifest. Every
sprite MUST carry a non-empty gen_prompt — generation fails loudly otherwise.
When to Use
cube_orchestrator routed here because the manifest exists but assets/packed/
or src/app_<game>_ids.h is missing.
- Resuming a partially-completed asset build after a user requested regeneration.
Do not trigger this skill directly for "generate assets" / "build assets"
requests — those are owned by cube_orchestrator, which routes here as Stage 3.
When NOT to Use
- No manifest exists → the orchestrator will route to Stage 2 (
technical_prompter).
- No GDD exists → the orchestrator will route to Stage 1 (
cube_game-designer).
- The user wants to modify game code → this skill does not touch
src/app_<game>.h.
Prerequisites
| File | Source | Required |
|---|
plans/<game>/<game>_assets.json OR plans/<game>_assets.json | technical_prompter | Yes |
A non-empty gen_prompt on every sprite in the manifest | technical_prompter (Step 4a) | Yes |
build_psd.py (at repo root, its scripts/, or next to scripts/) | Project | Yes |
pack.py (at repo root, its scripts/, or next to scripts/) | Project | Yes |
Pillow, numpy, requests, pytoshop, psd-tools | pip install | Yes |
OPENROUTER_API_KEY environment variable | User (OpenRouter account) | Yes (generate stage) |
If any prerequisite is missing, print the gap and stop. Do not attempt to
generate partial output. The AI sprite generation needs network access and a
valid OPENROUTER_API_KEY; the key is read from the environment and never
hardcoded.
Workflow
Step 1: Locate the manifest
Look in this order:
plans/<game>/<game>_assets.json
plans/<game>_assets.json
If neither exists, stop and return control to cube_orchestrator — the manifest is a Stage 2 output, so the orchestrator will route to Stage 2 (technical_prompter) to produce it.
Step 2: Run the generate stage
Invoke the pipeline driver:
python OCT_wowcube-agent-skills/scripts/build_pipeline.py \
generate --manifest <manifest-path> --workspace assets
The generate stage AI-generates a PNG for every sprite (from its gen_prompt,
resized to the manifest size) into assets/art/, and synthesises a WAV for
every sound into assets/wav/.
Exit codes:
0 — success.
2 — manifest invalid (errors printed to stderr; relay verbatim to user).
3 — missing dependency (Pillow / numpy / requests / pytoshop / psd-tools) or
missing OPENROUTER_API_KEY (message names which).
6 — sprite generation failed (OpenRouter/network error, or a sprite has no
gen_prompt); relay stderr to the user.
- other — unexpected; surface stderr to user.
On success, the driver prints a summary: PNG count, WAV count, group names.
Step 3: User checkpoint — MANDATORY
STOP. Do NOT proceed to the pack stage. Print the summary and wait for
user input. Offer these options verbatim:
Generated assets are in assets/art/*.png and assets/wav/*.wav.
Review visually and by ear, then reply:
ok or continue — pack and hand off to orchestrator.
regen <group> — regenerate a single group (others untouched). For
sprites this re-runs AI generation, so the art will differ from the
previous attempt even with the same prompt.
swap <name> — drop a PNG or WAV into assets/art/ or assets/wav/
with that name, then reply ok.
edit <name> prompt <text> — edit the sprite's gen_prompt in the
manifest, then I'll regenerate that sprite.
edit <name> size <WxH> — edit the manifest, then I'll regenerate
that sprite.
Wait for an explicit reply. Never auto-continue.
For regen <group> — re-run the generate command with --group <name>.
For edit <name> size <WxH> or edit <name> prompt <text>:
- Load the manifest JSON, find the entry, update
size (or gen_prompt).
- Save the manifest.
- Run
build_pipeline.py generate --manifest <manifest> --workspace assets --group <group> (where <group> is the sprite's group or derived group).
- Return to Step 3.
Step 4: Run the pack stage
After the user replies ok:
python OCT_wowcube-agent-skills/scripts/build_pipeline.py \
pack --game <game> --workspace assets --src-dir src
On success the driver prints:
- Path to
assets/packed/pal.png and the packed PNGs.
- Count of
assets/packed/*.raw — the decoded-RGBA asset bitmaps the simulator
and the cube .oct load (emitted by pack.py --emit-raw; pure Python, no
utils.exe/psd.exe).
- Path to
src/app_<game>_ids.h with the BMP_* constant count.
Step 5: Hand-off
Print:
Asset build complete.
src/app_<game>_ids.h ready with N BMP_* constants.
assets/packed/*.png + pal.png ready.
assets/packed/*.raw ready (decoded-RGBA assets for the sim / .oct).
assets/wav/*.wav ready.
Then return control to cube_orchestrator. Do NOT start implementation
yourself. The orchestrator will run the Stage 3→4 boundary checkpoint with the
user and begin the implementation workflow (coder/verifier/fixer subagents) when
approved.
Constraints
- Sprites are AI-generated, sounds are deterministic. Sprite PNGs come from
the OpenRouter image model (
scripts/genimg.py) and differ run-to-run; sound
WAVs are pure synthesis and byte-identical across runs. Either way the user
must approve before packing. Never silently replace a file the user provided
by hand unless they explicitly said regen.
- Per-sprite
gen_prompt is the source of the art. technical_prompter
(Step 4a) writes a ready-to-run image-generation prompt into every sprite
entry; the generate stage sends it to genimg.py and resizes the result to
the manifest size. A sprite with no gen_prompt aborts generation (rc=6)
— do not invent one here; send the user back to technical_prompter. Sounds
have no gen_prompt.
OPENROUTER_API_KEY is read from the environment, never hardcoded. If it
is unset the generate stage stops at the dependency check (rc=3). Tell the
user to export OPENROUTER_API_KEY=sk-or-... and retry.
- Never edit
_ids.h by hand. It is produced by pack.py.
- Never edit
src/app_<game>.h. That is cube_orchestrator's territory.
- Never invent asset names. Every sprite/sound name comes from the
manifest. If a required asset is missing, stop and ask the user to add
it to the manifest (and run
technical_prompter again if appropriate).
- 2-second sound cap and mono PCM16 WAV are enforced by the generator.
Do not tell the user to set different values — the validator will reject
out-of-range manifests.
Error Handling
| Symptom | Action |
|---|
Manifest invalid (rc=2) | Relay all stderr lines to the user; wait for them to fix the manifest (or delegate back to technical_prompter). |
Missing dependency or API key (rc=3) | Print the install hints / export OPENROUTER_API_KEY=... hint printed by the driver; stop. |
Sprite generation failed (rc=6) | Relay stderr. If it is a network/OpenRouter error, retry (optionally --group for just the failed group). If it names a sprite with no gen_prompt, send the user back to technical_prompter to add it. |
build_psd.py failure during pack | Show the failing filename from stderr. Ask the user to inspect assets/art/<name>.png. |
pack.py palette overflow | Suggest --target-colors 64; the driver currently uses default grouped palette — add the flag if this becomes common. |
Empty _ids.h after pack | Likely build_psd.py produced an empty PSD. Diagnose by listing assets/exported/ contents. |