2026-11-03 08:30:49 +01:00
2026-11-03 08:30:49 +01:00

DungeonCraft

An original dungeon building & defence game that runs in the browser (Rust + macroquad, compiled to WebAssembly).

Dig out your underground realm, claim the portal to attract creatures, keep them fed, rested and paid, fend off endless hero waves that adapt to your army – and finally destroy the Hero Gate.

  • 3D isometric view with a freely rotatable and tiltable camera
  • Procedural pixel art, irregular cave walls, flickering torch light
  • CP437 text-mode style interface with the DINOBYTE bitmap font
  • Map sizes from 64×64 to 256×256 tiles (one portal per 64×64 tiles, guarded treasure caves on bigger maps)
  • English and German (language files in lang/, easy to extend)

See DESIGN.md for all design decisions and CREDITS.md for third-party assets.

Running

The easiest way is Docker; the image builds the WASM file and serves it with nginx. A second container runs the savegame service (see below):

docker compose up -d --build
# open http://localhost:18093

Building without Docker

Requirements: Rust with the wasm32-unknown-unknown target.

rustup target add wasm32-unknown-unknown
cargo build --release --target wasm32-unknown-unknown
cp target/wasm32-unknown-unknown/release/dungeoncraft.wasm www/
cp ~/.cargo/registry/src/*/macroquad-*/js/mq_js_bundle.js www/
python3 -m http.server 8080 -d www   # open http://localhost:8080

Testing the game logic

The tests run natively: a headless simulation of whole games, a savegame round trip, rendering of all music modules and the audio engine:

cargo test --release

Music

The soundtrack consists of FastTracker 2 modules in assets/music/, generated by tools/compose_music.py (python3 tools/compose_music.py). They can be opened and edited in MilkyTracker. The game plays them with its own XM/MOD replayer (src/xm.rs); sound effects are synthesised chip sounds (src/sfx.rs). Both are mixed in src/audio.rs and streamed to the browser by www/dc_plugin.js.

Controls

Input Action
Esc Pause menu (save, load, settings)
Left click / drag Use the active tool (dig and rooms: drag a rectangle)
Right click Drop a unit from your hand (prisoners anywhere on your ground; onto a free torture place = locked up)
Shift + left click (hand) Backhand own units (15 s faster, costs a little HP and mood) / punch heroes on your ground (15 damage, 1 s stun)
Right drag, WASD, arrows, screen edge Move the camera
Middle drag, Q/E, R/F Rotate / tilt the camera
Mouse wheel Zoom
1–9, 0, X, V Select a tool or spell
P / Space Pause
M, +/- Sound on/off, volume
G Tile outlines on/off
H Help

All keys except Esc and the arrow keys can be changed in Settings → Keys.

Savegames

When the game is served together with the savegame service (server/, started by docker compose), Save Game and Load Game open a list of savegames stored on the server: save under a new name (type it into the name field), overwrite, load or delete (overwrite and delete ask for a second click). The list is shared by everybody who can reach the game - protect a public installation, for example with a password on the reverse proxy.

If the service cannot be reached (for example when www/ is opened as local files or served by a plain web server), the game falls back to savegame files: Save Game downloads a .dcsave file (JSON), Load Game opens the file picker; dropping the file onto the game window works too. Savegame files are also available from the server list (Download as file / Load from file).

The game also autosaves into the browser every two minutes and when the tab is closed; Continue on the title screen resumes from there.

Savegame service

A small Rust service (axum) in server/ stores savegames as files in the Docker volume savegames. nginx forwards /api/ to it; the service itself is not published.

Request Meaning
GET /api/health ok when the service runs
GET /api/saves list (id, name, date, map size, wave, play time), newest first
POST /api/saves?name=... store a new savegame (body: savegame JSON)
PUT /api/saves/{id}?name=... overwrite a savegame
GET /api/saves/{id} savegame JSON
DELETE /api/saves/{id} delete a savegame

Limits: 1 MB per savegame, 500 MB in total, 30 write requests per minute. Settings: SAVE_DIR (default /data), LISTEN (default 0.0.0.0:8080).

Adding a language

  1. Copy lang/en.lang to lang/<code>.lang and translate the texts (placeholders {0}, {1} stay as they are).
  2. Add the file to SOURCES in src/i18n.rs.
  3. Note: the DINOBYTE font only covers the CP437 character set.

License

DungeonCraft is released under the MIT License – this covers the code, the generated music in assets/music/ and the procedural graphics. The DINOBYTE font (assets/dbyte_1x.png) by mby is licensed separately under CC BY 4.0, see CREDITS.md.

S
Description
No description provided
Readme MIT
351 MiB
0 Stars 1 Watchers 0 Forks
2026-11-07 13:37:02 +01:00
Languages
Rust 48.2%
Logos 46.2%
Python 5%
JavaScript 0.4%
Shell 0.1%