Checkpoint current interactive fiction state

This commit is contained in:
2026-05-14 21:17:43 +02:00
parent c745efd1d2
commit 873049f7e6
183 changed files with 13755 additions and 1459 deletions
+186 -38
View File
@@ -1,38 +1,186 @@
# AI Interactive Fiction
A modern take on classic text adventures that combines traditional world modeling with Large Language Models (LLMs) to create natural language interactive fiction experiences.
## Project Overview
This application reimagines the classic text adventure game genre by replacing the traditional parser with an LLM. The system consists of:
1. **World Model**: A traditional game engine that manages rooms, objects, actions, and game state - similar to old-school Infocom games.
2. **LLM Interface**: An AI layer that processes natural language input from players and translates it into actions the game engine can understand.
3. **Narrative Generation**: The LLM converts the world state changes into rich, contextual prose for the player.
## Key Features
- **Natural Language Understanding**: Players can express their intent in plain language without worrying about specific command syntax.
- **Rich Narrative**: Dynamic descriptions that adapt to the current game state and player history.
- **Consistent World Model**: The underlying game engine enforces world rules to prevent hallucinations or inconsistencies.
- **Modular Design**: Easily swap between different world models, including YAML-based custom worlds or integrations with classic Z-machine games.
## How It Works
1. Player enters natural language input
2. LLM analyzes input and translates it into game actions
3. Game engine processes valid actions and updates the game state
4. LLM receives the state change information and generates narrative prose
5. Player receives the beautifully written response
## Technical Structure
- YAML-based world definition (rooms, objects, actions)
- OpenRouter API integration for accessing suitable LLMs
- Modular design allowing for Z-machine integration in the future
## Getting Started
[Installation and running instructions will be added here]
# AI Interactive Fiction
AI Interactive Fiction is a web and CLI text adventure prototype that combines a deterministic world model with LLM-assisted command interpretation and narrative output. The web client presents the story as an animated, novel-like book page with synchronized text animation, optional TTS, music, and sound effects.
## Quick Start
Use Node.js 22 LTS for development. The project accepts Node >= 18.17, but current development has been done on Node 22.
```powershell
nvm install 22
nvm use 22
npm install
npm run build
npm run dev
```
The web app starts on `http://localhost:3000` when launched through `src/index.ts` or `dist/index.js`. The lower-level server module defaults to `3001` when started directly. Set `PORT` to choose a port; the server will try the next few ports if the requested one is already in use.
## Commands
```powershell
npm run dev # Start the web UI through ts-node/nodemon
npm run start # Run the compiled web server from dist/
npm run build # Compile TypeScript
npm run test # Run Jest tests
npm run lint # Run ESLint on src/
npm run start:cli # Run the CLI interface
npm run dev:cli # Run the CLI interface through ts-node/nodemon
```
## Configuration
Environment variables are loaded from `.env`.
- `PORT`: preferred web server port.
- `DEFAULT_WORLD_FILE`: YAML world file to load. Defaults to `./data/worlds/example_world.yml`.
- `OPENROUTER_API_KEY`: API key for LLM command interpretation.
- `OPENROUTER_MODEL`: OpenRouter model name.
TTS provider settings are configured in the browser options menu and persisted in browser storage. Providers currently include `none`, browser speech synthesis, Kokoro, ElevenLabs, and OpenAI. Production should not assume a universal TTS default; the game or player state selects the active mode, and `none` is the safe fallback.
## Starting A Game
The web client no longer starts the game automatically. Browsers require a user gesture before audio playback, so the right page initially shows a start prompt and the command input is hidden. Use `new game` or `load` in the top bar to start.
The placeholder server API supports:
- `newGame()`
- `loadGame(slot)`
- `saveGame(slot)`
- `hasSaveGame(slot)`
- `getSaveGames()`
- `isGameRunning()`
Save slots are positive integers. In the current placeholder implementation, save availability is per socket session and is lost on reload. Loading a save starts the demo content like `newGame()`.
## Web Client
The browser app is built from native ES modules in `public/js/`. The loader dynamically imports modules, applies a cache-busting query string during development, resolves declared dependencies, and awaits module initialization in dependency order before the UI becomes usable.
Major modules:
- `module-registry.js`, `base-module.js`, `loader.js`: module lifecycle, dependency graph, progress overlay, state reporting.
- `text-processor-module.js`, `paragraph-layout-module.js`, `layout-renderer-module.js`: SmartyPants, language-aware hyphenation, Knuth-Plass line breaking, DOM rendering.
- `markup-parser-module.js`: story markup for chapters, sections, Markdown emphasis, images, SFX, and music.
- `sentence-queue-module.js`, `playback-coordinator-module.js`, `animation-queue-module.js`: sentence preparation, synchronized playback, timing, fast-forward.
- `tts-factory-module.js` plus provider modules: TTS provider selection, voice settings, speed mapping, caching, and playback.
- `audio-manager-module.js`: master, speech, music, and sound effect volume, music playback, sound effects, and music ducking.
- `ui-controller-module.js`, `ui-display-handler-module.js`, `ui-input-handler-module.js`, `options-ui-module.js`: book UI, command input, options, top-bar controls, and game API calls.
The static server sends no-cache headers for local development so stale ES modules do not mask changes. If the browser console shows `onpage-dialog.preload.js:121 Uncaught ReferenceError: browser is not defined`, ignore it; that comes from the installed ad blocker, not this project.
## Story Markup
Plain paragraphs are rendered paragraph by paragraph. Normal following paragraphs are horizontally indented and do not get a blank line between them. Special block markers change the treatment of the next paragraph.
Inline Markdown emphasis:
```text
*italic* or _italic_
**bold** or __bold__
***bold italic*** or ___bold italic___
```
Chapter:
```text
::chapter[The Mysterious Mansion]
The first paragraph uses a drop cap and no first-line indent.
Following paragraphs use the normal paragraph indent.
```
The heading is centered, italic, and uses the same text face as the body. The first paragraph after a chapter marker is unindented and receives the drop cap treatment.
Section or text block:
```text
::section
The first paragraph starts a separated block without horizontal indent.
The following paragraph returns to the normal indent.
```
`::textblock` is treated the same way. The first paragraph after the marker is separated from previous content by one line of vertical space.
Images are parsed for future rendering:
```text
::image[widescreen](mansion-rain.jpg)
::image[portrait](portrait-letter.jpg)
```
Image file names are relative to `public/images/`. `widescreen` means 100% page width and 50% page height. `portrait` means 100% page width and 100% page height.
Sound effects can be placed inline:
```text
The door opens {{sfx:squeaky-door.ogg}} and the hall exhales.
```
The marker is removed from display text and TTS text. It becomes a timed media cue that fires when the text animation reaches that point. Sound effect paths are relative to `public/sounds/`.
Music can be placed as a block:
```text
::music[crossfade, loop, lead=4](rain-theme.ogg)
```
Music can also be placed inline:
```text
The candles gutter. {{music:cut:danger.ogg}} Something moves upstairs.
```
Music paths are relative to `public/music/`. Supported modes are `queue`, `crossfade`, and `cut`. Use `loop` or `once` to control repetition. `lead=<seconds>` delays the following text/TTS paragraph so the music can play alone before narration continues.
## Assets
- `public/sounds/`: sound effects referenced by `{{sfx:file}}`.
- `public/music/`: background music referenced by `::music[...]` or `{{music:mode:file}}`.
- `public/images/`: story images referenced by `::image[...]`.
- `public/fonts/`: font assets used by the book UI.
Keep third-party assets licensed for local redistribution, and document source and license in the folder README or alongside the file.
## Typography And Playback Behavior
The renderer is designed to behave like a scaled static book page. The page keeps its aspect ratio, and text sizes and word positions scale relative to the page instead of reflowing unpredictably at small browser sizes.
Text processing order:
1. Parse story markup and remove non-display media markers.
2. Apply Markdown emphasis spans.
3. Run SmartyPants for typographic punctuation.
4. Apply Hyphenopoly for the selected language.
5. Calculate line breaks with the Knuth-Plass algorithm.
6. Render absolutely positioned word spans and animate them in sync with audio or estimated duration.
When real TTS audio is available, animation duration is driven by measured audio length. With TTS disabled or unavailable, duration is estimated from text length and the persisted speed setting.
Fast-forwarding by page click or space completes the active animation and fades/stops current TTS playback so queued content can proceed.
## Changelog
### 2026-05-14
- Consolidated usage, markup, and architecture documentation into `README.md` and `CLIENT_TODO.md`.
- Added no-cache static serving and module URL cache busting so browser reloads pick up JS changes reliably during development.
- Fixed module loader dependency ordering so modules are initialized only after their declared dependencies are ready.
- Added the placeholder game API for `newGame`, `loadGame`, `saveGame`, `hasSaveGame`, `getSaveGames`, and `isGameRunning`.
- Changed the web UI to require a manual game start before showing the command input, which keeps browser audio autoplay restrictions manageable.
- Implemented story markup for chapters, text blocks, Markdown emphasis, image placeholders, sound effects, and music cues.
- Added music block parameters for playback mode, loop/once behavior, and lead-in delay.
- Added sound and music asset folders and playback plumbing for sound effects and background music.
- Added music ducking while TTS is active.
- Reworked book typography around Knuth-Plass line breaking, Hyphenopoly hyphenation, SmartyPants, paragraph indentation rules, drop caps, and responsive page scaling.
- Reworked TTS provider behavior, speed mapping, persistence, caching keys, top-bar/options synchronization, and OpenAI voice validation.
- Added development notes for ignoring the unrelated ad-blocker console error.
### Earlier Prototype Work
- Established the original animated fiction prototype with inkjs, SmartyPants, Hyphenopoly, Knuth-Plass line breaking, custom animation scheduling, save/load concepts, and media tags.
- Split the client from a monolithic prototype into focused modules for text processing, layout, animation, audio, persistence, TTS, and UI control.