Appearance
Quick Start
Get oriented and authoring in a few minutes. This page covers the need-to-know: how to run the engine, the handful of concepts that everything else builds on, and the ready-made templates you'll copy instead of writing UI from scratch. When you want the details, head to the Authoring Guide.
Run the engine
Prerequisites: Node.js 18+, and an editor (VS Code recommended; install the Ana extension for .ana syntax highlighting and macro completions).
bash
npm install
npm run dev # dev server with hot reload at http://localhost:5173Open the URL Vite prints. The repo ships with a small example game so you have something running immediately; you'll replace its passages with your own.
Want these docs offline?
npm run docs:devserves this site locally with hot reload.
The three things to learn
Almost everything in a passage is one of three things:
$and_variables:$player.goldis global and saved;_tempis scratch that resets every passage.@directives are structural markers.@zone(text)targets a screen region,@system(init)marks GameInit, and@hook/@into/@onwire up injection and events.(macro:)calls are the verbs:(if:),(link:),(goto:),(set:),(add:). They follow a(name: args)shape, and blocks of content go in square brackets:(link: "Open")[ … ].
Get comfortable with those and the rest of the engine is just a larger vocabulary.
Where your game lives
Every .ana file under passages/ is discovered automatically, so organize them into folders however you like. A file holds one or more passages, each introduced by a :: Name header:
ana
:: TownSquare
@zone(text)
The square is quiet this afternoon.
@zone(options)
(link: "Enter the bar")[(goto: Bar)]passages/_init.ana is special. It holds the GameInit passage (@system(init)), where your declarations and configuration live. It runs once when a new game starts and again every time a save loads (saved values are applied over it), so keep it to declarations, definitions, and config; put one-time story beats in your (start:) passage instead. The two lines every GameInit needs:
ana
:: GameInit @system(init)
(start: TownSquare) // first passage after New Game
(layout: Layout_Standard) // the built-in two-sidebar layout
(declare: $player, name, "", gold, 100)
(declare: $player.health, 100, 0, 100) // bounded: (add:)/(sub:) auto-clampSee the annotated gameinit_walkthrough.ana template (in templates/) for a fully commented GameInit covering player vars, world state, time, NPCs, items, quests, and config.
Zones, links & navigation
- Zones are the named regions of the layout.
@zone(text)and@zone(options)are the two you'll use most; sidebars, image, header, and overlays are also zones. Content after a@zone(...)line goes into that region. - Links are clickable buttons:
(link: "Label")[body]. The body runs on click, so it can change state and then navigate. - Navigation tiers decide how much of the screen refreshes:
(goto: Passage)rebuilds the whole scene (a new location).(update: Passage)refreshes the text and options zones only (same scene, new beat).(action: Passage)makes a minimal, targeted update (toggle a detail without disturbing the rest).
ana
@zone(options)
(link: "Buy a round")[(pay: 5)(notify: "You spent 5 gold.")(action: Bar_Pour)]
(link: "Leave")[(goto: TownSquare)]No back button by design. Ana has no undo or quick-save key; the only way to rewind is to deliberately load a save slot. Author your branches knowing players live with their choices.
Start from a template
The engine ships working, restyleable screens in templates/. Copy the ones you need into passages/ (UI screens conventionally live in passages/ui/) and customize them. They follow every engine convention, loop over engine data instead of hardcoding, and use theme variables so they match any theme. They're the fastest way to a real game.
| Template | What it gives you |
|---|---|
title_screen.ana | New Game / Load Game title screen (renders automatically on boot via @system(title)) |
gameinit_walkthrough.ana | A fully annotated GameInit to adapt as your _init.ana |
game_menu.ana | Pause menu: save, settings, back to title |
settings_screen.ana | Settings modal with keybind remapping and clock/date format |
header.ana | Header bar with location, clock, and shortcut buttons |
char_creator.ana | Name + traits + skill-focus creator that hands off to your first passage |
char_panel.ana | Character sidebar: portrait, stats, traits, status effects |
npc_panel.ana | NPC sidebar: portrait and relationship tier |
inventory_screen.ana | Modal inventory list with use/equip actions |
equipment.ana | Equipment screen built from your defined slots |
quest_log.ana | Two-panel quest log (master/detail via (panel:)) |
achievements.ana | Achievements grid that loops every defined achievement |
See it live
With npm run dev running, save any file and changes hot-reload in the browser, with your game state preserved between edits.
Press ` (backtick) to open the dev debugger:
- Vars: inspect and edit
$variables live. - Eval: run macros directly; try
(set: $player.gold to 999). - Trace / Passages / Hooks: see where you've been, the total passages in game, and inspect injections.
Common mistakes
Nothing renders after New Game. GameInit needs (start: YourPassage), and the passage name must match the :: Name header exactly.
Variable changes don't persist. Only $ variables (declared with (declare:)) save. _temp variables reset every passage.
A link body doesn't navigate. A link body runs on click but only navigates if it contains (goto:), (update:), or (action:). Prose or (set:) alone will execute without moving anywhere.
A _temp is empty at click time. Macros in a link body fire on click, by which point the original passage's _temp vars are gone. Capture what you need into a $ variable first:
ana
// ✗ _id is gone by click time
(link: "Equip")[(add: $equip.weapon, _id)]
// ✓ promote _id at render time, use the global on click
(link: "Equip")[(set: $world.selected to _id)(action: _EquipWeapon)]Images don't show. Put them in assets/images/; (img:) appends .jpg automatically when you omit the extension.
Where to go next
| You want to… | Read |
|---|---|
| Understand variables, bounds, and types | State & Variables |
| Lay out the screen / define zones | Zones & Layout |
| Branch, loop, and link between passages | Navigation · Math, Loops & Expressions |
| Add inventory, NPCs, quests, stats | RPG Systems |
| Style prose and theme the UI | Prose & Text · Theming & Modals |
| Run time, schedules, and reactive content | Time & Scheduling |
| Drop to JavaScript for custom logic | Extending with JavaScript |
| Ship a mod | Modding Guide |
| Look up a macro's exact syntax | Macro Reference |