A small single-player kingdom-builder written in Rust. You don't control a character โ you watch your settlement from a top-down view, grow it, and defend it against rival camps. It renders tiles and entities with wgpu and runs both natively and in the browser (via WebGL) using Trunk.
๐ Documentation: https://playforge-coding.github.io/kingdom/ ยท ๐ฎ Play in your browser: https://playforge-coding.github.io/kingdom/play/
- Main menu & world creation. Start from a menu: enter a seed (or roll a random one) and create a world, load your saved world, or resume. A set seed is fully reproducible.
- Infinite, chunked world. The map is divided into 32ร32 tile chunks generated on demand from the seed as you explore, so the world is effectively endless. Terrain uses FastNoise Lite: a low-frequency continental field carves broad continents out of wide oceans (with a guaranteed home continent at the origin), a finer field roughens the coastlines, and another scatters forests (wood) and ore (stone). Winding, branching rivers (domain-warped noise isolines, 2โ3 tiles wide) meander across the land and flow to the coast, opening the interior to the sea; occasional inland lakes dot it too. Villages favour the waterside, so most towns sit on a river or coast โ prime hunting ground for the navy. Only single-tile notches are auto-bridged, so rivers stay real barriers you cross by bridge or boat.
- Saving. Save any time to a custom binary
.datblob (magicKGDM) that captures the seed, stockpile, stats, every unit, and all edited chunks (buildings, bridges, depleted resources). Native builds write a file (kingdom_save.dat); the web build stores the blob in IndexedDB. - Farmers walk to the nearest reachable resource, then chop wood and mine stone (with a swing animation). Everything they gather goes into your shared stockpile.
- Knights seek out and attack the enemy faction. Both sides take damage in melee; HP bars appear above wounded units. With no foe left in the field they press the assault on enemy huts and walls instead of idling. Set a rally flag (left-click in rally mode; right-click to clear) to pull them to a point.
- Three factions (you = blue, enemy = red, allies = green). The enemy is hostile to everyone; their soldiers stream out to hunt you. The allies hold villages on coasts across the sea: they trade with you and attack the enemy on their own, but never join your battles and never fight you. Both start with a few villages, and more enemy and allied villages keep being founded over time, spreading ever farther out across the endless map.
- Your village. You begin controlling a single village on the coast near the origin โ right by the sea, giving your cargo ships a home port. Villages change hands per-camp: leave one undefended with an enemy inside and you lose it (your knights auto-rally to retake it); strip an enemy village of its defenders and stand a unit in it to capture it. (Allied villages can't be captured.)
- Priorities. Toggle Agriculture / Military to bias which workers your houses raise, and Balanced / Wood / Stone to steer what farmers gather.
- Proclaim a draft. Need soldiers now? Declare a draft and, for a short spell, your farmers spontaneously take up arms as knights โ each still paid for in gold, so your treasury caps the call-up while a core of farmers is always spared.
- Economy. Alongside wood and stone you keep a purse of gold. You start with some seed gold; every new knight costs gold to arm (a broke village raises a free farmer instead), and most structures cost gold too.
- Trade. Load wood and stone onto a cargo ship and left-click open water in your harbour (ships launch only from near your village) to send it off. It charts a water route to the nearest allied coast (never crossing land) and sells the goods for gold on arrival โ stone fetches more than wood.
- Pirates. Rare pirate ships roam the open ocean, hunt your ships, and fire cannonballs; a hit sinks a cargo ship and its cargo. They keep to the deep sea, never enter rivers or lakes, and hold a standoff to shell their quarry instead of piling onto it.
- Navy. Build a warship (wood + stone + gold) on the water by your village and it fights on its own: it hunts pirates and bombards enemies ashore with cannonballs, holding off in the water so it never beaches. Warships have a hull bar and can be sunk by pirate fire โ escort convoys with a few.
- Building. Left-click to build:
- a House on open grass (wood + stone + gold) โ only next to your existing village, so your territory grows organically. Houses raise your population cap and spawn new workers (while you have 4+ farmers).
- a Bridge on open water (wood) โ makes that tile walkable.
- a Mine on open ground (stone + gold) โ a bottomless stone source, worked by up to four farmers at once.
- a Wall (wood + stone + gold) โ a defensive blocker units path around.
- a Hut (click a tree, gold) โ a knight builds it; it shelters farmers from raids, and knights rush to defend an attacked one.
- Units navigate with grid pathfinding (BFS) and treat water, buildings and resource nodes as obstacles, routing around them or across bridges.
| Input | Action |
|---|---|
WASD / arrow keys |
Pan the camera |
| Mouse scroll | Zoom in / out |
| Left-click | Perform the current build action / place the rally flag |
| Right-click | Clear the rally flag |
Esc |
Return to menu (from the menu: quit on native) |
The egui panel in the top-left shows your stockpile, population, score, and the current build mode, plus priority toggles and Save and Menu buttons.
cargo run --releaseRequires Trunk and the wasm target:
rustup target add wasm32-unknown-unknown
cargo install --locked trunk
trunk serve # dev server at http://127.0.0.1:8080
# or
trunk build --release # static bundle in dist/wgpu is built with the webgl feature so the game runs on browsers without
native WebGPU support.
| File | Responsibility |
|---|---|
src/main.rs |
Entry point (native + wasm), logging/panic hooks |
src/app.rs |
winit event loop, input, camera, per-frame draw list + animation |
src/gfx.rs |
wgpu instanced sprite-batch renderer + egui render pass |
src/atlas.rs |
Packs all PNGs into one texture atlas; slices animation frames |
src/world.rs |
Chunked infinite world, worldgen, bridges, walkability |
src/pathfind.rs |
Bounded BFS grid pathfinding |
src/game.rs |
Simulation: factions, AI, gathering, combat, spawns, building, save (de)serialization |
src/save.rs |
.dat persistence (native file / web IndexedDB) |
src/camera.rs |
Top-down orthographic camera (tile units) |
src/ui.rs |
egui menu + in-game panel |
src/shader.wgsl |
Instanced textured-quad shader |
assets/textures/ |
Tile, building and character-sheet PNGs |
docs/ |
Documentation site sources (Zensical / Material for MkDocs) |
scripts/fetch-fonts.py |
Downloads the docs' self-hosted webfonts |
The docs live in docs/ and are built with
Zensical (Material for MkDocs). Fonts are self-hosted
rather than loaded from the Google Fonts CDN, so fetch them once before building:
pip install zensical
python scripts/fetch-fonts.py # downloads docs/fonts/ + docs/stylesheets/fonts.css
zensical serve # live preview
zensical build --strict # static site into site/Pushing to the default branch builds the docs and the WebAssembly game and
publishes both to GitHub Pages (see .github/workflows/docs.yml):
- ๐ Docs โ https://playforge-coding.github.io/kingdom/
- ๐ฎ Play โ https://playforge-coding.github.io/kingdom/play/
Pushing a v* tag builds native binaries for Windows, macOS and Linux and
attaches them to a GitHub Release (see .github/workflows/release.yml).
The sprites are MiniWorld Sprites by Shade on OpenGameArt.org, released under CC0 โ thanks to Shade, who appreciates the credit.
Character art is stored as 5ร12 grids of 16ร16 frames; the renderer slices out walk and action (chop / mine / attack) frames per entity. Trees and rocks are padded onto a 16ร16 tile footprint. Entities are drawn as foreground tiles on top of the terrain.
