A 2D RPG where every NPC, item, weapon, quest, portrait, music track, and sound effect is generated by AI. One input — a STORY_SEED string — produces a playable, coherent world through a pipeline that orchestrates five AI modalities. Turn-based combat, multi-room exploration, LLM-driven NPC dialogue.
No install, no API keys, no Python — just download and run. Grab the zip for your OS from the latest release (~1 GB, includes all portraits, music, and sound effects).
- Download
MazeWorld-macos-arm64.zipand double-click to unzip. - The app is unsigned, so macOS Gatekeeper will block it on first launch. Open Terminal and run:
(Adjust the path if you moved the app. You only need this once.)
xattr -cr ~/Downloads/MazeWorld.app && open ~/Downloads/MazeWorld.app
- Play.
Saves and crash logs: ~/Library/Application Support/MazeWorld/saves/.
Intel Macs are not currently supported.
- Download
MazeWorld-windows-x64.zip, right-click -> "Extract All". - Open the extracted
MazeWorldfolder and double-clickMazeWorld.exe. - SmartScreen will warn "Windows protected your PC" (unsigned binary). Click More info -> Run anyway. You only need this once.
Saves and crash logs: %APPDATA%\MazeWorld\saves\.
Check crash.log in the saves folder (paths above). Startup errors get written there so console-less builds still leave a trail — paste the contents into a GitHub issue and I can help debug.
Multi-Model Pipeline — World generation orchestrates 5 AI modalities across a single pipeline run, with the ability to run locally and generate with local resources/models.
| Modality | API Backend | Local Backend |
|---|---|---|
| Text / Story | Claude Sonnet 4 (Anthropic) | Llama 3.2 3B (HuggingFace) |
| Portraits | fal.ai (nano-banana) | FLUX.1 (CUDA) / SDXL Turbo (MPS) |
| Music | Google Lyria 3 | — |
| SFX | ElevenLabs | — |
| Narrative | Claude | Llama 3.2 |
Agentic Validation Pipeline — Generated content passes three audits:
- Checker — per-entity structural validation (required fields, type constraints, puzzle solvability).
- Validator — cross-reference integrity (every quest target exists, every item reference resolves, no circular dialogue dependencies).
- World Editor — coherence audit against the World Bible.
On failure, the specific failure reason is fed back to the LLM as context for the retry. This one pattern did more for quality than switching models did.
Skeleton-Driven Generation — Mechanical properties (weapon dice, spell stats, encounter DCs) are pre-rolled as skeletons before the LLM call. The LLM generates only name and flavor text, then skeletons are merged back. This ensures balanced gameplay while preserving creative variety.
flowchart TD
subgraph phase1 ["Phase 1: Story and World"]
StorySeed["STORY_SEED + config"] --> StoryGen["Overarching Story\n(faction, arc, boss)"]
StoryGen --> Bible["World Bible\n(cross-reference index)"]
end
subgraph phase2 ["Phase 2: Per-Room Content"]
Skeletons["Pre-rolled Skeletons\n(weapons, spells, events)"]
LLM["LLM: Claude / Llama"]
Skeletons -->|"mechanics"| Merge["Skeleton + LLM Merge"]
LLM -->|"name + flavor"| Merge
Merge --> RoomData["Room Data\n(NPCs, items, monsters,\nevents, quests)"]
end
subgraph phase3 ["Phase 3: Assets"]
ImageGen["fal.ai / FLUX\n(portraits)"]
MusicGen["Lyria 3\n(music tracks)"]
SFXGen["ElevenLabs\n(sound effects)"]
end
subgraph phase4 ["Phase 4: NPC Dialogue"]
TreeGen["Dialogue Tree Generation\n(retry + validation)"]
Greetings["Opening Greetings\n+ Personality Notes"]
end
subgraph phase5 ["Phase 5: Validation"]
Checker["Checker\n(per-entity)"]
Validator["Validator\n(cross-reference)"]
EditorNode["World Editor\n(coherence)"]
Checker --> Validator --> EditorNode
EditorNode -->|"feedback"| LLM
end
phase1 --> phase2 --> phase3
phase2 --> phase4
phase2 --> phase5
Bible --> phase3
phase5 -->|"WorldBible"| DataFolder["data/ folder\n(all JSON, portraits,\nmusic, SFX)"]
phase3 --> DataFolder
phase4 --> DataFolder
flowchart LR
subgraph models [Models]
Player
NPC
Maze
Encounter
Quest
Spell
end
subgraph controllers [Controllers]
GC["GameController"]
CIH["CombatInputHandler"]
EIH["EventInputHandler"]
end
subgraph views [Views]
MazeView
CombatView
DialogueView
EncounterView
end
subgraph systems [Systems]
QuestMgr["QuestManager"]
SaveMgr["SaveManager"]
Survival["SurvivalSystem"]
FogOfWar
MusicDir["MusicDirector"]
end
GC --> CIH
GC --> EIH
GC --> models
GC --> systems
controllers --> views
views --> PygameDisplay["pygame display"]
| Mode | .env value |
Description |
|---|---|---|
| Offline (Static) | offline_static |
Pre-generated content with scripted dialogue trees. Fully self-contained, no API keys needed. |
| Offline (Local) | offline_local |
NPC dialogue generated by locally hosted LLM. Requires local GPU. |
| Online (API) | online |
NPC dialogue generated via Claude API. Requires internet + API key. |
- Multi-room maze exploration with fog of war and day/night cycle
- Turn-based combat with initiative, weapon stat scaling, spell modifiers
- 4 class archetypes (warrior, mage, healer, jester) with AI-generated stat blocks, names, and portraits per environment
- 5-element magic system (fire, water, forest, light, dark) with RPS multipliers
- 3 encounter types: combat, puzzle (tool / ability / spell solutions), event (multi-choice with DC rolls)
- 6 quest types: fetch, kill, escort, delivery, dialogue, multi-step chains
- Environment-themed monster pools with elemental affinities and loot tables
- Gate bosses per room, climax boss on the final room
- NPC followers, shops, survival (hunger / thirst / stamina), save/load
git clone <repo>
cd mazeworld
pip install -e ".[api,dev]"
cp .env.example .env # add keys for any providers you want
python main.py --dev # generate a world, then play it
python main.py --dev --skip-gen # play an already-generated worldFrom a generated world:
python main.py --dev --exePyInstaller needs a framework-built Python on macOS, so the --exe flag uses a separate .venv-build:
/Library/Frameworks/Python.framework/Versions/3.12/bin/python3 -m venv .venv-build
.venv-build/bin/pip install 'pygame>=2.6' 'pydantic>=2.9' 'python-dotenv>=1.1' \
'Pillow>=10.0' 'protobuf>=4.25' 'pyinstaller>=6.11'Requires Python 3.12 from python.org. Saves from the packaged app live at ~/Library/Application Support/MazeWorld/saves/ (including crash.log on failed launches).
PyInstaller can't cross-compile, so Windows .exe builds run on GitHub Actions. The .github/workflows/release.yml workflow packages both platforms and attaches the zips to a GitHub Release.
Because the generated data/ folder is ~1 GB (dominated by portraits) it stays out of git. It lives on a dedicated world-data-vN release tag and is consumed by the build jobs.
-
Generate a world locally (
python main.py --dev). -
Publish the data bundle as a release asset:
./scripts/publish_world_data.sh # auto-picks the next world-data-vN tag -
Point CI at that tag by setting a repository variable (Settings -> Secrets and variables -> Actions -> Variables, or via CLI):
gh variable set WORLD_DATA_TAG --body "world-data-v1"
Either push a version tag:
git tag v0.1.0 && git push origin v0.1.0Or run the workflow manually (GitHub Actions UI -> Release -> Run workflow) and supply a version like v0.1.0-test. The workflow:
- Builds
MazeWorld.apponmacos-14(arm64) viamazeworld.spec. - Builds
MazeWorld.exeonwindows-latestviamazeworld_win.spec. - Downloads the pinned
world-data-vNzip on each runner and unpacks it intodata/before PyInstaller runs. - Publishes both zips to the release tag with generated release notes.
To ship a new world without touching code, regenerate, re-run scripts/publish_world_data.sh (it picks a new world-data-vN), bump WORLD_DATA_TAG, and cut a fresh version tag.
- Python 3.11+
- Pygame 2.6, Pydantic 2.9+
- Anthropic SDK (online mode)
- PyTorch 2.4+, Transformers, Diffusers (offline_local mode only)
See requirements.txt for pinned versions.
MIT.