diff --git a/.project/objectives/README.md b/.project/objectives/README.md index 1e0f68ff..f7233b49 100644 --- a/.project/objectives/README.md +++ b/.project/objectives/README.md @@ -106,17 +106,17 @@ | [p2-10](p2-10-regression-ci-gate.md) | 🟑 partial | Automated regression CI gate on every push to main | [testwright](../team-leads/testwright.md) | 2026-04-17 | | [p2-11](p2-11-version-about-screen.md) | βœ… done | Version string + About screen | [shipwright](../team-leads/shipwright.md) | 2026-04-17 | | [p2-16](p2-16-audio-assets.md) | ❌ missing | Audio assets β€” SFX + music .ogg files shipped | [asset-audio](../team-leads/asset-audio.md) | 2026-04-17 | -| [p2-17](p2-17-sprite-assets.md) | ❌ missing | Sprite assets β€” full unit / building / race / tier coverage | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | | [p2-18](p2-18-guide-public-deployment.md) | 🟑 partial | Guide web app β€” public hosting + deploy pipeline | β€” | 2026-04-17 | | [p2-19](p2-19-guide-progress-report-page.md) | βœ… done | Guide progress report page β€” dynamic dashboard + missing assets | β€” | 2026-04-17 | | [p2-20](p2-20-guide-sim-cache-pnpm-resolve.md) | ❌ missing | Fix simCachePlugin pre-warm worker β€” tsx can't resolve @magic-civ/physics-rs through pnpm symlink | [tourguide](../team-leads/tourguide.md) | 2026-04-17 | | [p2-21](p2-21-guide-simcache-static-bake.md) | ❌ missing | Bake pre-computed sim-cache frames into the static build | [tourguide](../team-leads/tourguide.md) | 2026-04-17 | -| [p2-21](p2-21-sprite-generation-pipeline.md) | ❌ missing | Sprite generation pipeline β€” runnable end-to-end | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | -| [p2-22](p2-22-unit-sprites-dwarf-roster.md) | ❌ missing | Unit sprites β€” Dwarf-racial roster (m/f variants) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | -| [p2-23](p2-23-unit-sprites-wild-creatures.md) | ❌ missing | Unit sprites β€” wild creatures & fauna (generic, no race/sex) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | -| [p2-24](p2-24-building-sprites-base-coverage.md) | ❌ missing | Building sprites β€” base game coverage (non-wonder) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | -| [p2-25](p2-25-mundane-wonder-sprites.md) | ❌ missing | Mundane-wonder sprites β€” 24 distinct, higher-fidelity art | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | -| [p2-26](p2-26-city-population-tier-sprites.md) | ❌ missing | City population-tier sprites β€” city_q1 through city_q5 | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | +| [p2-22](p2-22-sprite-generation-pipeline.md) | ❌ missing | Sprite generation pipeline β€” runnable end-to-end | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | +| [p2-23](p2-23-unit-sprites-dwarf-roster.md) | ❌ missing | Unit sprites β€” Dwarf-racial roster (m/f variants) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | +| [p2-24](p2-24-unit-sprites-wild-creatures.md) | ❌ missing | Unit sprites β€” wild creatures & fauna (generic, no race/sex) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | +| [p2-25](p2-25-building-sprites-base-coverage.md) | ❌ missing | Building sprites β€” base game coverage (non-wonder) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | +| [p2-26](p2-26-mundane-wonder-sprites.md) | ❌ missing | Mundane-wonder sprites β€” 24 distinct, higher-fidelity art | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | +| [p2-27](p2-27-city-population-tier-sprites.md) | ❌ missing | City population-tier sprites β€” city_q1 through city_q5 | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | +| [p2-28](p2-28-sprite-provenance-ledger.md) | ❌ missing | Sprite provenance ledger β€” LICENSES.md per-file attribution | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | ## Out of Scope (Game 2 / Game 3) @@ -134,3 +134,11 @@ | [g3-05](g3-05-aether-school-oos.md) | ⚫ oos | Aether school spellbook β€” Game 3 (Age of Elves) | β€” | 2026-04-17 | | [g3-06](g3-06-arcane-ascension-oos.md) | ⚫ oos | Arcane Ascension victory β€” Game 3 (Age of Elves) | β€” | 2026-04-17 | +## Superseded + +> These objectives were split into narrower children. Files are retained as index stubs so external references don't 404. The `superseded_by:` frontmatter field names the replacement IDs. + +| ID | Status | Title | Owner | Updated | +|---|---|---|---|---| +| [p2-17](p2-17-sprite-assets.md) | ♻️ superseded | Sprite assets β€” superseded index (split into p2-22 … p2-28) | [asset-sprite](../team-leads/asset-sprite.md) | 2026-04-17 | + diff --git a/.project/objectives/p2-17-sprite-assets.md b/.project/objectives/p2-17-sprite-assets.md index 10894b27..9683a010 100644 --- a/.project/objectives/p2-17-sprite-assets.md +++ b/.project/objectives/p2-17-sprite-assets.md @@ -1,27 +1,27 @@ --- id: p2-17 -title: Sprite assets β€” superseded index (split into p2-21 … p2-27) +title: Sprite assets β€” superseded index (split into p2-22 … p2-28) priority: p2 status: superseded scope: game1 owner: asset-sprite updated_at: 2026-04-17 superseded_by: - - p2-21 - p2-22 - p2-23 - p2-24 - p2-25 - p2-26 - p2-27 + - p2-28 evidence: - - .project/objectives/p2-21-sprite-generation-pipeline.md - - .project/objectives/p2-22-unit-sprites-dwarf-roster.md - - .project/objectives/p2-23-unit-sprites-wild-creatures.md - - .project/objectives/p2-24-building-sprites-base-coverage.md - - .project/objectives/p2-25-mundane-wonder-sprites.md - - .project/objectives/p2-26-city-population-tier-sprites.md - - .project/objectives/p2-27-sprite-provenance-ledger.md + - .project/objectives/p2-22-sprite-generation-pipeline.md + - .project/objectives/p2-23-unit-sprites-dwarf-roster.md + - .project/objectives/p2-24-unit-sprites-wild-creatures.md + - .project/objectives/p2-25-building-sprites-base-coverage.md + - .project/objectives/p2-26-mundane-wonder-sprites.md + - .project/objectives/p2-27-city-population-tier-sprites.md + - .project/objectives/p2-28-sprite-provenance-ledger.md --- ## Summary @@ -30,12 +30,12 @@ Split on 2026-04-17 into seven narrower objectives. The original single-file for Replaced by: -- **[p2-21](p2-21-sprite-generation-pipeline.md)** β€” `tools/sprite-generation/` runnable end-to-end (gates every child below). -- **[p2-22](p2-22-unit-sprites-dwarf-roster.md)** β€” Dwarf-racial unit sprites with m/f variants. -- **[p2-23](p2-23-unit-sprites-wild-creatures.md)** β€” wild-creature unit sprites (generic, no race/sex). -- **[p2-24](p2-24-building-sprites-base-coverage.md)** β€” non-wonder building sprites. -- **[p2-25](p2-25-mundane-wonder-sprites.md)** β€” 24 mundane wonders at higher fidelity. -- **[p2-26](p2-26-city-population-tier-sprites.md)** β€” `city_q1.png` … `city_q5.png`. -- **[p2-27](p2-27-sprite-provenance-ledger.md)** β€” `LICENSES.md` per-file attribution (runs continuously alongside p2-22…p2-26). +- **[p2-22](p2-22-sprite-generation-pipeline.md)** β€” `tools/sprite-generation/` runnable end-to-end (gates every child below). +- **[p2-23](p2-23-unit-sprites-dwarf-roster.md)** β€” Dwarf-racial unit sprites with m/f variants. +- **[p2-24](p2-24-unit-sprites-wild-creatures.md)** β€” wild-creature unit sprites (generic, no race/sex). +- **[p2-25](p2-25-building-sprites-base-coverage.md)** β€” non-wonder building sprites. +- **[p2-26](p2-26-mundane-wonder-sprites.md)** β€” 24 mundane wonders at higher fidelity. +- **[p2-27](p2-27-city-population-tier-sprites.md)** β€” `city_q1.png` … `city_q5.png`. +- **[p2-28](p2-28-sprite-provenance-ledger.md)** β€” `LICENSES.md` per-file attribution (runs continuously alongside p2-23…p2-27). This file is retained as an index stub so external references (git history, prior conversations, the team-lead charter before the split) resolve to a pointer rather than a 404. It carries no acceptance bullets of its own β€” progress is tracked in the children. diff --git a/.project/objectives/p2-21-sprite-generation-pipeline.md b/.project/objectives/p2-22-sprite-generation-pipeline.md similarity index 94% rename from .project/objectives/p2-21-sprite-generation-pipeline.md rename to .project/objectives/p2-22-sprite-generation-pipeline.md index f3e59c6f..bf392024 100644 --- a/.project/objectives/p2-21-sprite-generation-pipeline.md +++ b/.project/objectives/p2-22-sprite-generation-pipeline.md @@ -1,5 +1,5 @@ --- -id: p2-21 +id: p2-22 title: Sprite generation pipeline β€” runnable end-to-end priority: p2 status: missing @@ -16,14 +16,14 @@ evidence: ## Summary -Gate-one objective for every other `asset-sprite` child (`p2-22` … `p2-26`). Before any sprite can legitimately land in `public/games/age-of-dwarves/assets/sprites/`, the `tools/sprite-generation/` pipeline has to run cleanly end-to-end: scan game data β†’ generate variants via the configured model β†’ auto-rank via Sonnet vision β†’ surface in the Theater GUI for human approval β†’ chroma-key + resize + install with LICENSES.md row written. +Gate-one objective for every other `asset-sprite` child (`p2-23` … `p2-27`). Before any sprite can legitimately land in `public/games/age-of-dwarves/assets/sprites/`, the `tools/sprite-generation/` pipeline has to run cleanly end-to-end: scan game data β†’ generate variants via the configured model β†’ auto-rank via Sonnet vision β†’ surface in the Theater GUI for human approval β†’ chroma-key + resize + install with LICENSES.md row written. Slate is clean (user deleted 7 pre-existing sprites on 2026-04-17 for quality-bar failure; the prompt library and ranker had drifted). This objective closes out the "pipeline works" half of the split; actual sprite shipping lives in the downstream children. ## Acceptance - βœ— `tools/sprite-generation/cli.py run --category units --variants 1` completes one full loop on a clean DB: sprite picked β†’ 1 variant generated β†’ ranker writes notes + rating β†’ `status` flips from `needed` to `review` or back to `needed` (never crashes mid-loop). -- βœ— `tools/sprite-generation/cli.py approve ` on a reviewed sprite chroma-keys, resizes to 256Γ—256 (or 512Γ—512 β€” the choice is documented in `sprite-config.json`), drops the PNG into the install path, and appends a row to `assets/sprites/LICENSES.md` (contract surface for `p2-27`). +- βœ— `tools/sprite-generation/cli.py approve ` on a reviewed sprite chroma-keys, resizes to 256Γ—256 (or 512Γ—512 β€” the choice is documented in `sprite-config.json`), drops the PNG into the install path, and appends a row to `assets/sprites/LICENSES.md` (contract surface for `p2-28`). - βœ— `engine/scanner.py` introspects every file in `public/games/age-of-dwarves/data/units/*.json` and `data/buildings/*.json` (excluding `stub.json` / `manifest.json`) and materialises one row per sprite target in `spritegen.db`.sprites. - βœ— `engine/prompts.py` composes a prompt for every sprite target using the YAML library under `engine/prompts/` (`races.yaml` with `id: dwarf`, `genders.yaml`, `unit_classes.yaml`, `combat_types.yaml`, `quality_tiers.yaml`, `composition.yaml`, `negatives.yaml`, `keywords.yaml`, `styles.yaml`) β€” no hardcoded strings in `prompts.py` itself. - βœ— `sprite-config.json` points at a model from the CLAUDE.md approved list (`juggernaut-xl-v9`, `epicrealism-xl`, `illustrious-xl-v2`, or current equivalent). No anime-model variants. @@ -37,6 +37,6 @@ Slate is clean (user deleted 7 pre-existing sprites on 2026-04-17 for quality-ba ## Non-goals -- Actually shipping any sprite PNG into `assets/sprites/` (that's `p2-22` … `p2-26`). +- Actually shipping any sprite PNG into `assets/sprites/` (that's `p2-23` … `p2-27`). - GPU autoscaling, distributed batch runs, or cross-host orchestration (post-EA if ever). - Replacement of `tools/gen-fallback-sprites.py` β€” the SVG fallback tool stays for procedural dev-baseline; it's not part of the ship-art path and is not owned by this objective. diff --git a/.project/objectives/p2-22-unit-sprites-dwarf-roster.md b/.project/objectives/p2-23-unit-sprites-dwarf-roster.md similarity index 88% rename from .project/objectives/p2-22-unit-sprites-dwarf-roster.md rename to .project/objectives/p2-23-unit-sprites-dwarf-roster.md index ff1d225f..49bfccdd 100644 --- a/.project/objectives/p2-22-unit-sprites-dwarf-roster.md +++ b/.project/objectives/p2-23-unit-sprites-dwarf-roster.md @@ -1,5 +1,5 @@ --- -id: p2-22 +id: p2-23 title: Unit sprites β€” Dwarf-racial roster (m/f variants) priority: p2 status: missing @@ -18,28 +18,28 @@ Every Dwarf-controlled combat + support unit declared in `public/games/age-of-dw The current roster of gender-bearing units in `data/units/` (2026-04-17 snapshot): `archer`, `berserker`, `cavalry`, `pikeman`, `runesmith`, `spearmen`, `warrior`, `worker` β€” 8 unit types Γ— 2 genders = 16 PNG files. Race id is `dwarf` (singular β€” confirmed in `public/games/age-of-dwarves/data/races.json`); the `Player.race_id` fallback in `unit_renderer.gd:_resolve_race_id()` resolves to that value at runtime. -Slate is clean β€” the 7 previously-authored sprites were deleted 2026-04-17 for quality-bar failure. Do not restore; regenerate via `p2-21` once the pipeline is green. +Slate is clean β€” the 7 previously-authored sprites were deleted 2026-04-17 for quality-bar failure. Do not restore; regenerate via `p2-22` once the pipeline is green. ## Acceptance - βœ— For each unit `` in `data/units/*.json` with a `gender` block, `_dwarf_m.png` and `_dwarf_f.png` exist in `public/games/age-of-dwarves/assets/sprites/units/`. Filename contract: `SPRITE_LOOKUP_RACE_SEX_FORMAT = "sprites/units/%s_%s_%s.png"` (`unit_renderer.gd:52`). - βœ— For each such unit, a generic `.png` also exists (renderer's fallback chain in `unit_renderer.gd:_get_unit_sprite()`; present so raceless/genderless resolution paths also render art). -- βœ— Each PNG is 256Γ—256 or 512Γ—512 (resolution choice consistent across the roster, documented once in `p2-27` LICENSES.md header), PNG with alpha channel, transparent background (no baked backdrop). +- βœ— Each PNG is 256Γ—256 or 512Γ—512 (resolution choice consistent across the roster, documented once in `p2-28` LICENSES.md header), PNG with alpha channel, transparent background (no baked backdrop). - βœ— Style coherence: all 16 sprites came from the same `tools/sprite-generation/` run or from a commission brief using the same prompt library β€” no mixed provenance within the roster. Verified by running `python3 tools/sprite-generation/cli.py verify --category units --race dwarf` (or equivalent; introduce if not present) returning zero mismatches. -- βœ— Each sprite passed the ranker threshold configured in `p2-21`, OR was approved via the Theater GUI with a rating β‰₯ 4 in `spritegen.db`. -- βœ— Each sprite has a row in `public/games/age-of-dwarves/assets/sprites/LICENSES.md` (contract satisfied via `p2-27`). +- βœ— Each sprite passed the ranker threshold configured in `p2-22`, OR was approved via the Theater GUI with a rating β‰₯ 4 in `spritegen.db`. +- βœ— Each sprite has a row in `public/games/age-of-dwarves/assets/sprites/LICENSES.md` (contract satisfied via `p2-28`). - βœ— Proof screenshot: one game turn rendered on plum Godot showing Dwarf units on the map with sprite overlays (not just procedural circles), captured via `tools/screenshot.sh` per `.claude/instructions/phase-gate-protocol.md`, SCP'd to `$SCREENSHOT_HOST`, reviewed in-conversation. ## Depends on -- `p2-21` (pipeline runnable end-to-end). +- `p2-22` (pipeline runnable end-to-end). - `p0-23` (sprite rendering capability β€” done). -- `p2-27` (LICENSES.md ledger) β€” each sprite shipped here adds one row there. +- `p2-28` (LICENSES.md ledger) β€” each sprite shipped here adds one row there. ## Non-goals -- Wild-creature sprites (`p2-23`). -- Building sprites (`p2-24`). +- Wild-creature sprites (`p2-24`). +- Building sprites (`p2-25`). - Animation frames / sprite sheets β€” post-EA. - Sprites for the aspirational `dwarf_*`-prefixed unit ids in `data/units/manifest.json` (e.g. `dwarf_founder`, `dwarf_steam_cannon`). Those units are not currently materialised in `data/units/*.json` and are tracked separately when the data is authored. - Units with `race_required` naming a non-Dwarf race β€” Game 1 is single-race; non-Dwarf playable races are Game 2 (`g2-02-additional-races-oos.md`) / Game 3. diff --git a/.project/objectives/p2-23-unit-sprites-wild-creatures.md b/.project/objectives/p2-24-unit-sprites-wild-creatures.md similarity index 89% rename from .project/objectives/p2-23-unit-sprites-wild-creatures.md rename to .project/objectives/p2-24-unit-sprites-wild-creatures.md index 894e5380..ec9d29ce 100644 --- a/.project/objectives/p2-23-unit-sprites-wild-creatures.md +++ b/.project/objectives/p2-24-unit-sprites-wild-creatures.md @@ -1,5 +1,5 @@ --- -id: p2-23 +id: p2-24 title: Unit sprites β€” wild creatures & fauna (generic, no race/sex) priority: p2 status: missing @@ -23,21 +23,21 @@ Each is a recognisable silhouette at the renderer's 56Γ—56 hex render size (veri ## Acceptance - βœ— For each wild unit `` in `data/units/*.json` with `unit_type: "wild"`, `.png` exists in `public/games/age-of-dwarves/assets/sprites/units/`. No race or sex suffix. -- βœ— Each PNG is 256Γ—256 or 512Γ—512 (matching the resolution chosen for `p2-22`), PNG with alpha channel, transparent background. +- βœ— Each PNG is 256Γ—256 or 512Γ—512 (matching the resolution chosen for `p2-23`), PNG with alpha channel, transparent background. - βœ— Silhouette legibility: each sprite remains identifiable when downsampled to 56Γ—56 (rendered hex size). Verified by eyeballing the `sprite_proof.tscn` rendering pass with each creature keyed into the cache in turn. -- βœ— Each sprite passed the ranker threshold configured in `p2-21` or was approved via Theater GUI with rating β‰₯ 4 in `spritegen.db`. -- βœ— Each sprite has a row in `LICENSES.md` (contract satisfied via `p2-27`). +- βœ— Each sprite passed the ranker threshold configured in `p2-22` or was approved via Theater GUI with rating β‰₯ 4 in `spritegen.db`. +- βœ— Each sprite has a row in `LICENSES.md` (contract satisfied via `p2-28`). - βœ— Proof screenshot: a map snapshot on plum Godot showing a lair tile + at least three wild creature types rendering with sprite overlays, captured via `tools/screenshot.sh` per `phase-gate-protocol.md`. ## Depends on -- `p2-21` (pipeline runnable end-to-end). +- `p2-22` (pipeline runnable end-to-end). - `p0-23` (sprite rendering capability β€” done). -- `p2-27` (LICENSES.md ledger). +- `p2-28` (LICENSES.md ledger). ## Non-goals -- Dwarf-racial unit sprites (`p2-22`). +- Dwarf-racial unit sprites (`p2-23`). - Race/sex variants for wild creatures β€” deliberately single sprite per id. - Animated or multi-pose creature sheets β€” post-EA. - Hostile-faction or barbarian-unique art β€” Game 2 concern. diff --git a/.project/objectives/p2-24-building-sprites-base-coverage.md b/.project/objectives/p2-25-building-sprites-base-coverage.md similarity index 82% rename from .project/objectives/p2-24-building-sprites-base-coverage.md rename to .project/objectives/p2-25-building-sprites-base-coverage.md index 298aa6d7..78d0e540 100644 --- a/.project/objectives/p2-24-building-sprites-base-coverage.md +++ b/.project/objectives/p2-25-building-sprites-base-coverage.md @@ -1,5 +1,5 @@ --- -id: p2-24 +id: p2-25 title: Building sprites β€” base game coverage (non-wonder) priority: p2 status: missing @@ -20,22 +20,22 @@ Current base roster (2026-04-17 snapshot, 10 buildings): `ale_hall`, `barracks`, ## Acceptance - βœ— For each building id `` parsed from the non-wonder files under `data/buildings/`, `.png` exists in `public/games/age-of-dwarves/assets/sprites/buildings/`. -- βœ— Each PNG is 256Γ—256 or 512Γ—512 (matching the resolution chosen for `p2-22`/`p2-23`), PNG with alpha channel, transparent background. +- βœ— Each PNG is 256Γ—256 or 512Γ—512 (matching the resolution chosen for `p2-23`/`p2-24`), PNG with alpha channel, transparent background. - βœ— Silhouette is legible at city-screen thumbnail scale (128Γ—128 or the current city-screen icon size β€” whichever `city_screen.tscn` consumes). -- βœ— Style coherence: palette + lighting direction consistent across the 10 buildings. Pipeline-generated via the same prompt library as `p2-22` (`tools/sprite-generation/engine/prompts/` β€” building branch). -- βœ— Each sprite passed the ranker threshold configured in `p2-21` or was approved via Theater GUI with rating β‰₯ 4 in `spritegen.db`. -- βœ— Each sprite has a row in `LICENSES.md` (contract satisfied via `p2-27`). +- βœ— Style coherence: palette + lighting direction consistent across the 10 buildings. Pipeline-generated via the same prompt library as `p2-23` (`tools/sprite-generation/engine/prompts/` β€” building branch). +- βœ— Each sprite passed the ranker threshold configured in `p2-22` or was approved via Theater GUI with rating β‰₯ 4 in `spritegen.db`. +- βœ— Each sprite has a row in `LICENSES.md` (contract satisfied via `p2-28`). - βœ— Proof screenshot: city-screen or world-map capture on plum Godot showing at least 4 distinct building sprites rendering on top of the procedural baseline, per `phase-gate-protocol.md`. ## Depends on -- `p2-21` (pipeline runnable end-to-end). +- `p2-22` (pipeline runnable end-to-end). - `p0-23` (sprite rendering capability β€” done). -- `p2-27` (LICENSES.md ledger). +- `p2-28` (LICENSES.md ledger). ## Non-goals -- Mundane-wonder sprites (`p2-25`) β€” separate fidelity bar, separate objective. -- City population-tier sprites (`p2-26`) β€” different key format (`city_q.png`). +- Mundane-wonder sprites (`p2-26`) β€” separate fidelity bar, separate objective. +- City population-tier sprites (`p2-27`) β€” different key format (`city_q.png`). - Building upgrade-stage visuals (post-EA if ever). - Improvement / tile-yield icons β€” those are UI icons, not building sprites. diff --git a/.project/objectives/p2-25-mundane-wonder-sprites.md b/.project/objectives/p2-26-mundane-wonder-sprites.md similarity index 89% rename from .project/objectives/p2-25-mundane-wonder-sprites.md rename to .project/objectives/p2-26-mundane-wonder-sprites.md index dc6e5117..4334b35e 100644 --- a/.project/objectives/p2-25-mundane-wonder-sprites.md +++ b/.project/objectives/p2-26-mundane-wonder-sprites.md @@ -1,5 +1,5 @@ --- -id: p2-25 +id: p2-26 title: Mundane-wonder sprites β€” 24 distinct, higher-fidelity art priority: p2 status: missing @@ -13,26 +13,26 @@ evidence: ## Summary -`public/games/age-of-dwarves/data/buildings/mundane_wonders.json` declares 24 Civ5-style world wonders for Game 1 (no magic schools β€” these are mundane flavour wonders). Each needs a **distinct, higher-fidelity** sprite β€” a generic "fancy building" look drags the whole wonder system's perceived prestige. Split from `p2-24` so the quality bar can be tracked independently. +`public/games/age-of-dwarves/data/buildings/mundane_wonders.json` declares 24 Civ5-style world wonders for Game 1 (no magic schools β€” these are mundane flavour wonders). Each needs a **distinct, higher-fidelity** sprite β€” a generic "fancy building" look drags the whole wonder system's perceived prestige. Split from `p2-25` so the quality bar can be tracked independently. Current wonder roster (2026-04-17 snapshot): `ancestral_forge`, `mead_hall`, `first_mineshaft`, `clan_moot_stone`, `iron_bulwark`, `hall_of_ancestors`, `the_deep_road`, `bardic_circle`, `archive_of_runes`, `royal_runestone`, `grand_observatory`, `covenant_stone`, `the_great_forge`, `iron_crown`, `undermount_vault`, `hall_of_echoes`, `world_pillar`, `well_of_ages`, `the_undying_flame`, `voice_of_ages`, `silent_cartograph`, `shrine_of_names`, `the_cold_anvil`, `hearthless_hall`. ## Acceptance - βœ— For each wonder id `` in `mundane_wonders.json`, `.png` exists in `public/games/age-of-dwarves/assets/sprites/buildings/` β€” one distinct silhouette per wonder, no palette-swapped reuse. -- βœ— Each PNG is 512Γ—512, PNG with alpha channel, transparent background. (Higher resolution than the base-building bar in `p2-24`; documented in LICENSES.md header.) +- βœ— Each PNG is 512Γ—512, PNG with alpha channel, transparent background. (Higher resolution than the base-building bar in `p2-25`; documented in LICENSES.md header.) - βœ— Tier-appropriate grandeur: a wonder's visual complexity reflects its `unlock_tier` in `mundane_wonders.json`. Verified manually β€” flagged wonders with complexity incongruent to tier get re-generated. - βœ— Style coherence within the wonder set: palette + lighting direction consistent across the 24, and readable as "ancient / monumental" rather than "functional building". -- βœ— Each sprite passed the ranker threshold configured in `p2-21` with a minimum rating β‰₯ 4.2 (stricter than `p2-22` / `p2-24`) OR was approved via Theater GUI at rating 5. -- βœ— Each sprite has a row in `LICENSES.md` (contract satisfied via `p2-27`). +- βœ— Each sprite passed the ranker threshold configured in `p2-22` with a minimum rating β‰₯ 4.2 (stricter than `p2-23` / `p2-25`) OR was approved via Theater GUI at rating 5. +- βœ— Each sprite has a row in `LICENSES.md` (contract satisfied via `p2-28`). - βœ— Proof screenshot: capture on plum Godot showing a built wonder rendering on a city tile with its sprite overlay, plus the wonder card in the production queue showing the same art. `phase-gate-protocol.md`. ## Depends on -- `p2-21` (pipeline runnable end-to-end). +- `p2-22` (pipeline runnable end-to-end). - `p0-04` (wonder tracking β€” done; wonders exist in simulation before we decorate them). - `p0-23` (sprite rendering capability β€” done). -- `p2-27` (LICENSES.md ledger). +- `p2-28` (LICENSES.md ledger). ## Non-goals diff --git a/.project/objectives/p2-26-city-population-tier-sprites.md b/.project/objectives/p2-27-city-population-tier-sprites.md similarity index 89% rename from .project/objectives/p2-26-city-population-tier-sprites.md rename to .project/objectives/p2-27-city-population-tier-sprites.md index eb30a7af..4ba3b8a0 100644 --- a/.project/objectives/p2-26-city-population-tier-sprites.md +++ b/.project/objectives/p2-27-city-population-tier-sprites.md @@ -1,5 +1,5 @@ --- -id: p2-26 +id: p2-27 title: City population-tier sprites β€” city_q1 through city_q5 priority: p2 status: missing @@ -18,18 +18,18 @@ evidence: ## Acceptance - βœ— `city_q1.png`, `city_q2.png`, `city_q3.png`, `city_q4.png`, `city_q5.png` all exist in `public/games/age-of-dwarves/assets/sprites/cities/`. -- βœ— Each PNG is 256Γ—256 or 512Γ—512 (matching the chosen resolution for `p2-22`/`p2-24`), PNG with alpha channel, transparent background. +- βœ— Each PNG is 256Γ—256 or 512Γ—512 (matching the chosen resolution for `p2-23`/`p2-25`), PNG with alpha channel, transparent background. - βœ— Visual progression: each tier is clearly "larger / denser" than the previous β€” a player glancing at the map can tell q1 from q3 without zoom. - βœ— Silhouette legible at the world-map rendered size (the resolved size in `city_renderer.gd` `_draw_city_sprite()`). -- βœ— Each sprite passed the ranker threshold configured in `p2-21` with rating β‰₯ 4, OR was approved via Theater GUI. -- βœ— Each sprite has a row in `LICENSES.md` (contract satisfied via `p2-27`). +- βœ— Each sprite passed the ranker threshold configured in `p2-22` with rating β‰₯ 4, OR was approved via Theater GUI. +- βœ— Each sprite has a row in `LICENSES.md` (contract satisfied via `p2-28`). - βœ— Proof screenshot: plum Godot capture of a game late enough to have cities at three distinct population tiers, showing the tier sprites rendering distinctly on the world map. `phase-gate-protocol.md`. ## Depends on -- `p2-21` (pipeline runnable end-to-end). +- `p2-22` (pipeline runnable end-to-end). - `p0-23` (sprite rendering capability β€” done). -- `p2-27` (LICENSES.md ledger). +- `p2-28` (LICENSES.md ledger). ## Non-goals diff --git a/.project/objectives/p2-27-sprite-provenance-ledger.md b/.project/objectives/p2-28-sprite-provenance-ledger.md similarity index 89% rename from .project/objectives/p2-27-sprite-provenance-ledger.md rename to .project/objectives/p2-28-sprite-provenance-ledger.md index 85c3924d..b608e2f2 100644 --- a/.project/objectives/p2-27-sprite-provenance-ledger.md +++ b/.project/objectives/p2-28-sprite-provenance-ledger.md @@ -1,5 +1,5 @@ --- -id: p2-27 +id: p2-28 title: Sprite provenance ledger β€” LICENSES.md per-file attribution priority: p2 status: missing @@ -13,7 +13,7 @@ evidence: ## Summary -Every sprite PNG that ships in `public/games/age-of-dwarves/assets/sprites/` must have a corresponding row in `public/games/age-of-dwarves/assets/sprites/LICENSES.md` recording source, license, author, URL, and SHA256. This is a cross-cutting compliance objective that runs continuously alongside the delivery children (`p2-22` … `p2-26`) β€” the ledger is complete exactly when every on-disk sprite has a matching row and every row points at an on-disk file. +Every sprite PNG that ships in `public/games/age-of-dwarves/assets/sprites/` must have a corresponding row in `public/games/age-of-dwarves/assets/sprites/LICENSES.md` recording source, license, author, URL, and SHA256. This is a cross-cutting compliance objective that runs continuously alongside the delivery children (`p2-23` … `p2-27`) β€” the ledger is complete exactly when every on-disk sprite has a matching row and every row points at an on-disk file. Commercial-use compatibility is non-negotiable. AI-generated output must come from a model on the approved list (`juggernaut-xl-v9`, `epicrealism-xl`, `illustrious-xl-v2`, or current equivalent per CLAUDE.md). Commissioned art must have assigned commercial rights in writing. @@ -24,13 +24,13 @@ Commercial-use compatibility is non-negotiable. AI-generated output must come fr - βœ— Every PNG file under `assets/sprites/**/*.png` has exactly one row in `LICENSES.md` β€” no duplicates, no missing entries. Verified by a script (to be authored under `tools/` β€” e.g. `tools/sprite-license-audit.py`) that diffs `ls assets/sprites/**/*.png` against the row paths. - βœ— Every row in `LICENSES.md` points at an existing file on disk with the declared SHA256. Same script verifies both directions. - βœ— No row carries a license that is not commercial-use-compatible. License whitelist documented at the top of `LICENSES.md`. -- βœ— `tools/sprite-generation/engine/installer.py` (touched by `p2-21`) appends a row on every approved install; no sprite lands in `assets/sprites/` without the ledger being updated in the same commit. +- βœ— `tools/sprite-generation/engine/installer.py` (touched by `p2-22`) appends a row on every approved install; no sprite lands in `assets/sprites/` without the ledger being updated in the same commit. - βœ— Running `python3 tools/sprite-license-audit.py` returns exit 0 with zero mismatch output in CI (integration with `./run verify` tracked as an optional enhancement; the script existing and passing locally is the ship gate). ## Depends on -- `p2-21` (pipeline runnable end-to-end) β€” installer path is where ledger rows are written. -- `p2-22` … `p2-26` β€” deliver the sprite files this ledger audits; `p2-27` closes when their combined on-disk set matches the ledger. +- `p2-22` (pipeline runnable end-to-end) β€” installer path is where ledger rows are written. +- `p2-23` … `p2-27` β€” deliver the sprite files this ledger audits; `p2-28` closes when their combined on-disk set matches the ledger. ## Non-goals diff --git a/.project/team-leads/asset-sprite.md b/.project/team-leads/asset-sprite.md index f4e837ad..140b4cc5 100644 --- a/.project/team-leads/asset-sprite.md +++ b/.project/team-leads/asset-sprite.md @@ -3,44 +3,74 @@ id: asset-sprite name: Asset β€” Sprite specialization: Generate, commission, and ship unit / building / wonder sprite art per the sprite-rendering capability contract objectives: - - p2-17 + - p2-22 + - p2-23 + - p2-24 + - p2-25 + - p2-26 + - p2-27 + - p2-28 --- ## Mandate -Ship the `.png` sprite files that the renderers expect when `ThemeAssets.load_sprite()` is called. The rendering *capability* is being built in p0-23: renderers draw procedural primitives first (unconditional baseline), then overlay a sprite if one exists at the resolved path. Asset-Sprite's job is producing the sprites β€” game-ready, style-consistent, tier-appropriate. +Ship the `.png` sprite files that the renderers expect when `ThemeAssets.load_sprite()` is called. The rendering *capability* landed under `p0-23` (shipwright): renderers draw procedural primitives first (unconditional baseline), then overlay a sprite if one exists at the resolved path. Asset-Sprite's job is producing the sprites β€” game-ready, style-consistent, tier-appropriate. -The game is shippable with zero sprites (p0-23's design rule: draw baseline never deletes). Asset-Sprite's delivery progressively replaces the circle-and-letter placeholders with real art, unit by unit, building by building. +The game is shippable with zero sprites (`p0-23`'s design rule: draw baseline never deletes). Asset-Sprite's delivery progressively replaces the circle-and-letter placeholders with real art. + +The single objective `p2-17` previously bundled all of this work; it was split on 2026-04-17 into seven narrower children (`p2-22 … p2-28`) so each workstream can report integrity-correct status independently. `p2-17` is retained as a `status: superseded` index stub. + +## Owned objectives + +| ID | Workstream | Gates | +|---|---|---| +| [p2-22](../objectives/p2-22-sprite-generation-pipeline.md) | Pipeline readiness β€” `tools/sprite-generation/` end-to-end | Gates p2-23 … p2-27 | +| [p2-23](../objectives/p2-23-unit-sprites-dwarf-roster.md) | Unit sprites β€” Dwarf-racial roster (m/f variants) | Depends on p2-22 | +| [p2-24](../objectives/p2-24-unit-sprites-wild-creatures.md) | Unit sprites β€” wild creatures (generic key) | Depends on p2-22 | +| [p2-25](../objectives/p2-25-building-sprites-base-coverage.md) | Building sprites β€” base roster | Depends on p2-22 | +| [p2-26](../objectives/p2-26-mundane-wonder-sprites.md) | Wonder sprites β€” 24 distinct at higher fidelity | Depends on p2-22 | +| [p2-27](../objectives/p2-27-city-population-tier-sprites.md) | City population-tier sprites β€” `city_q1` … `city_q5` | Depends on p2-22 | +| [p2-28](../objectives/p2-28-sprite-provenance-ledger.md) | `LICENSES.md` per-file attribution | Runs continuously alongside p2-23 … p2-27 | ## Owned surface -- `public/games/age-of-dwarves/assets/sprites/units/__.png` β€” every `data/units/*.json` entry should have a matching sprite variant per race Γ— sex combination the game supports -- `public/games/age-of-dwarves/assets/sprites/buildings/.png` β€” every `data/buildings/*.json` entry + every wonder in `mundane_wonders.json` -- `public/games/age-of-dwarves/assets/sprites/LICENSES.md` β€” per-file attribution (source, license, author, URL, SHA256) -- `tools/sprite-generation/` β€” the generation pipeline (prompt authoring, model inference, post-processing, normalization, drop-into-assets) -- Any authoring data: style references, prompt libraries, generation seeds, post-process scripts +- `public/games/age-of-dwarves/assets/sprites/units/__.png` β€” one pair (m/f) per Dwarf-racial unit; key format from `SPRITE_LOOKUP_RACE_SEX_FORMAT` in `src/game/engine/src/rendering/unit_renderer.gd`. +- `public/games/age-of-dwarves/assets/sprites/units/.png` β€” generic fallback (applies to wild creatures and as race/sex-less fallback for Dwarf units). +- `public/games/age-of-dwarves/assets/sprites/buildings/.png` β€” one per building id in `data/buildings/*.json` (including `mundane_wonders.json`). +- `public/games/age-of-dwarves/assets/sprites/cities/city_q.png` β€” N ∈ [1, 5], key format from `SPRITE_LOOKUP_CITY_FORMAT` in `src/game/engine/src/rendering/city_renderer.gd`. +- `public/games/age-of-dwarves/assets/sprites/LICENSES.md` β€” per-file attribution (schema in `p2-28`). +- `tools/sprite-generation/` β€” the generation pipeline (CLI orchestrator, prompt library, generator, ranker, Theater GUI, installer, SQLite registry `spritegen.db`). Does NOT own: -- `src/game/engine/src/rendering/*_renderer.gd` β€” the runtime sprite load + overlay path. Owned by godot-renderer. Asset-Sprite reads the expected path conventions and produces files that match. + +- `src/game/engine/src/rendering/*_renderer.gd` β€” runtime sprite load + overlay path. Owned by `shipwright` via `p0-23`. Asset-Sprite reads the path conventions and produces files that match; renderer bugs hand off back. - Sprite generation model selection beyond the CLAUDE.md rule ("NEVER use anime models for game art β€” use `juggernaut-xl-v9`, `epicrealism-xl`, `illustrious-xl-v2`"). +- `tools/gen-fallback-sprites.py` β€” the procedural SVG fallback tool is part of the dev baseline, not ship art. ## Working constraints -- **PNG with alpha channel.** Square canvas, 256Γ—256 or 512Γ—512 (document the choice in LICENSES.md). -- **Transparent background** β€” renderer composites sprite onto hex; any background color would bake incorrectly. -- **Consistent art style** across the library β€” use MTG-color-coded palette per the sprite-generation pipeline doc, but the Dwarf race is the only Game 1 race so visual coherence is within-race, not cross-race. -- **License must be commercial-use compatible** β€” AI-generated output has to be from a model the project is licensed to use commercially (check juggernaut-xl, epicrealism-xl, illustrious-xl-v2 license terms at ship time). Commissioned art must have assigned commercial rights. -- **SHA256 recorded in LICENSES.md** for binary-diff traceability. -- **Budget**: 256Γ—256 PNG at reasonable quality β‰ˆ 30-80KB. Full library of ~100-300 sprites ≀ 20MB. -- **Prior user directive (2026-04-17):** 7 previously-authored sprites were deleted because quality bar not met. Slate is clean. Re-generate from the pipeline or commission β€” do not restore the deleted files. +- **PNG with alpha channel.** Square canvas, 256Γ—256 or 512Γ—512 (choice consistent across a roster; 512Β² for wonders per `p2-26`). Resolution choice documented once in `LICENSES.md` header. +- **Transparent background** β€” renderer composites onto hex; any baked background would render incorrectly. +- **Style coherence** across a roster β€” MTG-color-coded palette per the sprite-generation pipeline docs. Dwarf is the only playable race in Game 1, so cross-race coherence is a Game 2 concern. +- **License must be commercial-use compatible** β€” approved-model AI output or commissioned art with assigned rights. Ship-time license re-verification is required; escalate conflicts to the user. +- **SHA256 per file** in `LICENSES.md` for binary-diff traceability. +- **Budget**: 256Β² PNG β‰ˆ 30–80 KB, 512Β² β‰ˆ 100–250 KB. Full library target ≀ 20 MB. +- **Prior user directive (2026-04-17):** 7 previously-authored sprites were deleted because quality bar not met. Slate is clean; regenerate via `p2-22` or commission β€” do not restore the deleted files. ## Acceptance loop -Per p2-17's acceptance bullets. Deliveries can land incrementally β€” every sprite added to `assets/sprites/` renders the next time the game boots. Flip p2-17 to `done` when all declared units + buildings + wonders have at least one sprite variant, LICENSES.md is complete, and a proof screenshot shows a sample map with sprite-rendered entities co-existing with draw-baseline fallbacks. +Per the acceptance bullets of each child objective. Deliveries land incrementally β€” every sprite added to `assets/sprites/` renders the next time the game boots, and the baseline procedural draw keeps working for anything not yet shipped. An objective flips to `done` only when every acceptance bullet is `βœ“` with cited evidence, per `.claude/instructions/objective-integrity.md`. + +Sequencing: + +1. `p2-22` first β€” without a green pipeline, there's no way to produce style-consistent sprites at quality bar. +2. `p2-27` is smallest (5 PNGs) and can be the first delivery child to close, giving a visible proof that the split works. +3. `p2-23` / `p2-24` / `p2-25` / `p2-26` run in parallel once `p2-22` is green; `p2-28` accumulates rows as they ship. +4. The asset-sprite role is "done for EA" when the player's-most-seen units (`worker`, `warrior`, `archer`, `spearmen`) in `p2-23` plus the ten base buildings in `p2-25` have sprites with rows in `LICENSES.md`. Full coverage (wild creatures, all wonders, all city tiers) can land post-EA as progressive visual polish β€” coordinate with `shipwright` on which slices block release. ## Escalation - **Model license conflict** at ship time β†’ escalate to user; a different base model may be required. -- **Style drift** between batches of generated sprites β†’ stop generating, iterate on the prompt library / post-process pipeline before shipping more. -- **Renderer can't load a specific PNG** (e.g. format bug, alpha channel issue) β†’ handoff to godot-renderer; Asset-Sprite does not patch renderer code. -- **Budget / timeline pressure** β†’ coordinate with shipwright; most sprites can land post-EA as progressive visual polish rather than blocking release. Prioritize "player's most-seen units" (Founder, Warrior, Scout) for EA. +- **Style drift** between batches β†’ stop generating, iterate prompt library / post-process pipeline (inside `p2-22`'s surface) before shipping more; do not push drifted art into the delivery children. +- **Renderer can't load a specific PNG** (format bug, alpha-channel issue, etc.) β†’ handoff to `shipwright` / `godot-renderer`. Asset-Sprite does not patch renderer code. +- **Budget / timeline pressure** β†’ coordinate with `shipwright`; all sprite work is `p2` by design, so slipping past EA is acceptable as long as the baseline draw path (from `p0-23`) continues to cover any missing sprite. diff --git a/public/games/age-of-dwarves/data/objectives.json b/public/games/age-of-dwarves/data/objectives.json index 4882628b..8cc9aa15 100644 --- a/public/games/age-of-dwarves/data/objectives.json +++ b/public/games/age-of-dwarves/data/objectives.json @@ -1,11 +1,11 @@ { - "generated_at": "2026-04-17T21:58:28Z", + "generated_at": "2026-04-17T22:01:06Z", "totals": { "done": 35, - "stub": 6, - "partial": 16, "missing": 11, + "partial": 16, "oos": 9, + "stub": 6, "total": 77 }, "objectives": [ @@ -579,16 +579,6 @@ "updated_at": "2026-04-17", "summary": "The audio capability shipped as **p0-21** β€” `AudioManager`, manifest, signal wiring, volume sliders all work. What's missing is the 16 actual `.ogg` files the manifest declares. Gameplay is currently silent. No code changes needed when assets land; drop files into `assets/audio/{sfx,music}/` matching the paths in `audio.json`.\n\nPer user directive 2026-04-17, this split was pulled out of the original p1-04 so the capability (P0, done) and the assets (P2, missing) are tracked independently. A silent ship is shippable; a broken audio system is not." }, - { - "id": "p2-17", - "title": "Sprite assets β€” full unit / building / race / tier coverage", - "priority": "p2", - "status": "missing", - "scope": "game1", - "owner": "asset-sprite", - "updated_at": "2026-04-17", - "summary": "With p0-22 capability in place, the game needs comprehensive sprite coverage:\n- Every unit Γ— race Γ— sex combination declared in `data/units/`\n- Every building declared in `data/buildings/`\n- Per-tier variants where meaningful (T1-T4 sprites can look different from T7-T10)\n\nCurrently 0 sprite files exist β€” prior 7 were deleted 2026-04-17 per user directive (quality bar not met). Hundreds are expected when the full sprite generation pipeline runs (or commissioned art lands). Slate is clean." - }, { "id": "p2-18", "title": "Guide web app β€” public hosting + deploy pipeline", @@ -630,27 +620,27 @@ "summary": "`simCachePlugin` (Vite dev plugin) pre-computes climate-simulator\nscenarios on `pnpm dev` startup and serves the resulting frames over\n`/__sim-cache//{status,frame/}` so\n`/climate/simulation` can load pre-rendered video-like playback\ninstead of running WASM inline for minutes on cold visits. Today this\nis dev-only; on production / `.next.` deploys there is no server to\nrun the plugin, so the frontend falls back to client-WASM β€” slow\ncold-start, but works.\n\nThis objective fills the gap: at build time, run each canonical\nscenario headlessly (node + the WASM pkg), emit the same binary frame\nformat `simCachePlugin` serves, and drop the output at\n`dist/__sim-cache//...` so the static deploy serves the\nsame byte streams the dev plugin serves. The frontend doesn't change\nβ€” it still GETs `/__sim-cache/base_no_magic/status?…` and gets the\nsame shape. The `try_files $uri $uri/` line in the\n`mc.next.black.local` vhost (p1-15) already passes them through.\n\nSide effect: this closes the bulk of p2-20 for production. The tsx\npnpm-resolve bug remains in dev, but nobody hits the stall path\nbecause in dev the plugin is the fallback (both paths go through\ntsx, both fail identically β€” hm, actually, server-mode cold reads\nRedis first; if Redis is warm, no tsx worker is spawned). p2-20\nstill needs its own fix for cold `pnpm dev` runs." }, { - "id": "p2-21", + "id": "p2-22", "title": "Sprite generation pipeline β€” runnable end-to-end", "priority": "p2", "status": "missing", "scope": "game1", "owner": "asset-sprite", "updated_at": "2026-04-17", - "summary": "Gate-one objective for every other `asset-sprite` child (`p2-22` … `p2-26`). Before any sprite can legitimately land in `public/games/age-of-dwarves/assets/sprites/`, the `tools/sprite-generation/` pipeline has to run cleanly end-to-end: scan game data β†’ generate variants via the configured model β†’ auto-rank via Sonnet vision β†’ surface in the Theater GUI for human approval β†’ chroma-key + resize + install with LICENSES.md row written.\n\nSlate is clean (user deleted 7 pre-existing sprites on 2026-04-17 for quality-bar failure; the prompt library and ranker had drifted). This objective closes out the \"pipeline works\" half of the split; actual sprite shipping lives in the downstream children." + "summary": "Gate-one objective for every other `asset-sprite` child (`p2-23` … `p2-27`). Before any sprite can legitimately land in `public/games/age-of-dwarves/assets/sprites/`, the `tools/sprite-generation/` pipeline has to run cleanly end-to-end: scan game data β†’ generate variants via the configured model β†’ auto-rank via Sonnet vision β†’ surface in the Theater GUI for human approval β†’ chroma-key + resize + install with LICENSES.md row written.\n\nSlate is clean (user deleted 7 pre-existing sprites on 2026-04-17 for quality-bar failure; the prompt library and ranker had drifted). This objective closes out the \"pipeline works\" half of the split; actual sprite shipping lives in the downstream children." }, { - "id": "p2-22", + "id": "p2-23", "title": "Unit sprites β€” Dwarf-racial roster (m/f variants)", "priority": "p2", "status": "missing", "scope": "game1", "owner": "asset-sprite", "updated_at": "2026-04-17", - "summary": "Every Dwarf-controlled combat + support unit declared in `public/games/age-of-dwarves/data/units/*.json` (the non-wild entries β€” those with a `gender: { male, female }` block) needs a matching pair of PNG sprites in `public/games/age-of-dwarves/assets/sprites/units/` so `UnitRenderer` can overlay the sprite on top of the procedural baseline.\n\nThe current roster of gender-bearing units in `data/units/` (2026-04-17 snapshot): `archer`, `berserker`, `cavalry`, `pikeman`, `runesmith`, `spearmen`, `warrior`, `worker` β€” 8 unit types Γ— 2 genders = 16 PNG files. Race id is `dwarf` (singular β€” confirmed in `public/games/age-of-dwarves/data/races.json`); the `Player.race_id` fallback in `unit_renderer.gd:_resolve_race_id()` resolves to that value at runtime.\n\nSlate is clean β€” the 7 previously-authored sprites were deleted 2026-04-17 for quality-bar failure. Do not restore; regenerate via `p2-21` once the pipeline is green." + "summary": "Every Dwarf-controlled combat + support unit declared in `public/games/age-of-dwarves/data/units/*.json` (the non-wild entries β€” those with a `gender: { male, female }` block) needs a matching pair of PNG sprites in `public/games/age-of-dwarves/assets/sprites/units/` so `UnitRenderer` can overlay the sprite on top of the procedural baseline.\n\nThe current roster of gender-bearing units in `data/units/` (2026-04-17 snapshot): `archer`, `berserker`, `cavalry`, `pikeman`, `runesmith`, `spearmen`, `warrior`, `worker` β€” 8 unit types Γ— 2 genders = 16 PNG files. Race id is `dwarf` (singular β€” confirmed in `public/games/age-of-dwarves/data/races.json`); the `Player.race_id` fallback in `unit_renderer.gd:_resolve_race_id()` resolves to that value at runtime.\n\nSlate is clean β€” the 7 previously-authored sprites were deleted 2026-04-17 for quality-bar failure. Do not restore; regenerate via `p2-22` once the pipeline is green." }, { - "id": "p2-23", + "id": "p2-24", "title": "Unit sprites β€” wild creatures & fauna (generic, no race/sex)", "priority": "p2", "status": "missing", @@ -660,7 +650,7 @@ "summary": "Wild creatures in `public/games/age-of-dwarves/data/units/*.json` (entries with `unit_type: \"wild\"`) do not participate in the raceΓ—sex permutation. `UnitRenderer` falls back to `SPRITE_LOOKUP_GENERIC_FORMAT = \"sprites/units/%s.png\"` (`unit_renderer.gd:53`) for them β€” a single sprite per creature id.\n\nThe current wild roster (2026-04-17 snapshot): `ancient_hydra`, `basilisk_wild`, `dire_bear`, `dire_wolf`, `drake_wild`, `elder_wyrm`, `feral_spider`, `fire_imp`, `frostfang_alpha`, `garden_snail`, `lava_elemental`, `shambling_dead`, `stone_sentinel`, `wild_wyvern`, `wolf_pack` β€” 15 creatures, 15 PNG files.\n\nEach is a recognisable silhouette at the renderer's 56Γ—56 hex render size (verified via `sprite_proof.tscn` scaling behaviour established in `p0-23`)." }, { - "id": "p2-24", + "id": "p2-25", "title": "Building sprites β€” base game coverage (non-wonder)", "priority": "p2", "status": "missing", @@ -670,17 +660,17 @@ "summary": "Every standard building declared in `public/games/age-of-dwarves/data/buildings/*.json` (excluding `manifest.json`, `stub.json`, and `mundane_wonders.json`) needs a sprite at `public/games/age-of-dwarves/assets/sprites/buildings/.png`. City-screen UI and, where the world-map eventually surfaces building silhouettes, the renderer both consume these.\n\nCurrent base roster (2026-04-17 snapshot, 10 buildings): `ale_hall`, `barracks`, `bathhouse`, `colosseum`, `forge`, `library`, `marketplace`, `monument`, `temple`, `walls`." }, { - "id": "p2-25", + "id": "p2-26", "title": "Mundane-wonder sprites β€” 24 distinct, higher-fidelity art", "priority": "p2", "status": "missing", "scope": "game1", "owner": "asset-sprite", "updated_at": "2026-04-17", - "summary": "`public/games/age-of-dwarves/data/buildings/mundane_wonders.json` declares 24 Civ5-style world wonders for Game 1 (no magic schools β€” these are mundane flavour wonders). Each needs a **distinct, higher-fidelity** sprite β€” a generic \"fancy building\" look drags the whole wonder system's perceived prestige. Split from `p2-24` so the quality bar can be tracked independently.\n\nCurrent wonder roster (2026-04-17 snapshot): `ancestral_forge`, `mead_hall`, `first_mineshaft`, `clan_moot_stone`, `iron_bulwark`, `hall_of_ancestors`, `the_deep_road`, `bardic_circle`, `archive_of_runes`, `royal_runestone`, `grand_observatory`, `covenant_stone`, `the_great_forge`, `iron_crown`, `undermount_vault`, `hall_of_echoes`, `world_pillar`, `well_of_ages`, `the_undying_flame`, `voice_of_ages`, `silent_cartograph`, `shrine_of_names`, `the_cold_anvil`, `hearthless_hall`." + "summary": "`public/games/age-of-dwarves/data/buildings/mundane_wonders.json` declares 24 Civ5-style world wonders for Game 1 (no magic schools β€” these are mundane flavour wonders). Each needs a **distinct, higher-fidelity** sprite β€” a generic \"fancy building\" look drags the whole wonder system's perceived prestige. Split from `p2-25` so the quality bar can be tracked independently.\n\nCurrent wonder roster (2026-04-17 snapshot): `ancestral_forge`, `mead_hall`, `first_mineshaft`, `clan_moot_stone`, `iron_bulwark`, `hall_of_ancestors`, `the_deep_road`, `bardic_circle`, `archive_of_runes`, `royal_runestone`, `grand_observatory`, `covenant_stone`, `the_great_forge`, `iron_crown`, `undermount_vault`, `hall_of_echoes`, `world_pillar`, `well_of_ages`, `the_undying_flame`, `voice_of_ages`, `silent_cartograph`, `shrine_of_names`, `the_cold_anvil`, `hearthless_hall`." }, { - "id": "p2-26", + "id": "p2-27", "title": "City population-tier sprites β€” city_q1 through city_q5", "priority": "p2", "status": "missing", @@ -689,6 +679,16 @@ "updated_at": "2026-04-17", "summary": "`CityRenderer` looks up a city's sprite via `SPRITE_LOOKUP_CITY_FORMAT = \"sprites/cities/city_q%d.png\"` (`city_renderer.gd:29`) with the quality bucket computed as `clampi(city.population / CITY_QUALITY_BUCKET + 1, 1, CITY_QUALITY_MAX)` β€” five buckets, five PNGs. Tiny scope relative to the other children, but the key format and renderer path are distinct enough to warrant its own objective β€” can flip `done` early." }, + { + "id": "p2-28", + "title": "Sprite provenance ledger β€” LICENSES.md per-file attribution", + "priority": "p2", + "status": "missing", + "scope": "game1", + "owner": "asset-sprite", + "updated_at": "2026-04-17", + "summary": "Every sprite PNG that ships in `public/games/age-of-dwarves/assets/sprites/` must have a corresponding row in `public/games/age-of-dwarves/assets/sprites/LICENSES.md` recording source, license, author, URL, and SHA256. This is a cross-cutting compliance objective that runs continuously alongside the delivery children (`p2-23` … `p2-27`) β€” the ledger is complete exactly when every on-disk sprite has a matching row and every row points at an on-disk file.\n\nCommercial-use compatibility is non-negotiable. AI-generated output must come from a model on the approved list (`juggernaut-xl-v9`, `epicrealism-xl`, `illustrious-xl-v2`, or current equivalent per CLAUDE.md). Commissioned art must have assigned commercial rights in writing." + }, { "id": "g2-01", "title": "Ley lines β€” Game 2 (Age of Kzzykt)", diff --git a/public/games/age-of-dwarves/guide/src/nav.tsx b/public/games/age-of-dwarves/guide/src/nav.tsx index f14310d6..969b5d11 100644 --- a/public/games/age-of-dwarves/guide/src/nav.tsx +++ b/public/games/age-of-dwarves/guide/src/nav.tsx @@ -3,8 +3,10 @@ import episodes from '@resources/episodes.json' // Episode accent colors β€” app navigation branding (UI-only, stays in TypeScript) const EP1_COLOR = '#c07040' // dwarf copper +const EP2_COLOR = '#4a7c59' // kzzykt green +const EP3_COLOR = '#7c5cbf' // elven violet -const [ep1] = episodes +const [ep1, ep2, ep3] = episodes export const NAV: NavGroup[] = [ // ─── Common (cross-episode) ─────────────────────────────────────────────── @@ -113,4 +115,48 @@ export const NAV: NavGroup[] = [ { to: '/playing/lenses', icon: 'πŸ”', label: 'Lenses' }, ], }, + + // ─── Episode 2: Age of Kzzykt β€” The Hive ──────────────────────────────── + { + episodeHeader: { number: 2, name: ep2.display_name, color: EP2_COLOR, link: ep2.route! }, + title: 'Kzzykt & The Hive', + items: [ + { to: ep2.route!, icon: 'πŸ“‹', label: ep2.name }, + { to: '/worlds/the-hive', icon: 'πŸ›', label: 'The Hive' }, + ], + }, + { + title: 'Ley Lines & Magic', + items: [ + { to: '/magic', icon: '🌿', label: 'Magic Overview' }, + { to: '/magic/ley-lines', icon: 'γ€°', label: 'Ley Lines' }, + ], + }, + + // ─── Episode 3: Age of Elves β€” Silvandel ───────────────────────────────── + { + episodeHeader: { number: 3, name: ep3.display_name, color: EP3_COLOR, link: ep3.route! }, + title: 'Elves & Silvandel', + items: [ + { to: ep3.route!, icon: 'πŸ“‹', label: ep3.name }, + { to: '/worlds/silvandel', icon: '🌲', label: 'Silvandel' }, + ], + }, + { + title: 'Schools of Magic', + items: [ + { to: '/magic/schools', icon: 'πŸ“š', label: 'All Schools' }, + { to: '/magic/schools/life', icon: 'πŸ’š', label: 'Life' }, + { to: '/magic/schools/death', icon: 'πŸ’€', label: 'Death' }, + { to: '/magic/schools/chaos', icon: 'πŸ”₯', label: 'Chaos' }, + { to: '/magic/schools/aether', icon: '✨', label: 'Aether' }, + ], + }, + { + title: 'Archons & Ascension', + items: [ + { to: '/magic/archons', icon: 'πŸ‘', label: 'Archons' }, + { to: '/magic/ascension', icon: '🌟', label: 'Arcane Ascension' }, + ], + }, ]