Skip to content

Repository files navigation

⚔️ llm-rpg-world-simulator

An AI-powered RPG world simulation where a Gemini LLM acts as the world transition engine (intent → plan → diff → narration), not a chatbot. The world has persistent state, NPCs with goals/memory, a supply/demand economy, rumors that propagate and mutate, and emergent quests. A vanilla HTML/JS frontend renders the live world graph via Cytoscape.

Demo Video

https://github.com/subho004/llm-rpg-world-simulator/blob/main/assets/demo.mp4

Compressed Version

demo.mp4

🎮 Player's guide → docs/GAME_GUIDE.md — how to play, actions, the quest loop, and how to complete quests.

📖 Full manual & feature reference → docs/MANUAL.md — setup, architecture, every subsystem, the complete API, the UI guide, configuration, testing, troubleshooting, and how to extend.

Built on Python 3.14.2 + uv, FastAPI, async SQLAlchemy 2.x (SQLite, swappable to Postgres), and google-genai.

Architecture at a glance

Player action / Tick
  → parse intent / NPC plan   (LLM, structured JSON via response_schema)
  → validate                  (deterministic rules; DiffApplier allow-lists + clamps)
  → apply effects             (only deterministic code mutates state)
  → economy / rumors / quests (deterministic triggers → LLM phrasing)
  → narrate                   (LLM, concise)
  → WorldDiff + narration

The LLM only ever emits minimal diffs / structured intents; every change passes through the DiffApplier choke point before touching the DB.

Configure

Copy .env.sample to .env. Set GEMINI_API_KEY to run with real Gemini, or leave it blank (or LLM_ENABLED=False) to run fully offline with a deterministic FakeLLMClient. Default model is gemini-3.1-flash-lite.

Run

uv run uvicorn main:app --reload
  • Frontend (live world graph): http://127.0.0.1:8000/ui/
  • Health: http://127.0.0.1:8000/health

Click Tick to advance the world, type actions ("travel to Oakvale", "buy a sword", "talk to Mira"), toggle Auto, or Reset to re-seed. Click any graph node to inspect an NPC's memories, relationships, and last rationale.

Key endpoints

Method Path Purpose
GET /world world snapshot (clock, locations, counts)
GET /world/graph Cytoscape graph JSON
GET /world/market market prices
POST /world/tick advance one tick → diff + narration
POST /world/reset re-seed the world (optional {"seed": N})
GET /world/snapshot export the whole world as JSON
POST /world/restore restore a previously exported snapshot
POST /actions submit a player action
GET /npcs, /npcs/{id}/details NPC list / detail
GET /quests, /quests/{id}/details quest list / detail
POST /quests/{id}/complete deliver the required item to complete a quest
GET /rumors rumors + spread map

Features

All "good-to-have" features from the implementation plan are implemented:

  • High value: auto-tick + adjustable speed, save/load snapshots (💾/📂), deterministic seed control, diff-flash + narration log, "Why?" inspector (an NPC's last rationale + the memories that drove it).
  • Medium effort, high wow: NPC reflection (periodic memory summarization), rumor truth-decay visualization, relationship dynamics (affinity shifts from interactions; cliques surface via NetworkX community detection), weather/ season effects on economy + NPC mood, day/night NPC schedules.
  • Larger: LLM cost guardrails (per-tick call budget + plan cache for unchanged NPCs), deterministic combat resolver (wound/flee/defeat, narrated by the LLM), and an eval harness that replays a fixed sequence and asserts world invariants (uv run python scripts/eval_harness.py).

Deliberately deferred (each a substantial project): vector/semantic memory, multiple kingdoms + politics, multi-agent NPC negotiation, Ollama local-model fallback, multiplayer, and SSE/websocket streaming narration.

Tuning (.env)

WORLD_SEED, MAX_NPC_CONCURRENCY, LLM_TIMEOUT_SECONDS, REFLECTION_EVERY_TICKS, and MAX_LLM_CALLS_PER_TICK (0 = unlimited) tune the simulation. See .env.sample.


Backend template setup

This project is built on a reusable FastAPI template using Python 3.14.2 and uv for fast, reproducible dependency management.

Prerequisites

Install uv (see the docs):

curl -LsSf https://astral.sh/uv/install.sh | sh

Setup

  1. Create a virtual environment with the pinned Python version:
uv venv --python 3.14.2
  1. Activate it:
source .venv/bin/activate
  1. Install dependencies:
uv pip install -r requirements.txt

Run the app

Start the FastAPI server with Uvicorn:

uv run uvicorn main:app --reload

Then hit the health check at http://127.0.0.1:8000/ or http://127.0.0.1:8000/health.

If your FastAPI app is located in a different module, update main:app accordingly.

Test

uv run pytest -v

Docker

Build and run the API with Docker Compose:

docker compose up --build

The image uses the python:3.14.2-slim base and installs dependencies with uv.

Notes

  • uv run executes commands inside the project environment automatically — no manual activation needed.
  • For production deployments, replace --reload with a production-ready configuration.

About

A text-based RPG world sandbox powered by Gemini. Uses LLMs for structured intent parsing, NPC planning, and dynamic narration behind a deterministic validation gate.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages