Explicit player agency
The scene should set up a meaningful decision. Perspective and agency checks guard against narrating an unchosen player action or treating the player as a separate character.
Engineering case study · AI & TypeScript · 2026
Book RPG started after I jailbroke my e-reader and wanted to make interactive stories work with as little logic on the device as possible. The result is a client/server story engine: choose a character, act and talk from their perspective, and follow the original story or take a different route while the server keeps the world coherent.
This demo, including its frontend, runs on an Azure server that scales to zero when idle. The first visit after inactivity may take longer while the server starts up.
The project began with a practical constraint: I had jailbroken my e-reader and wanted to experiment with an interactive book without turning the device itself into the story engine.
That pushed the architecture toward a thin client. A device client should only need to display the current scene and choices, collect input and send HTTP/JSON requests. EPUB import and indexing, AI calls, story progression, validation and saved games belong on the server.
The browser and Node.js terminal clients already use that separation. A KOReader/Lua client is still a future device target, so this is an architectural direction rather than a claim that the current application is already an e-reader product.
A scene can read beautifully and still be wrong. A character might know something too early, act from the wrong perspective, or complete a decision before the player makes it.
The core problem is coordinating source material, player agency and persistent state. The engine needs to distinguish what has happened, what can happen now, and what still belongs to the future.
The original book provides a canonical route. It is a reference for progression, while the interactive timeline can diverge when the player makes a different choice.
Extract chapters from an EPUB, resolve character identities and organize source events into ordered story beats.
Use the selected character, current story progress and game history to create a scene with meaningful actions.
Validate generated output and review continuity, presence and choices before accepting the next game state.
The scene should set up a meaningful decision. Perspective and agency checks guard against narrating an unchosen player action or treating the player as a separate character.
Completed beats are tracked for the active event. The engine tracks which source actions are still in the future and checks whether they remain compatible with the interactive timeline.
Conversation choices open a separate dialogue state. The browser also supports free-text actions, turn history, undo and persistent world rules.
OpenAI and xAI adapters sit behind one engine layer. Structured responses are validated before acceptance, with bounded generation attempts and retries.
The current implementation uses Node.js and TypeScript. A responsive browser client and a terminal client both talk to the same HTTP API. The clients present state and collect input; the server owns book analysis, AI orchestration, progression rules and persistence.
Local development uses file-backed repositories. The Azure configuration uses Blob Storage for analyzed books and Cosmos DB for user-scoped game saves. A Docker image and Bicep infrastructure support deployment to Azure Container Apps.
That boundary is what makes a small KOReader/Lua client feasible later: it can reuse the same server rather than duplicate the story engine on the e-reader. The repository already includes a Kindle-oriented data package, but the browser and Node clients are the current implemented interfaces.
The public snapshot was exported from the development code on 21 September 2026 and validated as a standalone repository. With Node.js 24.20.0 on Ubuntu, the TypeScript build passed and all 1,120 regular tests passed with 0 failures and 0 skipped tests. The same exported test suite also passed locally on Windows.
The tests cover source progression, player agency, validation, persistence, authentication, world rules, bridge logic and other deterministic behaviour. Separate Playwright tooling exercises the browser interface and repeated multi-turn flows.
Per-game logs record source progression, AI inputs and outputs, rejected generations and saved turns. These tools help reproduce failures such as premature dialogue suggestions, perspective drift and scenes that do not make the next action possible.
This remains an experimental AI application. Passing deterministic tests does not prove that every live model response, EPUB or sequence of player choices will behave correctly. Live-model evaluation and real e-reader testing remain separate concerns, and no aggregate reliability or latency benchmark is claimed here.
Amsterdam 750 explores a different set of constraints: high-demand registration and personal data protection. Its case study includes a public implementation and published load-test evidence.