⛏ Undermountain Dwarves
▶ Play it live: https://undermountaindwarves.com (single-player, or "Enter the Public World" for the real-time shared alpha.)
A Dwarf Fortress–inspired colony/management game. The single-player game runs
entirely in the browser — no build step, no dependencies — with a Canvas tile
grid and a classic ASCII aesthetic. The online public world adds real-time,
server-authoritative multiplayer (a Cloudflare Worker + Durable Object running
the same sim.js).
Guide seven dwarves as they strike the earth: dig down through stone, mine ore and gems, haul goods to stockpiles, keep everyone fed, watered and rested, grow your fortress with migrants, and survive paced threats from the surface.
How to run
The game is static files. Any of these work:
Easiest — open the file
Double-click
play.html(the single-player game).index.htmlis the landing page;public.htmlis the online world. Scripts are plain<script>tags, so this works fromfile://in most browsers.
Recommended — a tiny local server (avoids any browser file:// quirks):
# Python 3
python -m http.server 8123
# then open http://localhost:8123
# …or Node
npx serve .
Controls
| Action | How |
|---|---|
| Select a designation tool | Toolbar, or keys d dig · h chop · s stairs · c channel · t stockpile · w wall · k mason · l smelter · r craftsdwarf · p carpenter · f farm · x erase |
| Apply a tool | Drag a rectangle on the map |
| Inspect a tile | Hover — the readout under the map names what's there |
| Select a dwarf | Click (or shift-click) a dwarf ☺ on the map, or click a row in the Dwarves panel |
| Toggle a dwarf's labor | Checkboxes in the Dwarves & Labor panel (mine / woodcut / haul / build / farm / craft) |
| Change depth (z-level) | Up / Down buttons, or < / > |
| Pause / resume | Space |
| Game speed | 1 = 1× · 2 = 2× · 3 = 4×, or the ▶ buttons |
| X-ray (peek at the level below) | z |
The map, at a glance
☺a dwarf ·☻carrying something · colored by activity (gold idle, blue working, orange eating/drinking, purple sleeping, red hurt)▓wall (brown soil, grey rock) ·*ore vein (coal/copper/iron/silver/gold by color) ·♦gem ·♣tree ·▲boulder ·≈glowing magma (deep).·floor/biome (grass/forest/desert/snow/rocky) ·><Xstairs ·○cave entrance ·≈water=stockpile ·⌂mason ·♨smelter ·☼craftsdwarf ·Πcarpenter · farm plotd b q fwandering wildlife ·r w Thostile creatures ·•≡*♦loose stone / wood / ore / gems- A yellow outline marks a designated (queued) job.
The colony loop
Mine stone/ore and chop wood → haul to a stockpile → build workshops → Smelter turns ore into metal bars, Craftsdwarf turns bars/stone/wood into crafts (wealth). Wealth draws migrants; farms keep everyone fed and watered. Dwarves gain skill at jobs they repeat, working faster over time. Dig deep for richer ore — but big unsupported caverns risk cave-ins, and the deepest levels hold magma.
A first few minutes
- Build a Stockpile (
t) somewhere on the grass so haulers have a home for stone. - Dig a Stairs ↓ (
s) to open the level below, then press>to look at z-1. - Dig (
d) out some soil rooms. Watch dwarves walk over and mine — it takes real time, and drops stone that haulers carry back. - Keep digging deeper for richer ore and gems. Lay a Farm (
f) on soil to become self-sufficient in food and drink before your starting stores run low.
The early game is deliberately forgiving (see DESIGN.md): an untouched colony
survives comfortably for several minutes, and nothing hostile appears for the
first few minutes. Difficulty ramps rather than spikes.
Project layout
index.html landing page (front door) — rotating ASCII planet, news feed, sign-in
play.html the single-player game — markup + panels
public.html the online public world (multiplayer client)
css/style.css styling
js/sim.js pure simulation (no DOM) — the tick clock, needs, jobs, AI
js/net.js public-world client (render-model over WebSocket)
js/render.js Canvas tile renderer
js/ui.js toolbar, panels, event log, input
js/main.js fixed-timestep clock + render loop
test/smoke.js headless Node test of timing & balance (node test/smoke.js)
DESIGN.md tick rate + every key balance rate, in one place to tune
Tests
node test/smoke.js
Runs the simulation headless and asserts the balance guarantees — most importantly that the fortress no longer dies in 30 seconds and that an idle colony survives several minutes.