parththakkar106andClaude Opus 5 be6dbb0f24 Give NPCs their own editor section and unify the world-state boxes
NPCs are still part of stat_schema, but editing them inside the World State
panel meant a nested dashed sub-box among four flat stat lists. They now get
a top-level "Cast & NPCs" section: one card per NPC (avatar, name, npc.<id>
address, triggers, description, its own stats) in a responsive grid, saved
through the same schema path via the new NpcEditor/addNpc exports.

The panel's real inconsistency was CSS, not layout: the global field rule
keys off input[type="..."], which never matches the editor's typeless key and
description inputs, so those rendered with browser defaults beside properly
styled number boxes. One scoped base rule now covers the whole editor and
every entry is the same tile with a caption over each control.

Two bugs fell out of that: .se-band-n (0,1,0) always lost to
input[type="number"] (0,1,1), so band bounds rendered full-width; and the
exclusion has to be :not(:where([type="checkbox"])) because a plain :not()
inherits its argument's specificity and swallows every override.

In Play, NPCs group under a single "Cast" heading as compact plates instead
of each becoming another top-level group in the rail.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UeQVy5bEjLhfgWNc27Efet
2026-08-02 19:46:32 +05:30
2026-07-07 12:30:06 +05:30
2026-07-06 16:58:13 +05:30

AI D&D

An AI Dungeon-style interactive storytelling app you can run entirely on your own machine — with your own AI model. Create scenarios, play open-ended adventures where an LLM narrates the world, and extend the engine with JavaScript scripts compatible with real AI Dungeon scripting.

▶️ Try it live: ai-dnd-1gmp.onrender.com

Play a demo scenario as a guest — no sign-up, no API key needed. (Hosted on Render's free tier, so the first load after it's been idle takes ~30–60s to wake up.)

Built with FastAPI + SQLite on the backend and React (Vite) on the frontend. Works with any OpenAI-compatible endpoint: Ollama and LM Studio locally, or OpenRouter / OpenAI / Groq / vLLM in the cloud — endpoint, key, and model are all runtime settings, and OpenRouter's free-tier models make the whole experience $0.

📸 Screenshots and a demo GIF are coming; for now the fastest tour is running it — one command with Docker.

Features

  • The full play loop — Do / Say / Story / Continue actions, streamed AI responses (SSE), retry, undo, and edit. Reasoning models supported: "thinking" streams into a collapsible 💭 panel with its own token budget.
  • AI Dungeon-compatible context engine — memory, author's note, and story cards (world info) triggered by keywords in recent story text, assembled under a token budget (backend/app/context/builder.py).
  • Insights: total prompt transparency — every turn stores the exact prompt sent to the model; open 🔍 on any AI action to see each context component and why it was included.
  • JavaScript scripting, AI Dungeon-compatible — onInput / onModelContext / onOutput modifiers with shared state and a worldEntries API, executed in an embedded quickjs sandbox (backend/app/scripting/). Real AI Dungeon scripts import and run. In-app CodeMirror editor included.
  • Auto-summarization + Memory Bank — the modern AI Dungeon memory system: AI-generated memories every few actions, a running story summary, and embedding-based retrieval that pulls old-but-relevant facts back into context, with similarity scores visible in Insights (backend/app/memorybank.py).
  • Import/export — AI Dungeon-compatible formats for scripts and scenarios; JSON for everything.
  • Optional accounts for hosted deployments — by default the app is single-user with zero auth friction; set AIDND_MULTI_USER=1 and visitors play instantly as guests (signed session cookie), can register (email + password) at any point to keep their data, and each user gets isolated data plus their own encrypted-at-rest API key. A server-funded shared demo key with a daily turn cap lets people try it without bringing a key (backend/app/auth.py).

Quick start

Docker (any OS)

docker compose up --build

Open http://localhost:8000. Your data persists in a named volume across restarts.

Windows

cd backend; python -m venv .venv; .\.venv\Scripts\pip.exe install -r requirements.txt; cd ..
cd frontend; npm install; cd ..
.\start.ps1

Open http://localhost:5173 (dev servers; API docs at http://localhost:8000/docs).

macOS / Linux

./start.sh   # creates the venv and installs dependencies on first run

Open http://localhost:5173.

Connect a model

Open Settings in the app and point it at any OpenAI-compatible endpoint:

Provider Endpoint URL Notes
Ollama (local) http://localhost:11434/v1 free, private; also serves embedding models for the Memory Bank (e.g. nomic-embed-text)
LM Studio (local) http://localhost:1234/v1 free, private
OpenRouter https://openrouter.ai/api/v1 :free models cost nothing (no embeddings on the free tier)
OpenAI / Groq / vLLM / … provider's /v1 URL anything speaking /v1/chat/completions

Model name, API key, generation parameters, and (optionally) summary/embedding models for the Memory Bank are all configured there too — no config files, no rebuild.

How a turn works

player input
  → onInput script modifier
  → assemble context:  [AI instructions] + [plot essentials] + [story summary]
                       + [retrieved memories] + [triggered story cards]
                       + [story history, token-budgeted] + [author's note] + [player action]
  → onModelContext script modifier
  → snapshot context (Insights)
  → provider adapter → AI (streamed)
  → onOutput script modifier
  → store & render

Architecture

frontend/   React + Vite SPA  ──HTTP/SSE──►  backend/  FastAPI
                                              ├─ routers/      auth, scenarios, adventures, story cards, scripts, settings, debug
                                              ├─ models.py     SQLAlchemy: User, Scenario, Adventure, Action, StoryCard, Script, Settings, Memory
                                              ├─ auth.py       guest/registered users, sessions, shared demo key
                                              ├─ security.py   password hashing, cookie signing, API-key encryption
                                              ├─ context/      prompt assembly under a token budget
                                              ├─ scripting/    quickjs sandbox + AI Dungeon API surface
                                              ├─ memorybank.py auto-summarization + embedding retrieval
                                              ├─ providers/    OpenAI-compatible adapter, streaming
                                              └─ data.db       SQLite (path overridable via AIDND_DB_PATH)

In production the backend serves the built SPA from one port (see Dockerfile); in development Vite proxies /api to FastAPI.

Deploy (Render)

The repo ships a render.yaml blueprint: one Docker web service that serves the SPA and API same-origin, backed by external Neon Postgres (the free tier has no persistent disk, so the database lives off-box).

  1. Create a Neon project and copy its pooled connection string.
  2. In Render: New → Blueprint, point it at this repo. Render reads render.yaml.
  3. Fill the secrets it prompts for (sync: false vars): AIDND_DATABASE_URL (the Neon string) and, to offer a no-signup demo, AIDND_DEMO_API_KEY / AIDND_DEMO_MODELS. AIDND_SECRET_KEY is generated automatically and kept stable across deploys.
  4. Deploy. Pushes to main auto-deploy thereafter. Health check: /api/health.

On the free tier the service sleeps after ~15 min idle; the first request then takes ~30–60s to wake.

Repo notes

  • plan/ — the phased implementation plan this was built from, kept as a build log (phases 1–6 complete; 7–10 cover the public release).
  • backend/.env.example — the few environment variables the backend reads.
  • CODE_REVIEW_FINDINGS.md — notes from a self-review pass.

License

MIT

S
Description
Create an entirely local-based interactive story generator.
Readme MIT
5.8 MiB
Languages
Python 88%
JavaScript 9.7%
CSS 2.2%