## Summary The Style Reviewer judges prose habits, and its findings are injected into the narrator's system prompt as `<style_guidance>`. Given raw entries, it also judged the markup (`<pic>` prompts, Visual Prose HTML, `### Time | Place` headers, `---` rules), so a finding about markup became an instruction to the narrator. This adds one configurable narration cleaner, puts the reviewer and the classifier on it, and adds a **Clean Input** switch for the reviewer. The reviewer now reads plain prose, and the classifier still reads the header text that carries the time and place. The HTML stage parses with the DOM. The narrator's markup renders as real HTML (`marked` passes well-formed tags through raw; Visual Prose goes through `template.innerHTML`), so the cleaner reproduces what the reader sees: `<Kael>` is an invisible unknown element on screen and vanishes in the cleaned text too, and entities decode as the browser decodes them. A DOM parse also handles tag case, hyphenated names, unclosed tags and entities without a hand-kept tag list. Design, per-option behaviour and the experiment behind it: `docs/architecture/narration-cleaning.md`. ## Changes - **`utils/narrationClean.ts`** (new): per-markup modes (`keep` / `unwrap` / `remove`) and presets `CLEAN_NONE`, `CLEAN_FOR_REVIEW`, `CLEAN_FOR_CLASSIFICATION`. - The HTML stage parses with `template.innerHTML` (inert: scripts don't run and nothing loads) and walks the tree. Unknown and custom elements are unwrapped, `<style>`, `<script>` and comments are dropped, `<em>` / `<strong>` become `*` / `**`, block ends break lines, and table cells are separated by a space. - A `<` that does not begin a well-formed tag is escaped before the parse, copying `marked`'s inline `tag` rule, so `3 < 5`, `x<y and then…` and `<https://example.com>` stay text. A test runs a table of inputs through `marked`'s `Lexer.lexInline` to keep the two in agreement across upgrades. - `<pic>` tags (`<pic … />` and `<pic …></pic>`) are removed by a regex stage that runs first. - **Style Reviewer**: `buildReviewPassages` cleans each entry, skips one that cleans to nothing, and numbers the rest. **Clean Input** (Advanced Settings, `styleReviewer.cleanInput`, default on) switches to `CLEAN_NONE` through the same path. - **Classifier**: moved onto `CLEAN_FOR_CLASSIFICATION`, which unwraps heading and bold-line text for the time and place fields. `stripNarratorMarkup` is removed. - **New devDependency: `jsdom`.** The default test environment stays `node`; a file that reaches the HTML stage opts in with `// @vitest-environment jsdom` (`narrationClean.test.ts`, `styleReviewPassages.test.ts`). `devEngines` moves to `^24.15.0`, the floor jsdom 30 needs; `.nvmrc` resolves to the latest 24.x. - CRLF blank lines collapse in the final pass. - Docs: `narration-cleaning.md` (new), `testing.md`, the docs index and the `CLAUDE.md` table. ## Behaviour to know about - The HTML stage needs a `document` when the text contains `<` or `&`. The app always has one (SPA, `ssr = false`); under `node` the stage throws a `ReferenceError`. - In Visual Prose the browser parses the raw content and is stricter than `marked`, so a malformed tag there hides text on screen while the cleaner keeps it. The Visual Prose prompt asks for valid HTML, and the cleaner shows the reviewer the extra text. - `pic: 'keep'` combined with `html: 'unwrap'` drops the tag as an unknown element and keeps the prose around it. - A whole-line bold speaker or name label (`**Kael**`) is removed as a heading under `boldLines: 'remove'`; **Clean Input** switches that off. - jsdom stands in for the WebView's parser in tests, and the manual check below covers the real WebView. ## Test plan - [x] `check`, `test` and `lint:fix` pass (2012 tests) - [ ] In `tauri dev`, with Visual Prose on and inline images on, trigger a style review and check the dev log: the rendered `passages` variable is plain prose, and the prose after a `<pic>` tag is kept - [ ] A narration with a literal `<Kael>` reads the same to the reviewer as it does in the story view - [ ] The classifier fills time and place from a `### Time | Place` header and from a Visual Prose passage - [ ] The **Clean Input** switch turns cleaning off 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01YHkuCEJRUTBnsZaUnhfR9N <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added a “Clean Input” setting for Style Reviewer, enabled by default. When on, it cleans narration before review; when off, original text is retained. * Improved narration cleanup for reviews and classification, including handling of markup, images, and layout. * **Chores** * Updated the minimum required Node.js version. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com> |
||
|---|---|---|
| .cargo | ||
| .github | ||
| docs | ||
| scripts | ||
| src | ||
| src-tauri | ||
| static | ||
| third-party-licenses | ||
| .gitattributes | ||
| .gitignore | ||
| .nvmrc | ||
| .prettierrc | ||
| CLAUDE.md | ||
| compileApk.sh | ||
| components.json | ||
| eslint.config.js | ||
| lefthook.yml | ||
| LICENSE.md | ||
| logo.png | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| sun4.jpg | ||
| sun17.jpg | ||
| sun2022.png | ||
| svelte.config.js | ||
| tsconfig.json | ||
| vite.config.js | ||
| vitest.config.ts | ||
Aventuras
Interactive fiction with an AI that remembers. Play a text adventure or write collaboratively, on desktop and Android, with any LLM provider you like — cloud or running on your own machine.
Aventuras keeps the story straight: chapters are summarized as you play, a lorebook feeds the right entries into the right scene, an agent tidies that lorebook behind you, and the world state — who is present, where you are, what you carry — is tracked turn by turn.
Highlights
- Two modes — Adventure, with multiple-choice actions and world tracking; Creative Writing, freeform with AI suggestions. First/second/third person, past or present tense.
- Any provider — OpenRouter, OpenAI, Anthropic, Google, xAI, Groq, DeepSeek, Mistral, Z.AI, NanoGPT, Chutes, Pollinations, NVIDIA NIM, plus local llama.cpp, LM Studio and Ollama. Streaming, extended thinking, and per-subsystem Agent Profiles so retrieval, classification and narration can each use a different model.
- Memory that scales — automatic chapter summarization, and a retrieval step that goes and finds what the current scene needs from everything that came before.
- Lorebook — characters, locations, items, factions, concepts and events, with aliases, secrets, keyword and relevance-based injection, SillyTavern import, and an autonomous agent that consolidates duplicates and fills gaps.
- The Vault — a cross-story library of reusable characters, lorebooks and scenarios, with a tool-calling assistant that edits them and shows you a diff before anything lands.
- Every prompt is editable — they are Liquid templates, all of them, in an in-app editor.
- Images — inline
<pic>illustrations, scene backgrounds and character portraits, across nine backends including local ComfyUI and A1111. - Writing tools — local grammar checking (Harper/WASM), style analysis for repetition, suggestions that match how you write.
- Yours to keep — SQLite on your machine, full backup/restore,
.avtstory export, LAN sync between devices over QR pairing, and an optional translation layer over the whole app. - 26 themes, adjustable text size, dialogue highlighting.
Install
Pre-built binaries are on the Releases page:
| Platform | Download |
|---|---|
| Windows | Aventuras_vX.Y.Z_x64-setup.exe |
| macOS | Aventuras_vX.Y.Z_x64.dmg / _aarch64.dmg |
| Linux | Aventuras_vX.Y.Z_amd64.deb / .AppImage, or _x86_64.rpm |
| Android | Aventuras_vX.Y.Z.apk |
| iOS | Aventuras_vX.Y.Z_ios-arm64-unsigned.ipa (sideload; unsigned) |
No API keys in config files — providers are set up in the app, under Settings → API Settings.
Build from source
Requires the Node.js version in .nvmrc, the latest stable Rust, (for Android) the
Android SDK, NDK r27d and JDK 21–24, and (for iOS) a Mac with Xcode.
git clone https://github.com/AventurasTeam/Aventuras.git
cd Aventuras
npm install
npx tauri dev
| Script | Does |
|---|---|
npm run dev |
Vite dev server (frontend only) |
npx tauri dev |
full app, with hot reload |
npm run build |
production build |
npm run check |
type checking (svelte-check) |
npm test |
test suite (Vitest) |
npm run lint |
ESLint — lint:fix to fix |
npm run format |
Prettier |
npm run release |
version bump, tag and push |
Desktop builds are npx tauri build; Android and iOS are documented in
docs/development/release.md. iOS produces an unsigned
device .ipa (no Apple certificates or signing secrets — see
docs/development/ios-build-target.md for the full
account of how the target was added and how the unsigned CI pipeline works).
Tech stack
TypeScript (strict) · SvelteKit 2 · Svelte 5 runes · Tauri 2 (Rust) · Tailwind + shadcn-svelte ·
SQLite (tauri-plugin-sql / sqlx) · Vercel AI SDK · LiquidJS · CodeMirror 6 · Zod ·
Harper.js (WASM) · Vitest
Contributing
Start with docs/ — the architecture is documented per area, and
CLAUDE.md has the conventions. CI runs lint, type-check, tests and a build on every
PR against master, develop or dev.
Acknowledgments
Tauri · SvelteKit · OpenRouter · Harper · Lucide
License
AGPL-3.0