An original, fully playable fantasy 4X strategy game (explore, expand, exploit, exterminate) in the spirit of the classic '90s civilization-builders — orcs, elves, dwarves and men contending for a procedurally generated world. Node.js server, canvas client, zero dependencies, zero assets — every tile, banner, shield and city is painted procedurally at load time.
Elderfall is an original project inspired by classic turn-based strategy games and high-fantasy fiction. All faction names, place names, and characters are original — it contains no third-party IP, branding, assets or data.
npm start
Open http://localhost:5173, pick a faction, and play. To use a different port:
PORT=4000 npm start (PowerShell: $env:PORT=4000; npm start).
Your game autosaves to the data/ folder every turn and the menu offers
Continue on your next visit. Delete data/ for a fresh start.
No Node? Any static server works too (python -m http.server 5173) — the game
runs fine, you just lose saved games. You cannot open index.html directly from
disk (file://) — ES modules require an HTTP origin.
Optional headless regression test (no browser needed):
npm test # AI-vs-AI games across seeds: combat, growth, research, save round-trip
| Faction | Leader | Perk |
|---|---|---|
| Elves of Silverwood | Queen Aravel | +50% defense in forests; scouts see farther |
| Kingdom of Westmarch | King Aldric II | Cities grow 25% faster |
| Dwarves of Deepdelve | Thane Borin Flintbrow | +1 production from hills & mountains |
| Horde of Gruk-Mor | Warchief Zoguk | Melee +1 attack; warriors cost less |
Inscribe your name, pick your banner. You lead one; the other three are played by the AI, which settles, researches, garrisons its cities, and comes for yours.
The gold action button (bottom right) is the game's advisor — it always shows
your next required decision and walks you through them in order:
City: choose production → Choose research → Unit needs orders (3) → End Turn.
Click it and it takes you there. Enter always ends the turn regardless.
Click any of your settlements to open the city screen — production is grouped into ⚔ Troops and 🏛 City improvements, each with cost and a turns-to-complete estimate. Locked options stay visible with a 🔒 and the lore that unlocks them ("Requires Engineering"), so the tech tree's payoff is always in view — as your knowledge grows, the list grows. Garrisoned troops are selectable from the same screen, and the selected unit's panel shows a contextual hint (settlers are told where and how to found a city).
- Cities work their best nearby tiles for 🌾 food (growth) and ⚒ production (units & buildings), and generate 📜 lore (science) from population and Libraries.
- Lore unlocks a 10-tech tree across three tiers — Archery → Riding → Engineering → Steelcraft → Elder Legends → High Sorcery.
- Units move on an 8-direction grid with terrain costs; forests and hills are slow but defensible. Fortify (F) for +50% defense. Stone Walls double a city's defense; catapults double their attack against cities.
- Combat is round-based attack-vs-defense with terrain, walls, fortification and veteran modifiers — wounded units heal in friendly cities.
- Fog of war — unexplored void, remembered-but-dim, and live line of sight.
The game ends when one banner conquers all rivals (Conquest), someone completes the Beacon of the Ages wonder (Wonder), or the Age closes at turn 220 (Points). Losing every city ends your game too.
As you play, Elderfall keeps a running tally: cities founded, cities conquered, improvements built, lore discovered, people living, gold earned (cities produce gold each turn — Markets add more, and captured cities are plundered), and foes slain. When the game ends you get an itemized final score — each tally line weighted and summed, with victory and swiftness bonuses on top.
Scores go to the 🏆 Hall of Ages, saved in data/scores.json pinball-style:
enter your name on the start screen (it's remembered for next time), and the
top-10 table greets you before every game so you're always chasing your own
best. Your live score and treasury are shown in the top bar as you play.
| Input | Action |
|---|---|
| Click | select unit / open city; click again to move or attack |
| WASD / arrows | move selected unit (pan map when nothing selected) |
| B | found city (settler) |
| F / Space / N | fortify / skip / next unit |
| Enter | end turn |
| Drag / scroll | pan / zoom |
| H / M / L | help / minimap / event log |
Elderfall/
├── index.html HTML shell: screens, panels, modals
├── styles.css all UI styling
├── server.mjs zero-dependency static server + save API (data/save.json)
├── package.json npm start / npm test — no dependencies
├── data/ autosaved games + Hall of Ages scores (delete for a fresh start)
├── src/
│ ├── main.js entry point: menu, boot, save/load wiring ← start here
│ ├── config.js all game data: terrain, factions, units, buildings, techs
│ ├── rng.js seeded RNG + value noise (deterministic worlds)
│ ├── core.js DOM-free rules engine: map gen, cities, combat, turns
│ ├── ai.js pathfinding, research priorities, settling, war
│ ├── render.js canvas map, fog compositing, minimap, camera
│ ├── ui.js top bar, unit panel, city/tech modals, input
│ └── save.js game-state serialization for the save API (v2: name, gold, stats)
└── test/
└── smoke.mjs headless AI-vs-AI regression test (npm test)
The core rules engine (core.js, ai.js) never touches the DOM — the UI and AI
attach through a small hooks object — which is why the whole game can play
itself headlessly in CI.
All content lives in the data tables in src/config.js: TERRAIN, FACTIONS,
UNITS (+ per-faction FLAVOR names), BUILDINGS, TECHS. Add a unit or tech as
one object entry and the city build menus, research screen, and AI pick it up
automatically. Map size, tile size and game length are the three constants at the
top of the same file.
| Add a… | Touch |
|---|---|
| Terrain | config.js → TERRAIN + a paint case in render.js → drawTile |
| Unit | config.js → UNITS (+ FLAVOR names) — build menus & AI pick it up |
| Building / wonder | config.js → BUILDINGS (+ effect in core.js → cityWorkedYields or combat) |
| Tech | config.js → TECHS — the tree UI lays it out by tier |
| Faction | config.js → FACTIONS (+ perk hooks in core.js) |
Naval units & transports, roads and tile improvements (workers), diplomacy and alliances, ranged bombardment, heroes with abilities, multiple save slots, hot-seat multiplayer, and a larger tech tree with an era system.
MIT-style: do whatever you like with it.