Inspiration
I first saw a model tell an interactive story in AI Dungeon on GPT-2. That was seven years ago. Now local models can generate text, audio and images at good quality on your own hardware, but there is no app that is easy to set up and does all three across your own devices. So I built Plottery. The current version supports text, voices and pictures. Games in this style do not have to be only text. In the Worlds mode you walk around a generated map instead of reading a page. It is in the desktop app for now.
What it does
Plottery is a role-playing game where the AI runs on your own hardware. You write one sentence and the model turns it into a scenario. Then you play it. Each turn you write what your character does, with a d20 roll first if the outcome is uncertain, and the model writes what happens next. It also keeps the characters and the world up to date as the story moves on. Tap the image button and your own computer generates a picture of the scene and sends it to the phone. Tap the audio button and the app reads the story in a voice it generated from a written description. When you like a scenario, you can publish it to Community, where players share scenarios and characters. The Community page is accessed through a monthly subscription, sold through the App Store with RevenueCat. Playing is free.
How I built it
The app is a Tauri shell with a React and TypeScript frontend and a Python FastAPI backend. On iOS the backend is embedded CPython, with llama.cpp, stable-diffusion.cpp and Qwen3-TTS cross-compiled for the phone. The narrator writes the prose, and after that the app asks the model a series of small questions with fixed answer formats, such as who is in the scene now, what changed hands and how much time passed. Even a 2B model on a phone can answer questions like these, and that is what keeps a long story consistent. Accounts and Community are on Supabase. Payments go through RevenueCat on iOS and Stripe on the desktop, with one entitlement per account.
Challenges
Small models are the hard part. A 2B or a 12B model does not follow a long prompt the way a hosted model does. It drifts, it speaks for the player, it forgets who is in the room. So the app gives it one small task at a time to build the context for the storytelling. Each of those tasks answers in a fixed JSON shape, enforced by a grammar at generation time, so a small model cannot hand back something the game cannot read.
The most common failure was the narrator writing what the player says or decides. Iterating the prompts against the benchmark was very useful for this: it counts how often that happens, so I could see which prompt changes helped and which only looked better.
What I learned
Evals with a model as the judge worked better than I expected. The app has a benchmark that runs its own tasks against any local model, and I use it to improve the prompts.
What's next for Plottery
- Android, on the same embedded backend as the iPhone app.
- A phone layout for Worlds and other improvements. The worlds game mode has room to grow.
- Better template creation, and better context handling in stories and worlds.
- Small encoder models for the fast decisions before the language model runs.
Built With
- fastapi
- gguf
- hugging-face
- llama.cpp
- nuitka
- playwright
- postgresql
- pydantic
- python
- qwen3-tts
- react
- revenuecat
- rust
- sqlite
- stable-diffusion.cpp
- stripe
- supabase
- swift
- tailwind-css
- tauri
- tls
- typescript
- uvicorn
- vite
- xcode


Log in or sign up for Devpost to join the conversation.