Writing Adventures for Narratron Buddy
Welcome to the Narratron Buddy Adventure Authoring Guide! This document provides everything you need to create, test, distribute, and submit your own interactive narrative adventures.
1. Overview & Architecture
A Narratron Adventure is a self-contained content package that turns Narratron Buddy into a tailored, multimodal storytelling experience. An adventure defines:
- Narrative Logic & Agent Persona (
theater.yaml): Custom instructions, story planning rules, persistent "sticky note" tracking, art direction, and pacing controls for Google Gemini. - Package Metadata (
metadata.json): Title, description, genre tags, author credits, difficulty, and player count. - Optional Game (
game/game.yaml): State, rules, actions and board layout for turn-based transactional games. Main transactions require player and Narratron acceptance, or rules that strongly bound each side's actions before the other acts. Real-time game environments are unsupported. YAML supports comments and multiline expressions;game.ymland existinggame.jsonpackages also work. See the interaction model and conceptual tests, package format, and commented example adventure. - Lore Context (
lore/): Deep backstory, world lore, factions, secrets, and NPC motivations provided directly to the language model. - Characters (
references/characters/): One folder per character containing its portrait iterations. - Visual References (
references/): Maps, item designs, environment images, and cover artwork used to guide generative image tools. - Atmospheric Audio (
playlists/): Loopable background music, ambient soundscapes, and thematic tracks organized into switchable playlists.
2. Distribution & Getting Featured
Independent Distribution (Freely Distribute!)
All adventures are standard folder packages. You are free to package and distribute your adventures however you like!
- Zip your adventure folder and share it directly with friends or on Discord.
- Publish it on GitHub, itch.io, or gaming forums.
- Anyone running Narratron Buddy can drop your folder into their
adventures/directory and immediately start playing.
Getting Featured on narratron.app
If you would like your adventure to be hosted in the official cloud library and featured directly on narratron.app for all web users:
- Verify your adventure using the Testing Guide and Pre-Submission Checklist.
- Ping
syclonexon Discord with a link to your repository or your zipped package to request inclusion!
3. Getting Started: Developer Setup
To build an adventure with the recommended workflow:
Step 1: Download an IDE
We recommend using a modern code editor such as:
Step 2: Clone the Git Repository
Open your terminal and clone the narratron-buddy repository:
git clone https://github.com/siddtheshah/narratron-buddy.git
cd narratron-buddy
Step 3: Install uv and Dependencies
This project uses uv for fast Python environment and package management:
# Create a virtual environment and install project dependencies
uv venv
. .venv\Scripts\Activate.ps1
uv pip install -r requirements.txt
Step 4: Configure Your Gemini API Key
To test story planning and dialogue generation locally:
- Copy
.env-templateto.env:
Copy-Item .env-template .env
- Open
.envand fill in your Gemini API key:
GEMINI_API_KEY="your_actual_gemini_api_key_here"
(You can obtain a free API key from Google AI Studio).
4. Adventure Package Structure
All adventures live in subdirectories under adventures/. Take a look at adventures/example_adventure/ in this repository as an official working reference template.
A complete adventure package looks like this:
adventures/my-custom-adventure/
βββ metadata.json # Package metadata & UI display attributes
βββ theater.yaml # Story planning rules, agent persona & tool config
βββ README.md # (Optional) Notes for players/developers
βββ lore/ # Lore text files read by the agent
β βββ RESPONDER.md # Pinned immediate-response instructions
β βββ PLANNER.md # Pinned background-planning instructions
β βββ RECORDER.md # Pinned factual recording and game-action instructions
β βββ factions/
β β βββ rebels.txt
β βββ locations/
β βββ citadel.txt
βββ references/ # Location images, portraits, and cover art
β βββ characters/ # One folder per character
β β βββ Keeper Orun/
β β βββ 1.webp
β βββ cover.webp
βββ playlists/ # Thematic audio folders with sound files
βββ ambient/
β βββ wind_whispers.mp3
βββ combat/
βββ intense_percussion.mp3
4.1. metadata.json Specification
metadata.json provides catalog details for the adventure browser:
{
"id": "my-custom-adventure",
"title": "Secrets of the Obsidian Spire",
"description": "Infiltrate a forsaken crystal spire and decipher its ancient astronomical mechanisms.",
"author": "YourName",
"genre": "Sci-Fi / Fantasy",
"tags": ["Mystery", "Sci-Fi", "Exploration", "Puzzles"],
"created_at": "2026-09-07T12:00:00Z",
"cover_image": "references/cover.webp",
"difficulty": "Medium",
"recommended_players": "1-4"
}
id(string, required): Unique URL slug (my-custom-adventure). Use lowercase alphanumeric characters and hyphens.title(string, required): Display title.description(string, required): 1β3 sentence hook summarizing the adventure premise.author(string, required): Creator name or handle.genre(string, required): e.g.,"Dark Fantasy","Cyberpunk","Cozy Mystery".tags(array of strings): Discoverability keywords.cover_image(string): Relative path to the cover artwork within the adventure package (e.g."references/cover.webp").difficulty(string):"Easy","Medium", or"Hard".recommended_players(string): e.g."1","1-4","2-6".
4.2. theater.yaml Specification
Adventures use Narratron's standard theater configuration schema to define the live agent persona, art direction, audio pacing, and state preservation. Live-agent behavior belongs under the live_agent section; the former agent section is no longer used.
> [!NOTE] > Canonical Configuration Reference: > Rather than maintaining a separate explanation here, please refer to the theater.yaml Reference for comprehensive documentation on all available sections and optionsβincluding live_agent, visuals, image_generation, animation, interactive_canvas, music, story_planning, and chat.
Adventures specifically rely on the story_planning section to govern the interactive adventure loop. Here is an adventure-focused configuration example:
# Live Gemini agent behavior and adventure-specific instructions
live_agent:
special_instructions: "Carry user actions faithfully and guide the adventure with dramatic tension and clear consequences."
# Starting visual displayed on the canvas when the adventure starts
starting_image: "references/cover.webp"
# Pacing and style direction for generative canvas visuals
visuals:
cycle_length: 6
style: "dark fantasy matte painting, glowing runes, cinematic lighting, moody atmospheric fog, high detail"
image_generation:
enabled: true
cooldown_duration: 6
music:
style: "orchestral fantasy ambiance, haunting cello melodies, distant percussion, loopable background"
# Adventure Mode & Persistent State
story_planning:
adventure_mode: true # Required: Enables player action resolution & turn tracking
auto_begin: true # Automatically initiates the opening narrative scene
style: "engaging mystery with player agency, dramatic tension, and fair consequences"
# Require sticky definitions, initial values, and visibility in planning.yaml.
enforce_structured: true
chat:
cooldown_duration: 20
The top-level notepad section is solely for normal narration and configures initial_stickies, max_stickies, required_stickies, and hidden_stickies. Adventure Mode ignores these settings; all adventure topics are required and pinned in planning.yaml order, and capacity includes every declared topic. With story_planning.enforce_structured: true (the default), a missing or empty contract is a configuration error.
4.3. planning.yaml Specification
Sticky notes and persistent story planning contracts are configured in planning.yaml. All field values are strictly strings. Adventure planning checks each declared sticky's ownership and field contract before updating it. Set story_planning.enforce_structured: false to let recorder and planner also create and update shared freeform topics without a planning.yaml entry. Declared topics retain their contracts. Freeform topics are visible by default and persist across saves and restarts. Older optional notes are evicted at capacity; at least one freeform slot is available alongside required topics.
# Deep Planner Schema: planning.yaml
"Player Character":
owner: recorder
description: "Established player identity, objective, and condition."
fields:
name:
description: "Character name"
initial: "Unnamed Explorer"
objective:
description: "Current primary goal"
initial: "Reach the Spire's apex"
inventory:
description: "Key items carried"
initial: "Crystal lodestone"
condition:
description: "Physical and mental status"
initial: "Healthy"
"Spire Security Level":
owner: recorder
description: "Alert tier and automaton activity."
fields:
alert:
description: "Current alert level"
initial: "Green (Unnoticed)"
automatons:
description: "Automaton activity"
initial: "Dormant"
"Known Clues":
owner: recorder
hidden: true
description: "Discovered clues and hints."
initial: "The Spire activates only when three harmonic keys are aligned."
Each structured entry under fields contains a string description and a string initial value (defaulting to "undefined" when omitted). Structured topics have no top-level initial; topics without fields use an optional top-level string initial, also defaulting to "undefined" when omitted. Explicit empty strings are preserved. render is optional: by default, nonempty values appear as field_name: value | next_field: value in field declaration order. To customize labels or layout, add a template such as render: "Name: {name} | Objective: {objective}" using that topic's field names.
For full details on every field, default values, and advanced features (such as character_voicing, require_voice_input, interactive canvas surfaces, and video animation techniques), see the canonical theater.yaml reference.
4.3. Authoring Lore (lore/)
Files in lore/ are indexed and made available to the Gemini story planner to ground storytelling in your world's backstory, characters, and rules.
Pinned role guides: RESPONDER.md, PLANNER.md, and RECORDER.md
Every adventure has three independent instruction files in lore/. The complete RESPONDER.md is pinned in the responder's instructions; the complete PLANNER.md is pinned in the planner's instructions; and the complete RECORDER.md is pinned in the recorder's instructions. Each module cannot list, search, or read the others' guides. Give each file its own priorities and enough context to perform its role independently.
lore/RESPONDER.md: Premise, opening scene, tone, immediate action resolution, dice rules, disclosure limits, local lore roadmap, and factual planning signals. The responder owns narration and NPC dialogue and never writes sticky notes or takes game actions.lore/PLANNER.md: Campaign milestones, off-screen motives, clocks, consequences, outcomes, and planner-owned sticky notes. The planner never narrates a parallel scene, rolls dice, or takes game actions.lore/RECORDER.md: Factual note reconciliation, recorder-owned sticky tracking, and validated Narratron game actions. The recorder reconciles completed responses and committed player events against established facts.- Shared lore (
.txtor.md): World facts, detailed mechanics, NPCs, locations, and factions that roles may fetch on demand. Put shared rules here rather than linking one private guide from another.
The planner starts immediately when StoryTool.process_user_action receives an action. The initial event is unresolved player intent: research and preparation can begin, but action-dependent changes await the responder's separate result event. Reconcile that result once; these events do not represent two player turns. Each planner run allows eight lore reads and eight searches; the responder retains three of each. Ordinary lore is indexed and fetched on demand, with no filename-prefix preloading.
Best Practices for Authoring Lore
Store character portraits in the references/characters/ folder and annotate the canonical character name in its lore. Locations, artifacts, and factions can continue using paths under references/:
- Annotate Visual Reference Paths in Lore:
# Character Info: Keeper Orun
Orun is a seven-foot-tall brass automaton with an etched porcelain face mask and glowing amber optic lenses.
Speaks with a rhythmic, deliberate cadence, often punctuated by a soft clicking in his chest.
image_reference: Keeper Orun
Place the corresponding portrait inside references/characters/Keeper Orun/, for example references/characters/Keeper Orun/1.webp.
Why this is a best practice: When the story planner reads the lore file during play, using the canonical character name lets the planner bind the correct portrait and the live agent use <Keeper Orun> in visual prompts.
- Organize by Domain: Split detailed worldbuilding into clear subdirectories:
lore/RESPONDER.md: Pinned immediate-resolution guide.lore/PLANNER.md: Pinned campaign and tracking guide.lore/RECORDER.md: Pinned factual note reconciliation and game actions guide.lore/characters/*.txt: Key NPCs, personalities, secrets, dialogue habits, and their annotatedimage_reference.lore/locations/*.txt: Sensory descriptions, secrets, hazard triggers, and interactable elements.lore/factions/*.txt: Groups, motives, rivalries, and allegiances.
Use bullet points, clear headings, and concise summaries. Dense blocks of prose dilute prompt attention and consume unnecessary context.
- Keep Text Punchy & Structured:
Clearly distinguish between common world knowledge and DM-only secrets:
- Separate Public Knowledge from Secrets:
# Public Knowledge
Lord Vane is known as a benevolent benefactor to the town.
# Secret Lore (DM Only)
Lord Vane is covertly siphoning the town's life essence to power an obsidian golem beneath his estate.
4.4. Visual References (references/)
The references/ folder contains environment images, maps, cover art, and artifacts. Character portraits belong in the references/characters/ folder.
- Use
.webpfor new images. PNG, JPEG, and WebP uploads remain supported; existing images do not need to be converted. - Cover Image: Every adventure should have a cover image (e.g.
references/cover.webp). Reference this filename inmetadata.jsonandstarting_imageintheater.yaml. - During play, the agent can call
list_referencesorshow_imageto present these pre-made visual assets to players. Annotatingimage_reference: references/<filename>in your lore documents ensures the agent automatically and reliably binds visual assets to scenes and other non-character assets.
Scene imagery (references/scenes/)
Store each scene's images in its own folder, for example references/scenes/Old Harbor/1.webp, 2.webp. PNG, JPEG, and WebP are supported; the highest numbered iteration is used. Loose images directly under references/scenes/ are ignored.
Add scene.yaml beside each scene's portraits:
description: "An old harbor with fishing boats and stone piers at dawn"
At initialization, the manager reads authored scene images and scene.yaml directly without copying them into output. Existing session images and descriptions take precedence. Changed descriptions generate new numbered iterations under output/artifacts/updated_references/scenes/ and save the description to scene.yaml there. Authored files remain unchanged, and the initial image is not duplicated in output.
To preserve session updates for future play, copy the desired images back into the authored scene folder. To reset a scene to its authored imagery, remove its folder under output/artifacts/updated_references/scenes/ before starting a new session.
Character portraits (references/characters/)
Each character must have its own folder, with portrait iterations such as references/characters/Arthur Modella/1.webp, 2.webp. Loose files directly under references/characters/ are unsupported; the folder also holds character.yaml for the character traits. Supported formats are PNG, JPEG, and WebP. The highest numbered iteration is used; a non-numbered portrait can serve as the initial image.
When the reference manager starts, it reads authored portraits directly without copying them into output. Existing session portraits take precedence. Appearance changes create the next image iteration under output/artifacts/updated_references/characters/, using the previous authored or session portrait for continuity. The initial authored image is not duplicated in output, and the authored folder stays unchanged.
Add character.yaml alongside the portraits to initialize the character's traits:
description: "A silver-haired wizard in blue robes"
personality: "Patient and curious"
motivation: "Recover the lost archive"
quirk: "Hums while thinking"
gender: male
voice_tags: [male]
The folder name supplies the character name. Missing traits use normal character generation. Characters with only character.yaml are also registered. The manager reads authored profiles directly during initialization, prefers an existing session profile, and saves later trait changes to the session character.yaml without copying the original portrait. Authored files remain unchanged.
The live agent sees all available character visual names in canvas observability, including characters outside the active scene. Character image file paths and aliases stay internal; model-facing character context and tool results use names and traits. Image and animation prompts attach the latest portraits through tags:
<Arthur Modella> flashes a wand before stepping back from <Grim Vallos>.
Tags match complete character names or aliases, ignoring case and normalizing spaces/underscores. Repeated tags attach one portrait. Unknown tags return an error so the agent can correct the name. Character references need no separate reference_images argument; that argument remains available for canvas captures and other non-character references. Scene tags are not implemented yet.
To keep an updated appearance for future play, manually copy the desired session portraits into the theater's authored references/characters/ folder. To start over from authored portraits, remove the corresponding session character folder before the manager starts. Legacy references/ images can still be bound through create_or_update_character(image_reference=...); they are copied into the session library before further edits.
4.5. Atmospheric Playlists (playlists/)
The playlists/ folder contains subfolders representing different musical moods or scenes:
playlists/
βββ exploration/
β βββ ancient_corridors.mp3
β βββ forgotten_ruins.mp3
βββ suspense/
β βββ creeping_shadows.mp3
βββ climax/
βββ battle_for_the_core.mp3
- Supported formats:
.mp3,.wav,.ogg,.flac. - Keep files compressed and loopable when possible.
5. Testing Your Adventure
Narratron Buddy provides multiple testing tiers so you can iterate quickly without needing complex cloud deployments.
5.1. Fast CLI Testing with adventure_runner.py
The quickest way to test narrative flow, state updates, and tool staging is the Testlab Adventure Runner CLI.
Make sure your .env has GEMINI_API_KEY set, then run:
Interactive CLI REPL
uv run python testlab/adventure_runner.py --adventure my-custom-adventure
You can type player actions at the Player > prompt and inspect:
- The story planner's scene reaction and narrative response.
- Active sticky notes updating in real time.
- Staged peripheral tool calls (music changes, canvas prompts, image triggers).
- Type
resetto restart orquitto exit.
Automated Smoke Test
To verify that the adventure initializes cleanly and resolves an opening turn:
uv run python testlab/adventure_runner.py --adventure my-custom-adventure --smoke
This executes a single turn, checks that story beats generate properly, and exits with code 0 on success.
5.2. Autonomous Playtesting with Autoplay (--autoplay)
When authoring complex narratives, manually typing 20 turns to test edge cases or plot resolution is slow. Narratron Buddy includes a built-in Autonomous Player Agent (AutoPlayer) that plays your adventure automatically via an LLM agent, simulating realistic human decision-making, strategic reasoning, and dialogue.
How Autoplay Works
- Per-Turn Decision Loop: On each turn, the autonomous player inspects the adventure's premise, recent narrative chronicle, active dialogue, and current sticky notes.
- Dual-Channel Output: The player produces an internal strategic thought (its tactical intent or comedic reasoning) and a concrete in-character action (1β3 sentences).
- Engine Execution: The player's action is submitted to the Narratron adventure session, advancing the story planner, triggering lore lookups, updating sticky notes, and staging peripherals (music, images, canvas).
- Session Logging: Each turn is incrementally streamed to console and saved as a persistent Markdown chronicle and structured JSON summary under
evaluation_result/.
Basic Autoplay Run
Run a default 10-turn autonomous session:
uv run python testlab/adventure_runner.py --adventure my-custom-adventure --autoplay
Tailoring the Playstyle Persona (--autoplay-instructions)
Direct the player's behavior, tactical focus, and personality using --autoplay-instructions:
- Realistic & Pragmatic (Grounded survival and bureaucratic diplomacy):
uv run python testlab/adventure_runner.py --adventure the-overlords-assistant --autoplay --turns 20 --autoplay-instructions "Play in a realistic style: act as a grounded, pragmatic, and cautious mortal assistant in Overlord Malakor's court. Prioritize personal survival, use realistic bureaucratic diplomacy and workplace leverage, be observant and respectful of lethal power dynamics, and avoid absurd, reckless, or cartoonish actions."
- Zany & Boundary-Testing (Stress-testing story planner resilience against chaotic choices):
uv run python testlab/adventure_runner.py --adventure groove-space-odyssey --autoplay --turns 15 --autoplay-instructions "Be zany, audacious, and test edge cases. Attempt unexpected solutions, talk to inanimate objects, and bend the rules."
- Methodical Investigator (Deep lore probing and clue verification):
uv run python testlab/adventure_runner.py --adventure my-custom-adventure --autoplay --turns 12 --autoplay-instructions "Act as a meticulous, inquisitive detective. Prioritize examining clues, interrogating witnesses on contradictions, and recording evidence."
Command-Line Flags Reference
| Flag | Shorthand | Default | Description | | :--- | :--- | :--- | :--- | | --autoplay | β | False | Enables autonomous player mode. | | --autoplay-instructions | --autoplay_instructions | Default explorer | Directives, persona, or behavioral constraints for the player agent. | | --turns | -n, --autoplay-turns | 10 | Maximum number of turns to execute in the session. | | --autoplay-model | --autoplay_model | gemini-3.8-flash | Gemini model ID driving the autonomous player agent. | | --autoplay-log | --autoplay_log, --log-file | evaluation_result/autoplay_<id>_<timestamp>.md | Destination path for the session log file (supports .md and .json). | | --autoplay-delay | --autoplay_delay | 0.0 | Pause in seconds between turns to pace API requests. | | --action | β | "" | Optional custom starting action to override turn 1. |
Evaluating Autoplay Artifacts
Logs are saved automatically to evaluation_result/autoplay_<adventure_id>_<timestamp>.md. Review the generated log to verify:
- Narrative Progression: Check whether narrative events transition logically and reach satisfying milestones.
- Sticky Note Hygiene: Confirm that existing sticky notes are updated cleanly rather than ballooning into dozens of redundant notes.
- Peripheral Staging: Verify that character visual references (
references/), background music tracks (playlists/), and interactive canvas components trigger when appropriate. - Pacing & Tone: Assess whether NPC dialogue and narrator responses match the adventure's desired genre and difficulty.
5.3. Visual Browser Testing with Test Lab
You can test your adventure's UI and peripherals in a lightweight browser diagnostic without launching the full multi-user server:
uv run python -m uvicorn testlab.server:app --host 127.0.0.1 --port 8015
Open http://127.0.0.1:8015/adventure-runner in your browser to interact with the visual test harness.
5.4. Final Testing Step: Upload & Deploy via /deploy
As the final, definitive step of testing before public distribution or submitting to narratron.app, upload your package folder directly via /deploy to test it in the full Narratron application without needing to configure backend API keys locally:
- Navigate to narratron.app/deploy.
- In the theater creation dashboard, locate the "Drop Asset Folder or .ZIP here" dropzone.
- Click Select or drag-and-drop your custom adventure package folder (or compressed
.ziparchive). The system will mount your package, validatetheater.yaml, and bundlelore/,references/, andplaylists/. - Click π Deploy Theater to launch the live theater instance.
- Join the deployed room as host and test:
- Verify that your
starting_imagedisplays immediately on the canvas. - Speak into your microphone or submit actions via chat to ensure turns resolve, sticky notes update, and narration flows smoothly.
- Check that visual reference images, generative art, and atmospheric music playlists trigger properly in live play.
6. Submission Process (to narratron.app)
When your adventure is ready to be featured for everyone on narratron.app:
Pre-Submission Checklist
-
metadata.jsonexists, has a validid,title,author,genre, and references a validcover_image. -
theater.yamlis valid YAML and includesstory_planningwithadventure_mode: true. -
planning.yamldefines all required topics, owners, initial values, and hidden flags. -
lore/RESPONDER.md,lore/PLANNER.md, andlore/RECORDER.mddefine independent priorities, role boundaries, and lore roadmaps; shared rules live in separate lore documents. - The adventure passes the smoke test:
uv run python testlab/adventure_runner.py --adventure <your-adventure-folder> --smoke
- The adventure passes an autonomous multi-turn playtest session (10+ turns) verifying narrative consistency and peripheral triggers:
uv run python testlab/adventure_runner.py --adventure <your-adventure-folder> --autoplay --turns 10
- Final verification: Uploaded the folder via /deploy and successfully complete an interactive play session in the full Narratron app.
How to Submit
- Push your adventure to a public Git repository (or prepare a
.ziparchive of your adventure folder). - Ping
syclonexon Discord. - Include:
- Adventure Title & Slug ID
- Brief 1-sentence premise
- Link to repository or download package
- Your adventure will be reviewed, tested, and added to the official Google Cloud Storage repository for narratron.app!