diff --git a/.claude/skills/pixellab/SKILL.md b/.claude/skills/pixellab/SKILL.md index 0d7cc78..f0b7089 100644 --- a/.claude/skills/pixellab/SKILL.md +++ b/.claude/skills/pixellab/SKILL.md @@ -1,89 +1,24 @@ --- name: pixellab -description: Generate pixel art for Supervillain via the Pixel Lab API — sprites, tiles, animations. Use when adding or regenerating game art assets, or when the user asks for new sprites/tiles/graphics. +description: Generate pixel art for Misaligned via the Pixel Lab API — sprites, tiles, animations. Use when adding or regenerating game art assets, or when the user asks for new sprites/tiles/graphics. --- -# Pixel Lab art pipeline +# Pixel Lab art pipeline (skill shim) -Pixel Lab (https://api.pixellab.ai/v1) generates the game's pixel art. +The canonical documentation lives in `knowledge/art-pipeline.md` — read that +first. Quick reference: -## Auth +- Auth: `PIXELLAB_API_KEY` in `~/.zshrc` (`source ~/.zshrc` in harness + shells). Credit-based; `/balance` showing `{"usd": 0.0}` does not mean + generation is blocked. +- Generate (idempotent batch, skips existing PNGs): -The API key is exported as `PIXELLAB_API_KEY` in `~/.zshrc`. Shells launched by -the harness may not have it loaded — `source ~/.zshrc` first, or read the env var. -Check remaining credit with: + ```bash + python3 tools/pixellab/generate.py --batch assets/pixellab/manifest.json + ``` -```bash -curl -s https://api.pixellab.ai/v1/balance -H "Authorization: Bearer $PIXELLAB_API_KEY" -``` - -Note: a `{"usd": 0.0}` balance does NOT mean generation fails — the account is -generation-credit based. Just try a small generation. - -## Generating assets - -Use the helper script (stdlib-only Python, no venv needed): - -```bash -# Whole starter pack — idempotent, skips files that already exist: -python3 .claude/skills/pixellab/scripts/generate.py --batch assets/pixellab/manifest.json - -# One-off: -python3 .claude/skills/pixellab/scripts/generate.py \ - "a gold vault tile" assets/pixellab/tiles/vault.png --size 16 --view "high top-down" -``` - -To regenerate an asset, delete the PNG and re-run the batch (or run a one-off). -To add assets, add entries to `assets/pixellab/manifest.json` and re-run. - -## Conventions (keep these or the art clashes) - -- **Size:** 32x32 for everything. The OpenAPI schema claims a 16px minimum, but - the API rejects transparent (`no_background`) generations below 32x32 with - "Canvas must be size 32x32 area or larger" — so 32 is the real floor. The Bevy - frontend's `TILE_SIZE` is 16 world units; render 32px art scaled to fit. - Pixflux maximum is 400px. -- **Style suffix:** every prompt gets the shared style from the manifest - `defaults.style` ("dark evil lair theme, muted palette with purple and teal - accents..."). Change it in one place only. -- **Terrain tiles are the exception:** the shared suffix's "readable - silhouette" makes the model put a focal object in every tile, which tiles - into visual noise. Terrain entries (floor/wall/rock) override `style` - per-item with a texture-swatch suffix ("...very low contrast, no focal - point, no objects, uniform"), describe content as "seamless tileable - texture of ...", and carry their own seed. Copy that pattern for any future - ground/wall-class tile. -- **Seed:** fixed at 1337 in the manifest for coherence across the set - (except terrain, above). -- **Characters:** `"transparent": true`, `"view": "low top-down"`, `"direction": "south"`. - Stored in `assets/pixellab/sprites/`. -- **Tiles:** opaque, `"view": "high top-down"`. Stored in `assets/pixellab/tiles/`. - -## API surface (pixflux is the main one) - -- `POST /generate-image-pixflux` — text to pixel art. Body: `description`, - `image_size {width,height}`, optional `no_background`, `view` - (`side | low top-down | high top-down`), `direction` (8 compass points), - `seed`, `color_image` (forced palette), `init_image`. -- `POST /generate-image-bitforge` — style-matched generation from a reference - image (use when matching an existing asset's exact style; max 200px). -- `POST /rotate` — generate other facing directions from one sprite. -- `POST /animate-with-text` / `animate-with-skeleton` — animation frames (64px only - for text mode). -- `POST /inpaint` — edit a region of an existing sprite. -- Response: `{"image": {"base64": ...}, "usage": ...}` — decode base64 to PNG. - -Generation takes ~5-20s per image; the batch script retries on 429/5xx. - -## Where art goes - -- `assets/pixellab/manifest.json` — the manifest (source of truth for the set) -- `assets/pixellab/sprites/*.png` — characters (transparent) -- `assets/pixellab/tiles/*.png` — terrain/furniture (opaque) -- Generated PNGs are committed to git (they are small and regeneration costs credits). - -The Bevy frontend (`src/bin/bevy.rs`) loads these via an `Art` resource: -textured tiles fall back to flat colors for tile types without art, and a few -types reuse a base texture with a tint (security doors = tinted `door.png`, -trap variants = tinted `trap_spike.png`). When you generate a dedicated -texture for one of those, add it to the manifest and update `Art::load`. +- One-off: `python3 tools/pixellab/generate.py "description" out.png --size 32 + --view "high top-down"` (add `--transparent` for characters). +- Conventions (32x32, style suffixes, the terrain texture-swatch exception, + seeds, art direction) are in `knowledge/art-pipeline.md`. The manifest + (`assets/pixellab/manifest.json`) is the source of truth for the asset set. diff --git a/knowledge/art-pipeline.md b/knowledge/art-pipeline.md index db56abf..0fde53d 100644 --- a/knowledge/art-pipeline.md +++ b/knowledge/art-pipeline.md @@ -1,9 +1,24 @@ # Art pipeline -The generation workflow lives in the **pixellab skill** -(`.claude/skills/pixellab/SKILL.md`) — auth, endpoints, script usage, -conventions. This file covers what matters beyond generating: state and -integration. +Canonical doc for generating and integrating pixel art. The generator script +is `tools/pixellab/generate.py` (stdlib-only Python; single-image or +idempotent batch mode — it skips PNGs that already exist). + +```bash +# Whole set (only missing entries generate): +python3 tools/pixellab/generate.py --batch assets/pixellab/manifest.json + +# One-off: +python3 tools/pixellab/generate.py "a server rack" out.png --size 32 \ + --view "high top-down" # add --transparent for characters +``` + +API surface (https://api.pixellab.ai/v1, Bearer auth): `generate-image-pixflux` +is the workhorse (description + image_size, optional no_background / view / +direction / seed / color_image); `generate-image-bitforge` does style-matched +generation from a reference image; `rotate`, `animate-with-text` (64px only), +`animate-with-skeleton`, `inpaint` exist for later. Responses are +`{"image": {"base64": ...}}` PNG, ~5-20s each; the script retries on 429/5xx. ## Facts @@ -84,7 +99,7 @@ tile calls for it. ## Adding an asset, end to end 1. Add an entry to `assets/pixellab/manifest.json`. -2. `python3 .claude/skills/pixellab/scripts/generate.py --batch assets/pixellab/manifest.json` +2. `python3 tools/pixellab/generate.py --batch assets/pixellab/manifest.json` (idempotent; only the new entry generates). 3. Map it in `Art::load` (replace a tint-reuse or color fallback). 4. Commit the PNG — regeneration costs credits and a different result. diff --git a/.claude/skills/pixellab/scripts/generate.py b/tools/pixellab/generate.py similarity index 100% rename from .claude/skills/pixellab/scripts/generate.py rename to tools/pixellab/generate.py