README as a small game website in Crookfinger's voice; INSTALL.md, BESTIARY.md, playable standalone file
- README: logo, badges (Rust, WebAssembly, Claude Code, MIT), intro addressed to the master, features with screenshots, the household, how to play, licences and credits - INSTALL.md: server, PWA, building, tests, savegame service and API, languages, how to refresh generated files - BESTIARY.md generated from the game's data (tools/make_bestiary.py) with exported sprites and icons (docs/img, test export_doc_images) - play/DungeonCraft.html: the whole game in one file to download and play offline Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4ce2c2919e
commit
b3583f5e7e
124 files changed
+1178
-104
No files matched your search
@@ -1,135 +1,169 @@
|
||||
# DungeonCraft
|
||||
<p align="center">
|
||||
<img src="docs/img/logo.png" width="128" alt="DungeonCraft - the soul core">
|
||||
</p>
|
||||
|
||||
> **Made with the help of [Claude Code](https://claude.com/claude-code).** The code, graphics, texts and
|
||||
> documentation of this game were written together with Claude Code, Anthropic's AI coding assistant.
|
||||
<h1 align="center">DungeonCraft</h1>
|
||||
|
||||
An original dungeon building & defence game that runs in the browser (Rust + [macroquad](https://github.com/not-fl3/macroquad), compiled to WebAssembly).
|
||||
<p align="center"><b>Dig. Build. Defend. Conquer.</b><br>
|
||||
An evil little dungeon game for the browser - in glorious pixels, in 3D, for free.</p>
|
||||
|
||||
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.
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/Rust-macroquad-b7410e?logo=rust&logoColor=white" alt="Rust">
|
||||
<img src="https://img.shields.io/badge/WebAssembly-runs%20in%20the%20browser-654ff0?logo=webassembly&logoColor=white" alt="WebAssembly">
|
||||
<img src="https://img.shields.io/badge/made%20with-Claude%20Code-d97757?logo=anthropic&logoColor=white" alt="Made with Claude Code">
|
||||
<img src="https://img.shields.io/badge/license-MIT-2ea44f" alt="MIT License">
|
||||
<img src="https://img.shields.io/badge/languages-EN%20%7C%20DE-555" alt="English and German">
|
||||
</p>
|
||||
|
||||
- 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, dwarf caves with treasure and rune forge plans)
|
||||
- English and German (language files in `lang/`, easy to extend)
|
||||
<p align="center">
|
||||
<a href="play/DungeonCraft.html"><b>▶ Play now - download one HTML file, open it, done</b></a><br>
|
||||
<a href="BESTIARY.md">Bestiary</a> · <a href="INSTALL.md">Run your own server</a> · <a href="DESIGN.md">Design notes</a>
|
||||
</p>
|
||||
|
||||
See [DESIGN.md](DESIGN.md) for all design decisions and [CREDITS.md](CREDITS.md) for third-party assets.
|
||||
<p align="center">
|
||||
<img src="docs/screenshots/title-battle.png" width="820" alt="The title screen with the endless bridge battle">
|
||||
</p>
|
||||
|
||||
## 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):
|
||||
## Wake up, master.
|
||||
|
||||
```sh
|
||||
docker compose up -d --build
|
||||
# open http://localhost:18093
|
||||
```
|
||||
Yes, you. Don't look around, there's nobody else down here - just you, four imps and me, old **Crookfinger**.
|
||||
|
||||
### Install as an app (PWA)
|
||||
A hundred years ago the Order of the Lightwatch smashed your soul core into shards and carried them off like trophies.
|
||||
They polished their boots, sang songs about the sun and forgot about you. **Big mistake.**
|
||||
|
||||
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).
|
||||
Your heart still beats. Hear that? *Lub-dub. Lub-dub.* That's the sound of a grudge.
|
||||
|
||||
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.
|
||||
So pick up the pickaxe - well, point at the rock, the imps carry the pickaxes - and let's dig ourselves a realm.
|
||||
Gold is in the walls, creatures are waiting behind the portal, and the knights... the knights are about to have
|
||||
a very bad century.
|
||||
|
||||
### Building without Docker
|
||||
<p align="center">
|
||||
<img src="docs/screenshots/dungeon-heart.png" width="820" alt="The beating crystal heart, the demon gate and the dark towers">
|
||||
<br><i>Your heart, master, held in chains on its obsidian throne. And the demon gate. I polished it myself.</i>
|
||||
</p>
|
||||
|
||||
Requirements: Rust with the `wasm32-unknown-unknown` target.
|
||||
## What awaits you down here
|
||||
|
||||
```sh
|
||||
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
|
||||
```
|
||||
**🕳 Dig your realm.** Mark the rock and your imps dig, claim the ground, carry gold, gems and diamonds to the
|
||||
treasury and hang torches on the walls. Up to five imps help each other with one job. Every tile you claim is *yours*.
|
||||
|
||||
### Testing the game logic
|
||||
**🏰 Build rooms that bring the right guests.** A lair and a mushroom garden open the portal. A library brings
|
||||
shadow mages, a training hall stone ogres, a temple the flame priestess, an aerie giant bats, gargoyles, arcane
|
||||
owls - and maybe, one day, an **ember wyrm**. Fourteen rooms in total, from the forge to the sacrifice altar.
|
||||
|
||||
The tests run natively: a headless simulation of whole games, a savegame round trip, rendering of all music modules and the audio engine:
|
||||
**👹 Keep them happy, or they leave.** Every creature wants a bed, food and its wage on payday - and it walks to the
|
||||
treasury to fetch it. Each has a favourite room, and some of them simply cannot stand each other.
|
||||
Put a mage next to an ogre and watch the fur fly. (Nobody dies. Probably.)
|
||||
|
||||
```sh
|
||||
cargo test --release
|
||||
```
|
||||
**⚔ Train them into legends.** Ten ranks from Recruit to Warlord, with chevrons, bars and stars - and gear that grows
|
||||
with them, up to golden armour, a crown and a halo. With the level come abilities: the ogre learns to *stomp*, the mage
|
||||
to *step through shadows*, the chainbreaker to spin like a *whirlwind*.
|
||||
|
||||
## Music
|
||||
<p align="center">
|
||||
<img src="docs/screenshots/bridge-battle.png" width="820" alt="A battle at a bridge over an underground river">
|
||||
<br><i>The knights brought a bridge. How thoughtful. Now they're bringing it back, one piece at a time.</i>
|
||||
</p>
|
||||
|
||||
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`.
|
||||
**🔥 Defend with towers, traps and doors.** Arrow spires, hellmouth cannons and dark spires on the walls. In the
|
||||
**forge** your creatures build spike pits, poison vents, fire jets, stone rollers, alarm bells, rune mines and
|
||||
frost glows - and doors of wood, iron and magic. Lock them, and nobody gets through. Not even the giant. Well. Not for a while.
|
||||
|
||||
## Controls
|
||||
**✨ Cast nasty spells.** Lightning, healing, seer's eye, cave-in, haste, stoneskin, gold rain, invisibility,
|
||||
plague and quake. Your scholars **research** them in the library - one discovery after another.
|
||||
|
||||
| Input | Action |
|
||||
**🌫 Explore the dark.** Everything beyond your walls is black until your creatures go there.
|
||||
Somewhere out there: a cave of neutral **dwarves** guarding gold and gems - and sometimes a chest with the plans
|
||||
of a dwarven **rune forge tower**. Islands in lava rivers. Mana springs. Creatures in chains, waiting to be freed.
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/screenshots/forge-and-traps.png" width="400" alt="The forge with coglings and every kind of trap and door">
|
||||
<img src="docs/screenshots/dark-rooms.png" width="400" alt="Prison, graveyard, arena, altar and guard posts">
|
||||
<br><i>Left: the forge and its little coglings. Right: prison, graveyard, arena, guard posts and the altar. Cosy.</i>
|
||||
</p>
|
||||
|
||||
**👑 Other masters want your realm, too.** Mossgrim the Mouldy (green, smells like a wet cellar) and Lady Nightwell
|
||||
(blue, writes threatening letters on scented paper) dig their own dungeons in free play and in the campaign.
|
||||
And the humans attack *everybody*. Let them bite each other first.
|
||||
|
||||
**📜 A campaign of thirty missions.** Take back the shards of your soul core - from the first little outpost by the
|
||||
border brook to the citadel of Grand Master Valerian Brightshield. Rivers, fortresses, treasure islands, sealed
|
||||
caves, rival masters, and me, telling you the story. With tea.
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/screenshots/dwarf-cave.png" width="400" alt="A dwarf cave with a rune chest">
|
||||
<img src="docs/screenshots/fog-of-war.png" width="400" alt="The start of a game in the fog of war">
|
||||
<br><i>A dwarf cave, master. Nice dwarves. Don't go too close. - And this is where every game begins: in the dark.</i>
|
||||
</p>
|
||||
|
||||
## Meet the household
|
||||
|
||||
<p align="center">
|
||||
<img src="docs/img/units/worker_5.png" width="56" alt="Pit imp">
|
||||
<img src="docs/img/units/kobold_5.png" width="56" alt="Kobold">
|
||||
<img src="docs/img/units/spider_5.png" width="56" alt="Cave spider">
|
||||
<img src="docs/img/units/mage_5.png" width="56" alt="Shadow mage">
|
||||
<img src="docs/img/units/ogre_5.png" width="56" alt="Stone ogre">
|
||||
<img src="docs/img/units/jailer_5.png" width="56" alt="Jailer">
|
||||
<img src="docs/img/units/priestess_5.png" width="56" alt="Flame priestess">
|
||||
<img src="docs/img/units/cogling_5.png" width="56" alt="Cogling">
|
||||
<img src="docs/img/units/revenant_5.png" width="56" alt="Revenant">
|
||||
<img src="docs/img/units/bat_5.png" width="56" alt="Giant bat">
|
||||
<img src="docs/img/units/gargoyle_5.png" width="56" alt="Chain gargoyle">
|
||||
<img src="docs/img/units/owl_5.png" width="56" alt="Arcane owl">
|
||||
<img src="docs/img/units/wyrm_5.png" width="56" alt="Ember wyrm">
|
||||
<img src="docs/img/units/chainbreaker_5.png" width="56" alt="Chainbreaker">
|
||||
</p>
|
||||
|
||||
> *Fourteen kinds of wonderful creatures, master, and eight kinds of humans in shiny tin. I wrote everything down for
|
||||
> you - who loves what, who hates whom, who learns what - in* **[Crookfinger's Bestiary](BESTIARY.md)**.
|
||||
> *The same book is in the game, by the way - on the title screen and in the pause menu.*
|
||||
|
||||
## How to play
|
||||
|
||||
1. **Download [`play/DungeonCraft.html`](play/DungeonCraft.html)** and open it in your browser. That's all.
|
||||
It runs offline, on desktop and on phones (touch controls switch on by themselves).
|
||||
2. Or **run your own server** with Docker - with user accounts, savegames on the server and the game as an
|
||||
installable app: see **[INSTALL.md](INSTALL.md)**.
|
||||
|
||||
**The basics, master:**
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| 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 |
|
||||
| Left click / drag | use the tool - dig, build rooms (drag a rectangle), cast, place towers and traps |
|
||||
| Right click | drop what your hand holds (creatures, prisoners - or a sacrifice on the altar) |
|
||||
| Shift + click | slap your own creatures (faster for a while) or punch a hero |
|
||||
| Right drag, WASD, screen edge | move the camera · middle drag, Q/E, R/F: rotate and tilt · wheel: zoom |
|
||||
| Esc | pause menu: save, load, settings, bestiary |
|
||||
|
||||
All keys except Esc and the arrow keys can be changed in Settings → Keys.
|
||||
On phones: tap to use a tool, drag to mark or move, two fingers to zoom and turn, long press for information.
|
||||
|
||||
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.
|
||||
## Under the hood
|
||||
|
||||
### Touch (phones and tablets)
|
||||
- **Rust**, compiled to **WebAssembly**, with [macroquad](https://github.com/not-fl3/macroquad) - one small module, no engine, no plugins.
|
||||
- A real 3D isometric world in pixel art: chunked meshes, flickering point lights, a glow pass, particles,
|
||||
billboard sprites with eight viewing directions, every frame of it drawn by code - **no image files** except the font.
|
||||
- Procedural chiptune soundtrack as FastTracker 2 modules with its own XM replayer and synthesised sound effects.
|
||||
- A tiny Rust savegame server (axum, Argon2 passwords) - optional; without it the game uses savegame files.
|
||||
- English and German, more languages are one text file away.
|
||||
|
||||
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:
|
||||
## Made with Claude Code
|
||||
|
||||
| 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 |
|
||||
|
||||
A forgotten password is set again on the server with `docker compose stop saves && docker compose run --rm --no-deps saves dungeoncraft-saves set-password <name> '<password>' && docker compose up -d saves` (ends the user's sessions). To start over with no accounts at all, delete `users.json` and `sessions.json` in the `savegames` volume.
|
||||
|
||||
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
|
||||
|
||||
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.
|
||||
<p><img src="docs/img/claude-mark.png" width="72" alt="Claude Code mark" align="left"> DungeonCraft was developed with the help of
|
||||
<a href="https://claude.com/claude-code"><b>Claude Code</b></a>, Anthropic's AI coding assistant - the code, the graphics,
|
||||
the music, the texts and this page. Claude, Claude Code and Anthropic are trademarks of Anthropic; the pixel mark only
|
||||
credits the tool.</p>
|
||||
<br clear="left">
|
||||
|
||||
## License
|
||||
|
||||
DungeonCraft is released under the [MIT License](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](CREDITS.md).
|
||||
DungeonCraft is released under the **[MIT License](LICENSE)** - © 2026 Richard Zink. It covers the code, the generated
|
||||
music in `assets/music/` and the procedural graphics.
|
||||
|
||||
The **DINOBYTE** font (`assets/dbyte_1x.png`) by [mby](https://mby.itch.io/dinobyte) is licensed separately under
|
||||
**CC BY 4.0**. Details in [CREDITS.md](CREDITS.md).
|
||||
|
||||
---
|
||||
|
||||
<p align="center"><i>"The underworld is yours, master. Now - tea?"</i><br>- Crookfinger</p>
|
||||
Reference in new issue
Block a user