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.yml and existing game.json packages 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:


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:

  1. Copy .env-template to .env:
   Copy-Item .env-template .env
  1. Open .env and 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 (.txt or .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/:

  1. 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.

  1. 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 annotated image_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.

  1. Keep Text Punchy & Structured:

Clearly distinguish between common world knowledge and DM-only secrets:

  1. 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 .webp for 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 in metadata.json and starting_image in theater.yaml.
  • During play, the agent can call list_references or show_image to present these pre-made visual assets to players. Annotating image_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 reset to restart or quit to 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

  1. Per-Turn Decision Loop: On each turn, the autonomous player inspects the adventure's premise, recent narrative chronicle, active dialogue, and current sticky notes.
  2. 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).
  3. 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).
  4. 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:

  1. Navigate to narratron.app/deploy.
  2. In the theater creation dashboard, locate the "Drop Asset Folder or .ZIP here" dropzone.
  3. Click Select or drag-and-drop your custom adventure package folder (or compressed .zip archive). The system will mount your package, validate theater.yaml, and bundle lore/, references/, and playlists/.
  4. Click πŸš€ Deploy Theater to launch the live theater instance.
  5. Join the deployed room as host and test:
  • Verify that your starting_image displays 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.json exists, has a valid id, title, author, genre, and references a valid cover_image.
  • theater.yaml is valid YAML and includes story_planning with adventure_mode: true.
  • planning.yaml defines all required topics, owners, initial values, and hidden flags.
  • lore/RESPONDER.md, lore/PLANNER.md, and lore/RECORDER.md define 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

  1. Push your adventure to a public Git repository (or prepare a .zip archive of your adventure folder).
  2. Ping syclonex on Discord.
  3. Include:
  • Adventure Title & Slug ID
  • Brief 1-sentence premise
  • Link to repository or download package
  1. Your adventure will be reviewed, tested, and added to the official Google Cloud Storage repository for narratron.app!