# Dungeon Forge: A Deterministic Procedural Dungeon Generator in Three.js

> Dungeon Forge is a browser-based procedural dungeon generator that builds rooms, corridors, and props in real time using a deterministic pipeline: scatter, separate, Delaunay triangulate, MST plus loops, assign room semantics, carve, and decorate. Every stage is seeded from a single number, so the same seed always produces the same dungeon.

**majidmanzarpour/threejs-procedural-dungeon** — Real-time procedural dungeon generator in Three.js - deterministic seeds, Delaunay/MST graph layouts, room semantics, five themes, and a custom bloom/tilt-shift pipeline.

- Repository: https://github.com/majidmanzarpour/threejs-procedural-dungeon
- Stars: 507 · Forks: 84
- Language: JavaScript
- License: MIT
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/majidmanzarpour-threejs-procedural-dungeon

## What Dungeon Forge Is and Who It Is For

Dungeon Forge is a single-page browser application that generates and renders procedural dungeons in real time using Three.js. It targets three audiences: JavaScript developers who want to see a complete procedural generation pipeline with all stages visible, game designers who need a fast exploration tool for dungeon layouts and themes, and Three.js learners who want a non-trivial rendering example with instanced geometry, custom post-processing, and procedural textures.

The problem it addresses is that most procedural dungeon tools are either black boxes (Unity or Unreal plugins where the algorithm is hidden) or academic code samples that generate a grid without visualization. Dungeon Forge makes every stage of the pipeline observable in real time: a HUD lights up each step as it runs, and the user can scrub or skip the build animation.

A live demo is available at procedural-dungeon.netlify.app. The repository builds to a static dist/ folder that can be hosted on any static host.

## The Nine-Stage Deterministic Pipeline

Every dungeon is built by the same nine-stage pipeline, seeded from a single number using a mulberry32 pseudorandom number generator threaded through every step.

1. Scatter: Room rectangles are sampled in a rough disc, with a size distribution biased toward small rooms and a few large ones.
2. Separate: Overlapping rooms push each other apart over relaxation passes until the layout is non-overlapping but compact.
3. Delaunay: Room centres are triangulated using Delaunay triangulation to produce a natural, non-crossing candidate graph.
4. MST plus loops: A minimum spanning tree over the candidate graph guarantees full connectivity. A tunable fraction of leftover Delaunay edges are added back as loops for shortcuts and cycles.
5. Semantics: A breadth-first search from the entrance assigns each room a depth and difficulty score, finds the critical path to the boss room, and tags rooms as entrance, combat, elite, treasure, shrine, or boss.
6. Carve: Rooms and corridors are stamped into a tile grid (floor, wall, doorway), with L-shaped corridors and occasional sunken liquid pits.
7. Rasterize and BFS: The grid is walked to place walls, doorways, and edge trims, and to compute per-tile ambient occlusion from neighbouring walls, moss, and pool glow.
8. Decorate: Props, torches, runes, portals, and a theme-appropriate particle field are scattered by density. Point lights are budgeted and placed at important rooms and torch positions.
9. Render: Everything is batched into InstancedMesh draw calls and composited through the custom post-processing stack.

The pipeline's determinism is absolute: changing one digit in the seed produces a completely different dungeon, but the same seed always rebuilds the same dungeon down to the last torch position.

## Installing and Running Dungeon Forge

Prerequisites: Node 18 or newer. Two dependencies are declared: Three.js and Vite.

```bash
npm install
npm run dev
```

The dev server starts at http://localhost:5173 with hot module replacement. For a production build:

```bash
npm run build
npm run preview
```

npm run preview serves the built output at port 4173. The dist/ directory that npm run build produces can be dropped onto Netlify, GitHub Pages, itch.io, or any static host.

The control panel lets the user type a seed, pick a theme, and adjust room count, loopiness (the fraction of Delaunay edges added back as loops), and decoration density. Every change re-forges the dungeon deterministically.

## Five Themes and the Procedural Rendering Approach

Five hand-tuned themes are available: Ancient, Molten, Frost, Grim, and Verdant, plus AUTO, which the seed selects automatically. Each theme swaps the palette, lighting rig, liquid type (lava, water, or miasma), props, particle system (embers, snow, spores, or wisps), and torch colour.

All geometry and textures are generated procedurally. Stone, cracks, runes, portals, and light shafts are drawn to canvas textures at load time. No assets are loaded from disk.

Rendering uses Three.js InstancedMesh to batch thousands of floor tiles, walls, props, and decorations into a small number of draw calls. An 80-room dungeon with roughly 6,000 floor tiles holds a high frame rate according to the README. Instanced rendering is what makes real-time generation practical at this scale.

Post-processing is a hand-written pipeline: bright-pass bloom, separable blur, tilt-shift focus band, cool-shadow and warm-highlight colour grade, vignette, and film grain. The result is a painted-miniature look that can be toggled off live with the P key for an A/B comparison.

## Debug Overlays and Live Stats

The HUD provides real-time stats: room count, links and loops, critical-path length, floor-tile count, light count, generation time, draw calls, triangle count, and FPS, all updating as the dungeon forges.

Two debug overlays are available. The graph overlay (G key) displays Delaunay edges, the MST, and the added loop edges in world space, making the graph structure visible in the 3D view. The difficulty heatmap (H key) shows how danger ramps from the entrance to the boss room, using the room semantics assigned in stage 5.

Object layers can be toggled without re-forging: props, torches, particles, liquids, and lights can each be turned on and off individually. This is useful for studying how each decoration category contributes to the scene, or for testing how the dungeon reads without lighting.

The generation pipeline is animated: each stage lights up in the HUD as it completes, and the user can skip the animation with the spacebar. The build animation scrubber allows stepping through past stages to see the dungeon at any point in the pipeline.

## Code Structure and Limitations

The project structure is minimal:

- index.html: canvas mount and control panel markup.
- src/main.js: the entire application, including RNG, generator pipeline, themes, procedural textures, instanced rendering, post-processing, camera, input, and HUD.
- src/ui/styles.css: panel, HUD, legend, and control styling.

The README notes that the generator and renderer are tightly coupled in a single module: they share the RNG state, materials, geometry caches, and render targets. This makes the code readable as a single unit but means it is not structured for extraction as a reusable library. There is no module boundary between the generation logic and the Three.js rendering code.

For comparison, procedural dungeon generators for Unity such as Vazgriz's work (mentioned in Google searches about this project) integrate with Unity's asset pipeline, prefab system, and physics engine. The difference in approach is that Dungeon Forge is a standalone browser demo, not an editor plugin or game component. It generates the same pipeline as many game-oriented tools but packages it as a visualisation rather than a production asset pipeline.

The last push was on 2026-07-05. The repository has no GitHub releases. MIT license.

## Conclusion

Dungeon Forge suits developers who want to study a complete procedural generation pipeline in a single self-contained JavaScript file, and designers who want to explore deterministic dungeon layouts without installing native tools. It is not a game engine component or a reusable library: the generator and renderer live in one tightly coupled main.js that is not extracted into an importable module. Verify that Node 18 or newer is installed, then run npm run dev to see the full pipeline at localhost:5173.

## FAQ

### Why does Dungeon Forge always produce the same dungeon for the same seed?

Every stage of the generation pipeline uses the same mulberry32 pseudorandom stream initialised from the seed. Room scatter, triangulation, room role assignment, carving, and decoration all draw from that stream in a fixed order, so the same seed produces the same sequence of decisions.

### Can Dungeon Forge be used as a library in a game project?

The README notes that the generator and renderer are tightly coupled in a single main.js file with shared RNG state, materials, and render targets. It is not structured as an importable module and has no documented API surface for external use.

### What does the loopiness control do?

After building a minimum spanning tree from the Delaunay graph (which guarantees full connectivity), loopiness controls the fraction of remaining Delaunay edges added back as additional corridors. Higher loopiness creates more shortcuts and cycles; lower loopiness produces a more tree-like layout.

## Sources

- [Issues](https://github.com/majidmanzarpour/threejs-procedural-dungeon/issues)
- [License: MIT](https://github.com/majidmanzarpour/threejs-procedural-dungeon/blob/main/LICENSE)
- [majidmanzarpour/threejs-procedural-dungeon on GitHub](https://github.com/majidmanzarpour/threejs-procedural-dungeon)
- [README](https://github.com/majidmanzarpour/threejs-procedural-dungeon/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/majidmanzarpour-threejs-procedural-dungeon
