When I was a kid, I devoured those short, fast-paced branching horror books — the Goosebumps-era choose-your-own-nightmare stories where the ending depended on which page you flipped to. Years later, after nearly a decade as a full-stack engineer, I started wondering something.
Could AI generate an interactive novel that actually remembers everything?
Not a choose-your-own-adventure with pre-written branches. A living story — one that tracks what you did fifty pages ago, holds a grudge, and waits for the right moment to twist the knife.
That question became Twistloom. And what started as a curiosity project turned into a distributed AI orchestration system spanning 9 LLM providers, RAG-based semantic memory, and a structured story engine that refuses to forget.
People imagine AI storytelling as a single prompt
Usually, people picture AI fiction like this:
Write me a horror story...
Done.
But after building Twistloom, I realized the hardest part was never generating text. LLMs are astonishingly good at that. The hard part is maintaining consistency across hundreds of pages while every reader continuously changes the story.
A character shouldn't suddenly change personality. A missing key shouldn't magically reappear. Someone who died fifty pages ago shouldn't casually walk back into the scene. Every generated page has to understand everything that happened before it — and that problem turned out to be far more interesting than generation itself.
What Twistloom actually is
For a reader, Twistloom looks deceptively simple.
You type a story idea:
A detective in a city where the rain never stops starts receiving letters from victims who haven't died yet.
Within minutes, a full branching psychological thriller appears. Every page ends with choices — generated by the AI, tailored to your character's situation. Pick one, and the world responds.
And sometimes, the AI doesn't offer you the option you want at all. So you can type your own — a custom action, anything. The system checks if it's plausible, scores it, and generates a page for it anyway. You tried to pick the locked door? It'll write what happens when you do.
There are three story shapes:
| Mode | What it feels like |
|---|---|
| Novel | A straight line — one page after another, toward a single ending. |
| Interactive | A choose-your-own-nightmare — every choice closes one door and opens another. |
| Multiverse | Every choice generates multiple alternate realities. Re-read the same book and uncover endings you didn't know existed. |
That last one is the one people don't believe at first. In Multiverse Mode, two readers making identical choices may still walk away with different stories. The system continuously generates candidate branches in the background, so spoilers are effectively dead. No two playthroughs are the same.
The choices echo through the story: characters remember kindness and betrayal, your sanity meter rises and falls with the tension, clues you missed stay buried — and the ending adapts to what you actually did, not what an author planned.
The engineering challenge wasn't AI — it was memory
Here's the thing about writing with an LLM: a text-generation call has no memory of anything except what you stuff into its context window. If you want a coherent 300-page branching novel, you can't just paste the whole book in every time.
So Twistloom doesn't treat the story as flat text at all. Every page carries a structured narrative state snapshot. Behind the scenes, the backend tracks:
- character psychology, archetype, and stability
- relationships and interaction history
- discovered clues and open mysteries
- places, locations, and their atmosphere
- facts history — durable fact evolution per entity
- the world clock, mood, weather, date and time
- scene momentum and narrative threads
- hidden state — truth level, threat proximity, reality stability, and the planned ending
When the AI writes the next page, it doesn't just get the previous paragraph. It gets the state of the world. Consistency stops being a hope and becomes a data structure.
And there's a lot of state. To keep reconstruction fast, I built a hybrid delta + checkpoint architecture: snapshots are persisted every 5 pages, and everything between is stored as incremental deltas. Reconstructing a story state is roughly 90% faster than replaying every page from scratch.
When context windows aren't enough: RAG with Jina AI + pgvector
Even with structured state, there's a ceiling. Character backstories, world lore, clues discovered thirty chapters ago — you can't ship all of it to the model every single time.
That's where Retrieval-Augmented Generation comes in.
Twistloom embeds narrative memories using Jina AI embeddings and stores them directly in PostgreSQL using pgvector. Instead of replaying the entire novel to the model, only the memories most relevant to the current scene are retrieved at generation time.
I split semantic memory into five dedicated embedding tables (1024-dimensional, HNSW-indexed for fast ANN search):
page_embeddings — the narrative prose itself
character_embeddings — who everyone is, and how they feel
place_embeddings — where scenes happen
future_note_embeddings — deferred payoffs scheduled by the world clock
clue_embeddings — the trail of breadcrumbs readers might miss
When a page is about to be written, the engine embeds the current context, queries the nearest memories across these tables, and injects only the relevant fragments into the prompt. Embeddings are inserted fire-and-forget after each page persists — never during delta-chain replay, so semantic memory never slows down state reconstruction.
The result is a story engine that remembers far more than any context window would allow, without blowing up prompt size.
One AI provider wasn't enough
Most AI applications depend on a single provider. That works — until it doesn't.
Rate limits. Regional outages. Model deprecations. Temporary failures. For an experience where a reader is mid-scene and waiting for the next page, a provider outage isn't an error log — it's a ruined reading session.
So Twistloom abstracts every provider behind a common interface, and orchestrates nine different LLM providers in a waterfall:
gemini → github → cohere → mistral → groq → cerebras → nvidia → openrouter → cloudflare
If one provider is rate-limited, degraded, or down, the request automatically falls through to the next. The business logic never cares which provider generated a page — providers are interchangeable implementations of the same contract. The reader experience continues regardless of what happens to any single vendor.
One insight that shaped the whole design: resilience isn't a feature you bolt on at the end. It's an architectural decision you make on day one, in how you define the provider interface. If your code is written against a single SDK, adding a second provider later is a rewrite. Written against a contract, it's a config change.
Every page is generated twice
Another thing I learned fast: LLMs occasionally produce surprisingly good stories — and occasionally complete nonsense.
Instead of trusting a single response, every generation passes through a two-call pipeline:
- A primary call generates the page, its actions, and the state updates.
- A second call — a different model, a different prompt — acts as an evaluator judge. It scores the page for quality, coherence, and correctness before it ever reaches the reader.
On top of that, every page runs canon validation (runCanonValidationPass()): the engine checks for timeline contradictions, character knowledge violations, established fact conflicts, and personality inconsistencies. If a page breaks canon, it's flagged and rewritten — at generation time, not discovered by an angry reader three chapters later.
Custom actions get their own three-gate pipeline:
- Gate 0 (client): regex safety patterns guard against prompt injection.
- Gate 1 (AI): plausibility + progression scoring — will this action move the story forward?
- Gate 2 (generation): the outcome page, with full canon validation.
And the branching contract is enforced at the database layer, not by convention. Novel mode allows one action per page and one destination. Interactive allows 2–6 actions. Multiverse allows 2–6 actions with unlimited destinations. The backend rejects anything that violates the mode contract, so the story graph stays structurally valid no matter what the model outputs.
Because generation is expensive, books are created asynchronously — a GitHub Actions worker handles the heavy lifting while you watch progress stream in via polling. You can start a book and come back when it's done.
The tech stack
The whole thing runs on the JAMstack of my dreams:
Frontend
- Next.js 16 (App Router, ISR, Server Components) + React 19
- TypeScript across the full stack
- Tailwind CSS v4 with tension-driven theming — the UI colors literally bleed darker as the story's tension rises
- next-intl for full English and Indonesian locale support
- TanStack Query for server state, Zustand for client state
- NextAuth v5 for cookie-based JWT auth, TipTap for the admin's rich editor
Backend
- Hono — ultra-fast, runtime-agnostic HTTP framework
- Drizzle ORM for type-safe SQL
- Neon PostgreSQL (serverless) with pgvector for semantic memory
- GitHub Actions as the async generation runner
- Stripe for the credit economy, ImageKit for media, Resend for email
AI
- 9 LLM providers with automatic fallback
- Jina AI embeddings + pgvector RAG pipeline
- Structured JSON generation, two-call evaluation, canon validation
Everything is deployed on Vercel serverless. Public pages are ISR-cached (60–300s), reader pages are cached for fast loads, and the generation UX is built so the modal opens instantly on click — before the first network request completes — with progress streaming in as the story assembles piece by piece.
More than an AI story generator
When I started, I thought I was building a branching horror generator.
After several months of solo work, I realized I was building something much bigger: an AI-native interactive fiction platform. Not a text generator — a platform where readers get living stories, and where writers will eventually sit down with an AI as a creative partner, not a replacement.
My long-term vision isn't AI-authored slop. It's giving real authors a co-pilot that:
- remembers their lore
- understands their characters
- protects their canon
- and suggests ideas without seizing the pen
The AI should write with you — never for you. That's the difference I care about most.
Right now the platform is free to use, because I'm running on non-commercial free-tier LLM API keys and can't legally commercialize yet. The credit economy, subscriptions, and gamified systems are all built and ready — the commercial switch is a configuration away.
What I learned
This project taught me something unexpected.
The hardest problem in AI storytelling isn't prompting. It's software engineering. Building resilient orchestration. Managing long-term memory. Designing structured pipelines. Keeping generated worlds internally consistent. Testing, optimizing, and shipping it all as a solo developer.
Generating text is easy.
Generating believable worlds is much, much harder.
If you've made it this far, I'd genuinely love your feedback — whether you're into AI engineering, interactive fiction, or just building unusual things. And if you want to see what an AI-native thriller actually feels like, step into the loom:
👉 https://twistloom-web.vercel.app
The story remembers. Every choice leaves a scar. 🩸



Top comments (0)