feat(@projects): ✨ add world-map visual proof scene documentation
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
bff4c1dc46
commit
f783d24dc7
3 changed files with 142 additions and 2 deletions
133
.project/objectives/p2-66-world-map-visual-proof.md
Normal file
133
.project/objectives/p2-66-world-map-visual-proof.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
---
|
||||
id: p2-66
|
||||
title: "World-map visual proof scene that actually renders"
|
||||
priority: p2
|
||||
status: stub
|
||||
scope: game1
|
||||
category: tooling
|
||||
owner: godot-renderer
|
||||
created: 2026-05-10
|
||||
updated_at: 2026-05-10
|
||||
blocked_by: []
|
||||
follow_ups: []
|
||||
---
|
||||
|
||||
## Context
|
||||
|
||||
`src/game/engine/scenes/tests/iter_7q_worldmap_visual_proof.tscn` is the
|
||||
canonical "boot a real game session and screenshot the world map" proof
|
||||
scene used by the phase-gate protocol. Today it produces a fully-black
|
||||
1920×1080 frame even after the prerequisite fixes below, so the
|
||||
proof-screenshot rail (`tools/screenshot.sh` / direct flatpak launch)
|
||||
cannot validate the gameplay surface against `HEX_GEOMETRY.md` and the
|
||||
worldmap-rendering design docs.
|
||||
|
||||
Two prerequisite fixes that landed during the 2026-05-10 demo run while
|
||||
diagnosing this:
|
||||
|
||||
- `tools/screenshot.sh` — added `--socket=wayland`,
|
||||
`--filesystem=xdg-run/<socket>`, `--env=WAYLAND_DISPLAY`,
|
||||
`--display-driver wayland --rendering-driver opengl3`. flatpak
|
||||
sandboxes outer env by default, so the previous version could never
|
||||
reach a working Wayland display from a fresh ssh session. Without
|
||||
this nothing in the proof-scene capture rail worked.
|
||||
- `iter_7q_worldmap_visual_proof.gd` — added
|
||||
`ThemeAssets.set_theme("age-of-dwarves")`. `main.gd` calls this on
|
||||
app boot but proof scenes that bypass `main.gd` did not.
|
||||
- `theme_assets.gd::load_sprite()` — added SVG fallback. Renderers
|
||||
request `.png` paths but `tools/gen-fallback-sprites.py` emits SVG.
|
||||
The mismatch was silently breaking sprite loading for any proof
|
||||
scene that bypasses the editor-imported asset path.
|
||||
|
||||
After all three fixes, sprite loads succeed (no `FAILED to load`
|
||||
warnings except the one Game-3-only `tower_of_wizardry` icon) but
|
||||
`get_viewport().get_texture().get_image()` still returns a black image.
|
||||
|
||||
## Root cause (provisional)
|
||||
|
||||
The active warning during instantiation is:
|
||||
|
||||
> Can't change the size of a `SubViewport` with a `SubViewportContainer`
|
||||
> parent that has `stretch` enabled. Set `SubViewportContainer.stretch`
|
||||
> to `false` to allow changing the size manually.
|
||||
|
||||
`world_map.tscn` mounts a `ViewportWindowManager` (`Control`) child
|
||||
that creates SubViewports (background / split / floating tiers — see
|
||||
`src/ui/viewport_window_manager.gd`). When `world_map.tscn` is the
|
||||
**main scene** the Control fills the window naturally. When iter_7q
|
||||
calls `add_child(WorldMapScene.instantiate())` from a `Node2D` parent,
|
||||
the Control has no stretched parent, the SubViewports cannot resize,
|
||||
and the composited output is empty.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- ❌ `iter_7q_worldmap_visual_proof.tscn` produces a non-black image
|
||||
with hex sprites visible at seed 42, duel size, 2 players, default
|
||||
start position centered.
|
||||
- ❌ Image is reproducible from a fresh ssh session via the canonical
|
||||
command in this objective's "Reproducer" section.
|
||||
- ❌ Phase-gate protocol can use the resulting frame as the proof
|
||||
screenshot for any HEX_GEOMETRY / worldmap-rendering closure.
|
||||
|
||||
## Three fix paths (pick one)
|
||||
|
||||
1. **Make iter_7q a proper top-level `Control` with stretch.**
|
||||
Restructure the proof scene so its root is a `Control` filling the
|
||||
window; instantiate `world_map.tscn` as a child of that. Lowest
|
||||
risk; does not touch world-map architecture. Likely 30 min.
|
||||
|
||||
2. **Capture the SubViewport texture directly.**
|
||||
In `_capture_and_quit`, walk to the background `SubViewport` (via
|
||||
`_viewport_manager.get_background_viewport()` or similar) and call
|
||||
`.get_texture().get_image()` on it instead of the main viewport.
|
||||
Useful regardless of whether world_map is hosted as main scene or
|
||||
child. Surgical; doesn't change rendering behavior.
|
||||
|
||||
3. **Refactor world_map to render to the main viewport directly.**
|
||||
Drop the SubViewport tiering for the bench/headless path. Largest
|
||||
blast radius; touches production rendering and hud composition.
|
||||
Avoid unless 1 + 2 both fail.
|
||||
|
||||
## Reproducer (current failing path)
|
||||
|
||||
```
|
||||
ssh apricot 'XDG_RUNTIME_DIR=/run/user/$(id -u) timeout 90 \
|
||||
flatpak run --user --socket=wayland --filesystem=xdg-run/wayland-proof \
|
||||
--unset-env=DISPLAY --env=WAYLAND_DISPLAY=wayland-proof \
|
||||
org.godotengine.Godot \
|
||||
--path ~/Code/project-buildspace/magic-civilization/src/game \
|
||||
--display-driver wayland --rendering-driver opengl3 \
|
||||
--rendering-method gl_compatibility --fixed-fps 10 \
|
||||
res://engine/scenes/tests/iter_7q_worldmap_visual_proof.tscn'
|
||||
```
|
||||
|
||||
Captures `iter_7q_worldmap_visual_*.png` in flatpak userdata
|
||||
`screenshots/`. Today the file is a fully-black 1920×1080 PNG.
|
||||
|
||||
## Source-of-truth rails
|
||||
|
||||
- **Rust crate**: none — pure presentation.
|
||||
- **JSON path**: depends on `ThemeAssets.set_theme()` reading
|
||||
`public/games/age-of-dwarves/data/`; sprite fallback writes
|
||||
`public/games/age-of-dwarves/assets/sprites/{terrain,units}/*.svg`.
|
||||
- **GDScript**: `iter_7q_worldmap_visual_proof.gd` and
|
||||
`viewport_window_manager.gd` are the two files in scope.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Generating PNG sprite assets (Game-1 ships with SVG fallback per
|
||||
`theme_assets.gd` change in this same session).
|
||||
- Production sprite-pack delivery — separate Game-1 art ticket.
|
||||
- Fixing `capture_screenshot.gd`'s `world_map` handler that bounces
|
||||
back to the main menu — different bug, different scene path.
|
||||
|
||||
## References
|
||||
|
||||
- `src/game/engine/scenes/tests/iter_7q_worldmap_visual_proof.gd`
|
||||
- `src/game/engine/scenes/world_map/world_map.tscn`
|
||||
- `src/game/engine/scenes/world_map/world_map.gd:271` (`_start_game`)
|
||||
- `src/game/engine/src/ui/viewport_window_manager.gd`
|
||||
- `src/game/engine/src/autoloads/theme_assets.gd:50` (loader paths)
|
||||
- `tools/gen-fallback-sprites.py` (SVG output pipeline)
|
||||
- `tools/screenshot.sh` (flatpak Wayland fix this session)
|
||||
- `.claude/instructions/phase-gate-protocol.md` (why this matters)
|
||||
|
|
@ -1,6 +1,11 @@
|
|||
extends Node2D
|
||||
extends Control
|
||||
## Iter 7q — Real world_map visual Phase Gate.
|
||||
##
|
||||
## Root is `Control` (not `Node2D`) so the world_map SubViewportContainer
|
||||
## children can stretch to the window — `Node2D` parents leave SubViewports
|
||||
## unsized and the composited frame renders fully black under headless
|
||||
## llvmpipe (see p2-66 "World-map visual proof scene that actually renders").
|
||||
##
|
||||
## Programmatically runs the full New Game flow:
|
||||
## 1. Load theme + world
|
||||
## 2. Initialize game state
|
||||
|
|
|
|||
|
|
@ -2,5 +2,7 @@
|
|||
|
||||
[ext_resource type="Script" path="res://engine/scenes/tests/iter_7q_worldmap_visual_proof.gd" id="1"]
|
||||
|
||||
[node name="Iter7qVisualProof" type="Node2D"]
|
||||
[node name="Iter7qVisualProof" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource("1")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue