reikhelm/.dev/2026-05-28-procgen-map-core
Parley Hatch 3232cf3d09 chore: record Task 12 + integration stress results (core complete)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-28 22:29:14 -06:00
..
spec chore: scaffold reikhelm cargo workspace (core + viz crates) 2026-05-28 20:56:24 -06:00
state chore: record Task 12 + integration stress results (core complete) 2026-05-28 22:29:14 -06:00
tasks chore: scaffold reikhelm cargo workspace (core + viz crates) 2026-05-28 20:56:24 -06:00
dependencies.md chore: scaffold reikhelm cargo workspace (core + viz crates) 2026-05-28 20:56:24 -06:00
files.md chore: scaffold reikhelm cargo workspace (core + viz crates) 2026-05-28 20:56:24 -06:00
README.md chore: scaffold reikhelm cargo workspace (core + viz crates) 2026-05-28 20:56:24 -06:00

reikhelm — Procedural 2D Map Generator: Implementation Plan

Goal: Build a Rust Cargo workspace whose pure reikhelm-core library generates deterministic 2D dungeon maps from composable passes, with a reikhelm-viz macroquad binary that renders them interactively.

Architecture: reikhelm-core is a pure library (no rendering deps) layered as geometry → Grid<T> → semantic regions + connectivity graph → a GenContext/Pass/Pipeline engine → a vocabulary of passes (Partitioner / Shaper / Connector / Placer) → a dungeon recipe. The engine owns per-pass RNG forking so editing the pipeline never reshuffles an existing seed. The library's sole output is a plain-data Map; reikhelm-viz consumes a Map and paints it — it contains no generation logic. The dependency direction is enforced: viz → core, never the reverse.

Tech Stack: Rust (Cargo workspace), rand + rand_chacha (ChaCha8 deterministic RNG), serde (derive on Map), macroquad (viz renderer).

Spec: spec/design.md

v1 Scope

Ship a dungeon recipe end-to-end (BSP → rooms → MST-connect → corridors → doors), an ASCII debug renderer, and an interactive macroquad window with seed reroll. Towns, caves, additional tiles/decorators, sprite rendering, and serialization tooling are designed-for but explicitly deferred (spec §11).

Inter-Pass Data Contract (read before any pass task)

Passes never call each other; they communicate only through GenContext fields. The v1 dungeon contract:

Pass Reads Writes
BspPartition (empty grid) ctx.regions: one placeholder Region { kind: Room, bounds: <leaf rect>, cells: [] } per BSP leaf
RoomCarver ctx.regions (placeholder Rooms) carves Floor into ctx.tiles; shrinks each Room's bounds to its actual room rect and fills cells
MstConnect ctx.regions (kind=Room, non-empty cells) centers ctx.graph: edges { a, b, at: None } forming an MST over rooms + a few extra loop edges
CorridorCarver ctx.graph edges + Room region bounds/centers carves L-shaped Floor corridors into ctx.tiles; appends Region { kind: Corridor, .. } per corridor
DoorPlacer ctx.tiles + ctx.regions + ctx.graph converts boundary Wall cells (room↔corridor) to Door; sets the corresponding edge.at = Some(point)

This is the integration contract. Each pass is unit-tested by constructing a GenContext in its required input state, so all five passes are implementable in parallel against this table.

Shared Wiring Files (parallel-edit note)

  • reikhelm-core/src/lib.rs — each module-creating task appends its own pub mod <name>;. These tasks are mostly sequential, so appends don't conflict.
  • reikhelm-core/src/passes/mod.rs — created empty (with the contract doc comment) by Task 6; each pass task (711) appends one pub mod <name>; + pub use. The pass tasks run in parallel, so the orchestrator merges these append-only lines at integration.