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>
Adds RegionTheme + RoomThemer: a pure classifier (no tile changes) that
labels each room (terrain-driven Forge/Cistern/Hall, special Throne/
Threshold, weighted Crypt/Den/Library/Vault/Stone). Renderer tints themed
rooms; EntityPlacer biases contents by theme. Entrance/exit now chosen
RNG-free from geometry so themer & placer agree.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The roadmap capstone: the dungeon is now populated.
- New entity layer: src/entity.rs (Entity { kind, at }, EntityKind {Entrance,
Exit, Treasure, Monster}); Map gains an `entities: Vec<Entity>` overlay field
(serde round-tripped). Entities aren't terrain, so no new Tile and the frozen
viz is untouched.
- EntityPlacer/EntityConfig: places one Entrance (random room), one Exit (the
room farthest from it — a traversal goal), per-room Treasure (treasure_chance)
and Monsters (monster_chance, 1..=max, never in the entrance room). All on
plain Floor only, never two per cell, fully deterministic.
- Handoff via the Blackboard (the designed side channel for non-tile/region/edge
data) under entity::BLACKBOARD_KEY, harvested by Pipeline into Map.entities —
so GenContext's 25 literals stay untouched.
- Renderer draws iconic markers on the final stage: green beacon (entrance),
cyan portal (exit), gold diamond (treasure), crimson eyed-blob (monster), each
with a soft glow. New entities toggle + treasure/monster sliders + readout.
Core: 135 tests green (6 new: one entrance/one exit on distinct floor, entrance
room monster-free, determinism, empty-map, recipe populated-check). clippy
clean. Pipeline is now 9 passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Seventh pass (before pillars): floods an organic blob of Water or Lava into
some larger rooms via randomized BFS growth.
- New Tile::Water / Tile::Lava (impassable hazards). Exhaustive matches updated
(ascii '~'/'!', frozen viz colors, wasm codes 4/5).
- PoolDecorator/PoolConfig (water_chance, lava_chance, min_room): blob is
interior-only (>= 2 from edge, never the center), and a connectivity guard
verifies the room's remaining floor stays 4-connected with the center intact
before committing — so a pool never orphans part of a room.
- DungeonConfig gains `pools`; recipe inserts PoolDecorator after DoorPlacer.
- Renderer: water as cool reflective pools; lava as molten rock that ALSO
throws warm light onto nearby floor (BFS light field, wall-blocked) — lava
chambers visibly glow. New water/lava sliders.
Core: 125 tests green (4 new: interior placement, floor stays connected,
zero/small-room skip, determinism); connectivity holds with pools in the
default recipe. clippy clean (core + viz).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A finishing decorator that scatters free-standing pillar columns into larger
rooms on a spaced interior grid. Sixth pass in the dungeon recipe.
- New Tile::Pillar (impassable like Wall, drawn distinctly). Exhaustive matches
updated: ascii ('o'), frozen macroquad viz (still compiles), wasm code 3.
- PillarPlacer/PillarConfig (room_chance, min_room, spacing): places isolated
single-cell pillars only on interior room floor (>= 2 from the edge, never the
center), on a grid with spacing >= 2 — so the floor stays 4-connected by
construction and a room is never orphaned. Respects non-rect room shapes
(pillars land only on actual carved floor).
- DungeonConfig gains `pillars`; recipe appends PillarPlacer after DoorPlacer.
- Renderer draws pillars as lit stone columns with a contact shadow; new
"pillars" density slider.
Core: 121 tests green (5 new: interior-only placement, floor stays connected,
zero-chance/small-room skip, determinism). clippy clean (core + viz).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Renderer-only: low-frequency stone mottling (per ~4x4 block) with faint grain
instead of high-frequency per-cell noise; room glow now warms toward amber so
lit chambers read as torch-lit while corridors fall to shadow. Stronger
room/corridor light contrast.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 0+1 of the browser viz effort:
- core: drop unused `rand` dep (removes getrandom/libc → clean wasm32 build);
derive serde on DungeonConfig + 5 sub-configs so the bridge can (de)serialize
- reikhelm-wasm: thin wasm-bindgen cdylib exposing generate(seed, config_json)
-> JSON envelope (tiles as int codes, regions, edges, per-pass snapshots) and
default_config_json(); holds no generation logic
- workspace: add reikhelm-wasm member; default-members keeps host cargo
test/clippy on core+viz only
- reikhelm-web: vanilla-JS + Canvas 2D renderer running the real core live in
the browser. Atmospheric look — lit stone floor, raised stone walls with
rim-lit carved edges + top bevel, room light-pooling, amber door thresholds,
vignette. Controls: seed/reroll, 9 config sliders, stage scrubber, semantic
overlays (region outlines / graph / grid). window.reikhelm hooks for
Playwright-driven iteration.
Core stays 115 tests green. Driven + screenshotted via Playwright MCP.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>