- Service: accounts with Argon2 password hashes and session tokens; the first login creates the admin (shared savegames of before move to the admin); the admin creates and deletes users; everybody can change the password; savegames are stored and listed per user - Game: login page before the title (only when the service is reachable), with licence and repository link; account page (password, logout; users for the admin); text fields with Tab/Enter, masked passwords, browser dialog on touch screens; long status messages wrap - Download Standalone: DungeonCraft.html with the game embedded (built in the Docker image, served to logged-in users via nginx auth_request); works from file:// without server and opens downloaded savegames - Without the service (standalone, local files) there is no login, savegame files as before Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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
Install as an app (PWA)
DungeonCraft is a progressive web app: browsers offer to install it (Chrome/Edge: install icon in the address bar or "Install app" in the menu; Android: "Add to home screen"; iOS Safari: Share → "Add to Home Screen"). The installed game starts in full screen and also works offline (the savegame list on the server then falls back to savegame files).
Browsers only allow the installation over HTTPS (or on localhost), so a public installation needs a reverse proxy with a certificate in front of port 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, K, J, B, C, T | 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.
The toolbar groups the tools into categories (Dig, Hand, Rooms, Towers, Spells, Orders) plus a menu button; categories with several tools open a row above the toolbar. The keys select tools directly.
Touch (phones and tablets)
The touch interface switches on automatically on touch devices or after the first touch (Settings → Game → Touch interface: Auto / On / Off). It uses a larger interface and these gestures:
| Gesture | Action |
|---|---|
| Tap | Use the tool (hand: pick up a unit; spells, flag, towers: at that spot) |
| Drag | Dig, rooms and sell: mark a rectangle; other tools: move the map |
| Two fingers | Move the map, pinch to zoom, twist to rotate the camera |
| Long press | Information about the spot; hand: drop the units there |
| Double tap (hand) | Backhand own units / punch heroes on your ground |
The savegame name is entered with the browser's text dialog when the name field is tapped.
Savegames
When the game is served together with the service (server/, started by docker compose), it starts with a login:
- The very first login creates the admin account with the entered name and password - do this right after installing.
- The admin creates further users (title screen -> Account); every user can change the password there and log out.
- Every user only sees the own savegames on the server: Save Game and Load Game open the list (save under a new name, overwrite, load, delete).
- Download Standalone (title screen) downloads
DungeonCraft.html: the whole game in one file, without login and without server. Savegame files (Download as file) open there as well.
If the service cannot be reached (for example the standalone file, www/ opened as local files or a plain web server), there is no login and the game uses savegame files: Save Game downloads a .dcsave file (JSON), Load Game opens the file picker; dropping the file onto the game window works too.
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/ keeps the user accounts (Argon2 password hashes) and the savegames as files in the Docker volume savegames (one folder per user). nginx forwards /api/ to it; the service itself is not published. The standalone file is served under /standalone/ only for logged-in users (nginx auth_request).
| Request | Meaning |
|---|---|
GET /api/health |
ok when the service runs (ok setup while there is no account yet) |
POST /api/login |
{name, password} -> {token, name, admin}; the first login creates the admin |
POST /api/logout, GET /api/me, POST /api/password |
session, own account, change password |
GET/POST /api/users, DELETE /api/users/{name} |
admin: list, create, delete users |
GET /api/saves |
own savegames (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 |
All requests except health and login need Authorization: Bearer <token>. Limits: 1 MB per savegame, 500 MB in total, 30 write requests and 20 login attempts per minute. Settings: SAVE_DIR (default /data), LISTEN (default 0.0.0.0:8080).
Adding a language
- Copy
lang/en.langtolang/<code>.langand translate the texts (placeholders{0},{1}stay as they are). - Add the file to
SOURCESinsrc/i18n.rs. - 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.