feat(client): add visual test harness with golden regression

Gives Claude eyes: `make screenshot` captures a rendered frame,
`make test-visual` compares against golden PNGs, `make visual-update`
regenerates goldens. Built to debug the Sprint 22 fog regression and
prevent future visual regressions across fog, HUD, dialogue, and UI.

Config-driven via tests/visual.json (11 scenarios, 2 flows).
Capture engine boots main.tscn with real GPU rendering (not --headless),
waits for NoiseTexture2D async gen, uses deterministic shader time.

Components:
- visual_capture.gd: SceneTree capture engine (scenario + movie modes)
- visual_scenarios.gd: per-scenario setup hooks
- tooling/visual-diff: pixel comparator (PIL primary, struct fallback)
- tooling/visual-thumbnail: contact sheet + crop tool
- tests/run-visual: suite script (xvfb wrapping, golden workflow)
- fog_state.gd: override_time for deterministic captures
- fog_shader.gd: fog_noise_ready signal for settle sequencing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 16:33:55 +01:00
co-authored by Claude Opus 4.6
parent 8ac904fe69
commit 6bcdc48412
10 changed files with 1323 additions and 3 deletions
+5
View File
@@ -52,6 +52,11 @@ var _prev_visible: Dictionary = {} # Tiles visible last frame (for incremental
## Toggle via FogState.debug_exploration = true in the console.
var debug_exploration: bool = false
## Deterministic shader time for visual test captures.
## When >= 0, fog_shader.gd uses this instead of Time.get_ticks_msec().
## Set before settle frames so noise phase is reproducible across runs.
var override_time: float = -1.0
func _ready() -> void:
_resize(Rect2i(0, 0, 64, 64))