First GPU pass on the rev-3 depth pipeline surfaced two issues; both fixed
and re-rendered clean:
1. Blown near-field highlights (regression from 018909b). Mapping the
nearest pixel to pure white (nearPlane=nearRaw) made the depth
ControlNet render overexposed near floors/ceilings at strength 0.85.
fpv.js: nearPlane=0 (anchor white at the camera; nearest real surface
≈gray 214, headroom intact) + minSpan 5→8. Re-bake confirms the blown
ceiling is gone while recesses still reach black and geometry holds.
2. Phantom doors on closed walls — a PROMPT problem, not the depth map
(present in old maps too). Opening NOUNS in the positive prompt summon
a passage onto solid stone: threshold's "gatehouse, portcullis,
entrance" painted a gate on a blank wall, and at cfg 1.0 the negative
can't cancel it. bake_atlas.py: THEME_BODY_CLOSED (full theme flavor,
zero opening nouns) for closed facings + opening-nouns negated on
closed facings only. r0_N (threshold) now renders clean ashlar wall.
("Bricked-up archway" backfires — "archway" alone re-summons the arch.)
Also: sweep_strength.py re-exec-under-venv guard (the venv python is a
symlink to the base interpreter, so the realpath check wrongly skipped
the hop and the montage died after every render); now env-sentinel
guarded. Findings in .dev/2026-06-15-diffusion-pipeline-reliability.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
--alt-work renders each test frame from a second depth dir alongside the
new full-range maps, so the GPU run proves the rev-3 normalization fix
(018909b) beats the washed-out rev-2 maps rather than just looking
better. Persisted the rev-2 maps under tools/out/compare/rev2_depths so
the A/B is reproducible. Doc updated with the one-shot command.
Workstation note: host 192.168.1.26 is up but ComfyUI (:8188) wasn't
running this iteration — needs a manual start before the sweep.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
sweep_strength.py renders one open + one closed FPV frame across a
ControlNet strength matrix at fixed seed/prompt and montages them beside
the depth map — the GPU experiment to find the right strength now that
rev-3 depth maps carry a full-range signal (018909b). Findings/plan in
.dev/2026-06-15-diffusion-pipeline-reliability.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
All 208 frames of seeds 7/69/59, rendered with per-direction cameras
(directedVantage: gap-centered when open, close + off-axis when walled,
per-class wall seed) and dithered through the speckle-free rev-2 recipe
(sRGB-spaced LUT, gamut-clamped diffusion, --overshoot 6).
Walls no longer grow phantom doors; the passage you walk is the passage
you see; shadows are warm stone instead of green confetti.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Parley's review: dither full of green spots, baked rooms don't match the
nav graph (doors painted on closed walls, real openings off-center).
Both root-caused:
- pixelate.py: the nearest-color LUT was spaced in LINEAR RGB, cramming
the whole shadow range into ~4 cells — dark picks were effectively
arbitrary (green/teal confetti in warm near-blacks). LUT is now
sRGB-spaced, diffusion error is gamut-clamped (no more blue blobs at
torch highlights), and a new --overshoot penalty forbids choosing a
color more saturated than the source. Green-dominant dark pixels on
the test frame: 5.2% -> 0.02%, while palette usage went UP (107 -> 135
colors). Recipe rev 2: append --overshoot 6.
- fpv.js: new directedVantage(env, region, dir) — per-(room,facing)
camera instead of one room-wide vantage. Open ahead: stand in a cell
whose straight-ahead ray escapes through the actual gap (the passage
you walk is centered, 2-7 cells deep). Closed ahead: stand ~2 cells
from the wall, deliberately OFF the room's axis — a symmetric stage
begs the model to paint a centered focal door; an off-axis dead-end
corner doesn't. Walls also render under their own fixed seed and an
emphatic sealed-masonry prompt clause (cfg 1.0 negatives are inert).
Validated on seed 7 room 1: the closed-N phantom door is gone; the open-S
passage is dead-center. Full campaign re-bake follows as its own commit.
Also: rest-overlay no longer sticks without a keyup, in-combat drink
message, feathered sprite mask, no monster packs on floor 1.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The pieces finally meet: procgen dungeons + the baked EoB atlas pipeline +
the Vigor combat engine become one game. Three fixed pre-baked floors
(seeds 7 → 69 → 59, 208 frames), monsters/loot/encounters rerolled per run
and composited over the empty scenes; the Ember Sovereign waits at the
bottom.
- game-wasm: run state machine in Rust (manifest nav graph as dungeon
truth, seeded spawning by theme/depth, embedded combat-core Encounter,
vigor/fatigue persistence between fights, rest/potions/relics/flee,
permadeath + victory). 8 native tests incl. a whole-run bot and a
ScriptedPlayer boss-winnability probe used for tuning.
- game-web: no-framework front-end — title/death/victory screens, baked
frames with screen-blend monster portraits, combat overlay (dual vigor
bars, cast telegraphs, cooldown sweeps, floaters), minimap with fog,
all SFX synthesized in WebAudio.
- balance: floor-scaled levels with a hero's edge over trash, no packs on
floor 1, boss tuned by sim sweep (~35%/55% win at skill 50/80).
- campaign atlases now versioned (tools/.gitignore exception); boss
portrait added to the Z-Image roster.
Verified end-to-end in-browser: an autopilot beat the full game through
the real UI (10 fights, 2 flees, Sovereign down), and died plenty before
that.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Render actual generated dungeons through the AI pipeline — both top-down and
first-person (Eye-of-the-Beholder style) — instead of synthetic test depth.
All renderer-side: derived from the envelope's tiles+regions+theme, the core
stores none of it.
- depth.js: top-down height-field depth exporter (walls raised, pools recessed,
pillars as bumps, subtle per-theme relief), calibrated to the proven room_depth
levels so one tall room can't crush every floor dark.
- fpv.js: first-person depth via a Wolfenstein-style grid raycaster (16:9),
reports straight-ahead distance for opening detection.
- explore.js: room->room nav graph derived from REAL tile openings (scan
boundary gaps, bin by cardinal, flood the corridor to the destination room) —
nav + open share one source of truth with the rendered passages.
- bake_atlas.py: bakes per-room x4-facing pixel-art frames; per-theme + per-facing
(wall vs passage) prompts, fixed diffusion seed for cross-frame style coherence,
per-run unique prefixes so re-bakes don't silently skip.
- explore.html + explore-viewer.js: WASD first-person dungeon explorer
(room-to-room movement, turning, minimap), integer-pixel fullscreen.
- serve.py: stdlib dev server — static web root + /out tree + POST /save, no-store.
- main.js/render.js/style.css: export hooks, the depth button, distanceToWall export.
- tools/README.md: Stage 0/1/2/3 docs; .dev/2026-06-01-fpv-prompts.md: prompt
research (cfg-1 negatives are inert; trigger words summon hands; empty-ruin
reframe; fixed seed = consistency).
Proven end-to-end on seed 7 (17 rooms). Outputs organized under git-ignored
tools/out/. Control strength: 0.80-0.85 top-down, 0.85 first-person.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>