Reference¶
addventure is the CLI tool providing commands:
new— scaffold a gamebuild— compile to PDF or markdown
A game is a directory of .md files:
index.md— metadata, verb list, and inventory object list- Room files — one
.mdper location, loaded alphabetically
Room files use a scripting syntax consisting of interactions, arrows, actions, signals, and more.
CLI commands¶
See Getting Started for installation instructions.
new¶
Scaffold a new game directory with a starter index.md.
addventure new [name] # Scaffold with defaults (oneshot)
addventure new # Interactive setup (choose verbs, set author name)
Run from inside an existing game directory to scaffold a new chapter subdirectory instead. The chapter is automatically assigned the next available ledger prefix (B, C, D...).
build¶
Compile a game to PDF (default) or markdown.
addventure build [dir] # Compile to PDF (default)
addventure build [dir] --md # Compile to markdown
addventure build [dir] -o FILE # Custom output path
addventure build [dir] --paper SIZE # Paper size: a4 (default), letter, legal
addventure build [dir] --blind # Blind mode: room names/IDs hidden until discovered
addventure build [dir] --no-cover # Omit the How to Play cover page
addventure build [dir] --fragment MODE # Fragment output mode (see below)
addventure build [dir] --all # Build all chapters into one output
If no directory is given, looks for index.md in the current directory.
--all discovers chapter subdirectories (those containing index.md with a # Verbs header), builds each independently, and combines them into a single PDF or markdown output. Warns if any chapters share the same ledger_prefix.
Fragment modes¶
The --fragment flag controls how fragment blocks are output:
| Mode | Effect |
|---|---|
included |
Fragments appended at the back of the main PDF (default) |
jigsaw |
Fragments sliced into shuffled rectangular pieces across cut pages, appended to the main PDF |
separate |
Fragments emitted as <name>-fragments.pdf; main PDF has none |
--fragment separate is useful when you want to print and distribute fragments as physical notes — cut them out and hand them to players in envelopes labelled with the ref (e.g. Alpha).
Index files¶
Frontmatter¶
YAML metadata between --- fences at the top of index.md:
| Field | Description |
|---|---|
title |
Game title, shown on printed sheets |
author |
Author name, shown in footers |
start |
Starting room name (must match a # header) |
ledger_prefix |
Prefix for ledger entry labels (default: A). Auto-assigned by addventure new for chapters |
image |
Path to an image shown on the title page alongside the description |
image_height |
Height of the title page image |
name_style |
Identifier rendering style: upper_words (default) or title — see Name rendering |
Unknown keys are accepted but produce a build warning.
Description¶
Body text between the frontmatter and the first # header is used as the game description, shown on the title page alongside the image (if set).
Sections¶
List one name per line, ALL_CAPS. # Inventory is only needed for objects that never exist as room objects — most objects are auto-registered when they have a -> player arrow in a room.
Room files¶
Room header¶
Starts a new room. The text after # is the room name.
Room-level interaction¶
No + prefix. Defines what happens when a verb targets the room itself.
Room objects¶
Bare ALL_CAPS name on its own line. Declares a room object.
Interactions¶
+ VERB: Inline narrative.
+ VERB:
Block narrative on
indented lines.
+ VERB + TARGET:
Multi-target: requires verb + object + target (three IDs added).
Actions¶
Direct ledger lookup — no addition needed. Printed on the room sheet with an entry reference. Nested inside an interaction body, the action becomes discoverable.
Arrows¶
Fires when the parent interaction triggers. See Arrow destinations below.
State-specific interactions¶
Nested under the arrow that creates the state.
Freeform interactions¶
Room-level interactions not tied to a specific room object. Goes at the bottom of a room file.
Fragment blocks¶
Content inside fragment is Typst markup. See Fragment modes.
Script reference¶
Most scripting concepts are explained in Writing Rooms and State & Transformation. This section covers the quick-reference tables.
Arrow destinations¶
| Destination | Effect |
|---|---|
player |
Move to inventory (auto-creates inventory object; inventory ID = TAKE + room object ID) |
trash |
Remove object from the game |
room |
Place object in the current room |
"Room Name" |
Move the player to another room |
ENTITY__STATE |
Transform object to a new state |
VERB__STATE |
Transform a verb to a new state |
-> VERB |
Reveal a new verb on the player's verb sheet (no subject) |
VERB -> trash |
Remove a verb from the player's verb sheet |
? -> "Room" |
Cue: deferred cross-room effect (see Advanced) |
ACTION_NAME -> trash |
Remove an action from the room sheet |
NAME -> signal |
Emit a signal (player writes the signal ID) |
Signals¶
Signals branch narrative based on earlier decisions. A signal is a named flag — when the player triggers it, they write a numeric code on their sheet. Later, a signal check directs them to different ledger entries depending on which signals they have. This works within a single game or across chapters.
Signal IDs are derived automatically from the name (deterministic hash). No declaration section is needed — the compiler derives signal info from NAME -> signal arrows and NAME? blocks.
See Signals (Advanced) for design guidance and examples.
Emitting signals¶
Use a signal arrow on any interaction:
The player instruction: "Write 64745 in your signals."
Signal checks¶
Signal checks branch narrative based on which signals the player has. They use NAME? syntax with otherwise? as the default.
In the index description (fires at chapter start):
EVERYONE_OUT_ESCAPE?
A companion catches up to you...
WITNESS_ESCAPE?
You're alone.
otherwise?
Default text.
In interaction bodies (fires during play):
All matching branches fire — if the player has multiple signals, they read every matching entry. otherwise? fires only when no signal matches.
On the printed sheet, signal checks render as: "Check your signals: 64745 → read B-3. 92951 → read B-7. Otherwise → read B-12."
Special syntax¶
| Syntax | Meaning |
|---|---|
ENTITY__STATE |
Double-underscore separates base name from state |
* |
Wildcard — matches all room objects in an interaction (see Wildcards) |
// |
Comment — ignored by the compiler |
## Interactions |
Section for freeform interactions in a room file (see The Interactions section) |
? -> "Room" |
Cue arrow — deferred effect in another room |
? -> "Room__STATE" |
Cue targeting a specific room state |
? -> "Room__" |
Cue targeting only the base room state |
* is only valid as the entire target of an interaction (LOOK + *:). It is not valid inside multi-target or alternation forms (USE + * + KEY:, USE + BOX|*:).
Trailing // comments are not stripped from narrative text — // inside prose is treated as literal text.
Naming rules¶
- Room objects, inventory objects, verbs, and actions:
ALL_CAPSwith optional single underscores between segments - States:
BASE__STATE(double underscore) - Room names: any text after
#, case-sensitive - Room references in arrows: must be quoted (
"Room Name")
Plain identifiers may not contain __. Double underscore is reserved for state syntax only.
Name rendering¶
Identifiers are authored in strict machine form (GO_NORTH, WALL_PANEL) and rendered for players with spaces by default (GO NORTH, WALL PANEL). Set name_style in frontmatter to change this:
| Value | Example |
|---|---|
upper_words (default) |
GO_NORTH → GO NORTH |
title |
GO_NORTH → Go North |
This affects verbs, room objects, inventory objects, states, and actions on the printed sheets. It does not affect free-text room names or narrative prose.