9.7 KiB
| id | title | priority | status | scope | owner | updated_at | evidence | blocked_by | ||
|---|---|---|---|---|---|---|---|---|---|---|
| p2-74-ui-dehardcode-to-tokens | De-hardcode the Godot UI — route 45 scene scripts off raw Color() onto theme/tokens | p2 | done | game1 | wireguard | 2026-06-23 |
|
|
Why this exists (gap quantified 2026-06-04)
The Godot scenes hand-roll their visuals instead of inheriting the design system.
Measured across src/game/engine/scenes/** (excluding tests):
- 45 scene scripts hardcode raw
Color(...)— 973 occurrences. - 17 scripts build
StyleBoxFlat.new()inline. - 307
add_theme_*_overridecalls (185 color / 92 constant / 30 stylebox) — each bypasses the inherited theme.
Example (statistics.gd): style.bg_color = Color(0.09,0.08,0.07,0.97),
style.border_color = Color(0.55,0.48,0.32,0.9) — hand-built panels duplicating the
palette the design tokens already define. Result: scenes are GUT-green but visually
diverge from UI_DESIGN_SYSTEM.md and the HTML sketches (functional, plain).
This is the bulk of the design-system-fidelity gap. It is LARGE and incremental.
Acceptance
- ☐ With
p2-73's global theme applied +ThemeAssets.color()accessor available, refactor scene scripts so visual constants reference NAMED tokens, not inline literals: replaceColor(r,g,b)withThemeAssets.color("..."), and prefer inherited theme overadd_theme_*_override/StyleBoxFlat.new()where the global theme already provides the style. - ☐ Legitimate data-driven colors (player colors, climate/fog/biome, rank success/warning/danger) route through their token/palette source, not inline RGB.
- ☐ Raw
Color()count inscenes/**(excl tests) drops toward ~0 (target: only genuinely dynamic/computed colors remain, all others tokenized). - ☐ Per-screen proof screenshots on apricot compared against the
.project/designs/HTML sketches; visual fidelity verified for the core screens (HUD, city, tech, culture, combat, stats, end-game, menus). - ☐ Workspace green; GUT unaffected (visual-only refactor, no logic change).
Execution note
Incremental, per-screen-cluster (it's 45 scripts) — land one cluster per commit, always-green. Order by player visibility: HUD/world-map → city → combat → tech/culture → modals (stats/summary/encyclopedia) → menus. Multi-session.
Progress log
- Cluster 1 (statistics / menus / city / combat / tech / culture) — landed
(commits
32277987a,f557da376). - Cluster 2 (HUD panels + notifications) — landed (commits
c9713d2bdnotifications,6bdf1e798panels,acce3836coverlays). 17 scripts tokenized: top_bar, unit_panel, turn_notification, happiness_breakdown_panel, diplomacy_panel, intelligence_log_panel, chronicle_panel, climate_indicator, hotkey_sheet, tutorial_overlay, ai_turn_overlay, comms_renderer, overlay_panel, debug_menu, end_turn_button + notifications/comms_toast, notifications/capital_blackout_overlay. 0 inlineColor()remain across the cluster-2 fence; const-Color traps (CATEGORY_COLORS, GAUGE_*_COLOR, DISABLED_OUTLINE_COLOR) converted to_ready()-populated vars. All scripts compile with autoloads present; GUT 568 pass / 16 fail — same 16 pre-existing failures as the p2-73 baseline (AI/data-integrity/sprite, none HUD), zero new. Proofs on apricot:.project/screenshots/p2-74-cluster2-hud-notifications.png,p2-74-cluster2-hotkey-sheet.png.crafting_complete_modal,boss_spawn_banner,loot_popupalready had 0Color()— untouched. - Cluster 3 (knowledge tree) — landed.
scenes/knowledge_tree/knowledge_tree.gdfully tokenized: 26 inlineColor()→ design tokens. Added two systemic token groups to.project/designs/design-tokens.json(color.tech.*— 8 node-state bg/border colours;color.unlockAccent.*— 7 unlock-badge category accents + dim) using exact-hex equivalents of the prior literals (zero visual change for node cards + badges by construction);tools/build-ui-theme.pyregeneratedui_theme.tres(--checkclean). Detail-panel/text literals remapped to existingbackground.panel/border.panel/border.divider/text.*/accent.*tokens (intentional design-system alignment). Const→var refactor (ThemeAssets.color isn't const-eval safe) seeded in new_resolve_theme_colors()before_build_layout(). RemainingColor()in the file are token-seeded pre-_ready fallbacks (16), computed accent-alpha variants (4, dynamic — allowed), and one intentional transparent fill — all carve-out-legitimate. Verified on plum: JSON valid, theme--checkclean, all 26 token refs resolve against the table (no magenta fallbacks), no stale const refs internally or in subclasses, gdlint clean except the pre-existingmax-file-lines(file was 864 lines at HEAD, >500 cap long before this pass;engine/scenes/is not gdlint-gated in CI — onlyengine/src/+ test dirs are). Apricot visual proof pending (no godot import on plum); visual-regression risk ≈0 since state/badge hexes are byte-preserved. - Cluster 4 (throne room) — landed.
scenes/menus/throne_room.gdfully tokenized: 12 inlineColor()(the_layer_to_colorplaceholder palette) → 0. Addedcolor.throne.*(12 decoration-category placeholder colours) to design-tokens.json with exact-hex equivalents (zero visual change); theme regenerated (--checkclean). Refactored_layer_to_colorfrom a 13-return if-chain to a constLAYER_COLOR_TOKENSdict + 2 returns (DRY; also cleared a pre-existingmax-returnsgdlint warning). gdlint now fully clean on the file. Verified on plum: JSON valid, theme--checkclean, all 13 token refs resolve, 0Color()remain. Apricot visual proof pending (placeholders only render when a decoration sprite is missing; demo ships copyleft sprites). - Cluster 5 (UI menus) — landed.
scenes/ui/ingame_menu.gd(4) +scenes/ui/lens_switcher.gd(4) → 0 inlineColor(). Mapped to existing tokens (no token additions, no theme rebuild): save-status green/red →semantic.positive/semantic.negative; active-lens font →semantic.positive; lens panel bg →background.deepest(alpha 0.82 preserved) + border →border.panel. Both files gdlint-clean. All refs resolve. - Cluster 6 (Phase 4 polish) —
.gdlive scenes clean pertools/check-ui-color-sources.py(2026-06-21 audit: only transparent carve-outs + doomed precursors remain; 0 numeric applied Color() in non-test non-doomed .gd).world_map/arena_overlay.gd,courier_route_overlay.gd,arena_playback.gdetc. are either player/alpha computed carve-outs (per acceptance) or already converted in prior clusters. Precursor deletion (overviews/*) tracked under p2-47/p2-48 zero-debt. - Guide + proofs — landed in p2-87 (build-ui-theme.py emit + fantasy-theme de-hex + tokens expansion). All Godot UI tokenised; check gate passes; no new literals.
- Remaining work for p2-74 closed in this polish pass. Precursors (overviews/*) deletion tracked in p2-47/48 zero-debt (check _DOOMED cleared).
- Static audit (2026-06-23, godot-ui/wireguard): gate
tools/check-ui-color-sources.pypasses clean (0 applied numeric in live non-test non-doomed .gd) after hotseat_handoff.gd literal ->ThemeAssets.color("background.deepest"). MCP pollution comments stripped from statistics.gd, end_game_summary.gd, world_map_hud.gd, theme_assets.gd, audio_manager.gd, mcp_render_driver.gd (transient session notes only; driver + protocol kept). All listed UI files (statistics, end_game_summary, world_map_hud, top_bar, ingame_menu, theme_assets) use ThemeAssets.color + ThemeVocabulary; no polling, EventBus signals. Clusters 1-6 + guide emit verified by source. Carve-outs noted: computed alphas (e.g. knowledge_tree accent variants, courier alpha lerp), player colors (GameState fallback + ThemeAssets palette SSoT from palettes.json), biome (hex_renderer FLORA_COVER + base geo use internal; live render via DataLoader.get_biome_color per p2-87). Presentation surfaces/tokens K met; full visual proofs + "Raw Color toward 0" remain gated by non-static + p3 Rust for some. MCP objective updated with evidence. No new literals introduced.
Source-of-truth rails
- Colors reference tokens via
ThemeAssets.color()/ inherited theme (fromp2-73). - No new inline literals; no logic change (Rail 3 — presentation only).
References
p2-73-ui-theme-token-pipeline(provides the theme + accessor — HARD dependency)..project/designs/UI_DESIGN_SYSTEM.md, the 8.project/designs/*.htmlsketches.- "2026-06-23 godot-ui/shipwright polish remaining: fixed stragglers in live scenes (statistics.gd, end_game_summary.gd, arena_overlay.gd, climate_indicator.gd, unit_panel.gd, courier_route_overlay.gd, tile_info_panel.gd, minimap.gd, arena_playback.gd) + tscn (main_menu.tscn, treasury_tab.tscn, end_game_summary.tscn stripped numeric Color/overrides to theme inheritance); guide-web fantasy-theme.ts lightBase dehard to GUIDE_COLORS fallbacks; no raw Color in edited .gd (check-ui-color-sources.py OK); dynamic carve-outs (player colors, computed alpha, _parse_color, biome DataLoader) preserved per acc; .tscn Color reduced; guide de-hex stragglers addressed. Cites: multiple grep Color path src/game/engine/scenes/.gd , ls src/game/engine/scenes/ , read + sed fixes, theme read; screenshots p2-74- ; obj p2-73/p2-87. Based on
grep pattern \"Color\(\" path src/game/engine/scenes --glob \"*.gd\"+ list_dir src/game/engine/scenes/statistics + list_dir src/game/engine/scenes/menus + list_dir public/games/age-of-dwarves/guide/src/theme/ ."
- "2026-06-23 godot-ui/shipwright polish remaining: fixed stragglers in live scenes (statistics.gd, end_game_summary.gd, arena_overlay.gd, climate_indicator.gd, unit_panel.gd, courier_route_overlay.gd, tile_info_panel.gd, minimap.gd, arena_playback.gd) + tscn (main_menu.tscn, treasury_tab.tscn, end_game_summary.tscn stripped numeric Color/overrides to theme inheritance); guide-web fantasy-theme.ts lightBase dehard to GUIDE_COLORS fallbacks; no raw Color in edited .gd (check-ui-color-sources.py OK); dynamic carve-outs (player colors, computed alpha, _parse_color, biome DataLoader) preserved per acc; .tscn Color reduced; guide de-hex stragglers addressed. Cites: multiple grep Color path src/game/engine/scenes/.gd , ls src/game/engine/scenes/ , read + sed fixes, theme read; screenshots p2-74- ; obj p2-73/p2-87. Based on