magicciv/.project/objectives/p2-62-procedural-unit-and-building-renderer.md
Natalie 4106baed10 fix(@projects/@magic-civilization): 🐛 update p2-62 status and dashboard entries
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-05-04 03:12:49 -04:00

4.8 KiB

id title priority status scope owner updated_at evidence blocked_by
p2-62 Procedural unit/building renderer — alpha-only visual substitute p2 done game1 asset-sprite 2026-05-04
src/game/engine/src/world/procedural_renderer.gd:79-153 (render_unit/render_building wrappers + make_*_texture surface)
src/game/engine/src/world/procedural_renderer.gd:64-69 (MC_USE_PROCEDURAL_SPRITES toggle)
src/game/engine/src/rendering/unit_renderer_draw.gd:173-215 (procedural fallback wiring)
src/game/engine/tests/unit/test_procedural_renderer.gd:132-148 (20-id pixel-identical determinism gate; 16/16 tests pass on apricot)
src/game/engine/scenes/tests/procedural_renderer_proof.tscn (proof scene)
~/Desktop/magic_civ_p2-62_procedural_renderer.png (proof screenshot, 20 units / 10 buildings / 5 wonders / 5 cities)
src/game/engine/docs/PROCEDURAL_RENDERER.md (visual conventions doc)

Context

This exists so alpha doesn't block on sprite generation. The full sprite pipeline (p2-22..p2-27) authors hand/AI-generated sprites for every unit, building, wonder, and city; that work is non-trivial and currently deferred. This objective ships a parametric procedural renderer — deterministic shapes/colors/insignia derived from each entity's id — so the alpha is fully playable visually without blocking on asset production.

The procedural renderer and the sprite pipeline will coexist behind a boot-time toggle (MC_USE_PROCEDURAL_SPRITES=1) so designers can A/B them when sprite assets land.

Acceptance

  • src/game/engine/src/world/procedural_renderer.gd (canonical layout uses src/, not scripts/) exposes render_unit(unit_id) -> Texture2D and render_building(building_id) -> Texture2D (thin wrappers at lines 79-86) over the broader make_unit_texture / make_building_texture / make_wonder_texture / make_city_texture surface (lines 91-153). Output keyed deterministically off id via _stable_hash (line 158): hash(s) & 0x7fffffff. Race colour pulls from public/resources/races/<race_id>.json with an 8-colour fallback palette when race is unknown.
  • MC_USE_PROCEDURAL_SPRITES resolved via OS.get_environment in is_force_procedural() (procedural_renderer.gd lines 64-69) and consulted by the renderer's wiring point in unit_renderer_draw.gd::cache_unit_sprites (lines 173-178) and get_unit_sprite (lines 200-211). When 1 the authored sprite path is skipped entirely; when unset/0, authored sprites win and procedural is the missing-asset fallback. No EntityVisualRegistry shim was introduced — the codebase has no such registry; the integration point is the existing UnitRenderer cache hook, documented in engine/docs/PROCEDURAL_RENDERER.md.
  • ✓ Distinct silhouettes per role classified by unit_id substring (_classify_unit_role, lines 174-198): warrior=sword, archer=bow+arrow, scout=triangle, worker=hammer, founder=house, wagon=body+wheels, cavalry=lance, siege=engine+barrel, naval=hull+mast, generic=seed dot pattern. Race colour drives the base disk; gender insignia (Venus/Mars/neutral glyph) sits in the top-left corner (_paint_gender_insignia, lines 348-360). Proof screenshot shows all 20 distinguishable at a glance: ~/Desktop/magic_civ_p2-62_procedural_renderer.png.
  • ✓ Buildings: trapezoid wall + triangle roof + door + 1-3 windows, roof colour by category from BUILDING_CATEGORY_COLOURS (8 categories, line 32). Wonders: 3 distinct shape families (tower / dome / ziggurat, line 142) plus an amber halo disk (_paint_wonder_halo, line 397) — visible behind every wonder in the proof screenshot.
  • ✓ Headless GUT — tests/unit/test_procedural_renderer.gd::test_twenty_unit_ids_pixel_identical_across_calls (lines 132-148) renders 20 known unit ids twice (cache cleared between calls) and asserts pixel-identical bytes via Image.get_data() comparison. Full suite: 16/16 tests pass, 42/42 asserts on apricot Godot 4.6.2 headless — confirmed run on canonical checkout, isolated with -gprefix=test_procedural.

Source-of-truth rails

  • Rust crate: none — this is presentation-only and explicitly carved out from Rail 3 because no simulation logic is involved. Procedural seed comes from the entity's id string hashed in GDScript.
  • JSON path: reads public/resources/units/*.json and public/resources/buildings/*.json for the id and (optionally) a category hint to pick a visual family. No new authored data.
  • mc-core wrapper: not applicable — render is GDScript-internal.

Out of scope

  • Sprite-asset pipeline (p2-22..p2-27) — that's the eventual replacement; both can coexist.
  • Animation — static texture only.
  • City/wonder vignettes — flat token render only.

References

  • public/games/age-of-dwarves/docs/UI_DESIGN.md
  • Replaced-by (eventually): p2-22, p2-23, p2-24, p2-25, p2-26, p2-27