Rea Language — Cheat Sheet
Plain text is valid content. Just write.
Two Core Symbols
The entire Rea language builds on two characters:
| Symbol | Purpose | Remember |
|---|---|---|
{ } | Commands — everything that "does" (logic, variables, control) | Curly = code |
[ ] | References — everything that "points" (links, media, anchors) | Square = link |
Everything else is story text.
Text & Formatting
Plain text. Just write.
_italic_ *bold* _*bold italic*_ `monospace`
{underline begin}underlined{end underline}
{strike begin}strikethrough{end strike}Structure:
# Chapter ## Section ### Scene
= centered > right-aligned < forced left
| blockquote || nested quote
--- Horizontal rule (1–5 dashes = 5 weights)Links & Media [ ]
The first character after [ determines the type:
| Prefix | Type | Example |
|---|---|---|
| (none) | Link | [Continue > #forest] |
! | Image | [!Forest map < media/map.jpg] |
> | Video | [>Intro < media/intro.mp4] |
? | Audio | [?Rain < media/rain.ogg, volume=0.5, loop] |
# | Anchor (define) | [#forest] |
[[ | Part gate | [[ story/0005-forest.rea ]] (ends the part) |
For a link ([text > target]), the first character of the target (after >) picks the destination:
| Target prefix | Type | Example |
|---|---|---|
# | Anchor | [back > #forest] |
| (file/path) | Part | [on > story/0004-kingdom.rea] |
^ | Footnote | [dialect > ^Old Elvish, nearly lost.] |
* | Hint | [the tower > *A nudge.**A firmer hint.] |
Arrow direction: > = where the link goes, < = where the source comes from.
Variables & Printing {set} {name}
{set player.gold = 100} Number
{set player.name = "Aria"} String (always double-quoted)
{set player.items = ["sword", "map"]} Array
{set stats = [hp=100, dex=8]} Named items
Hello, {player.name}! You have {player.gold} gold.
{player.gold > 50 ? "rich" : "poor"}Domain prefixes (read-only platform data): reader.* story.* world.* device.* group.*
Control Flow
{if player.gold > 10 begin} {for item in player.items begin}
You have enough gold. - {item}
{else if player.gold > 0} {end for}
Still have something.
{else} {while fuel > 0 begin}
Broke. Keep going...
{end if} {set fuel = fuel - 1}
{end while}
{switch weapon begin}
{case "sword"} Melee. {case "bow"} Ranged.
{default} Fists.
{end switch}Choices & Branching
* [One-time choice] Disappears after selection
Text after choosing.
+ [Sticky choice] Always available
Text after choosing.
* {player.gold >= 10} [Buy potion] Conditional choice
{set player.gold = player.gold - 10}
* * [Nested choice] Second level
- Gather point Branches reconverge here
-> anchor_name Divert (jump)
->-> section_name Tunnel (jump + auto-return)
* -> Fallback (auto-selected when nothing remains)
* hidden [&card_id] ... Hidden choice — no button; fires via free-text or scan/mark/listen
{menu select=2 begin} Exploration menu — waits for 2 picks
* hidden [&qr_door] ... Hidden option — no button, wakes only by activation
{end menu}
{storylet bench_secret begin} Triggered storylet — the world deals the card
trigger: scan Input kind: scan, listen, text, nfc, ... (open set)
match: "^REAST-BENCH-.*" Optional regex on the input value
... Plays as a side path, returns to the main story
{end storylet}Functions
{function greet(name, title = "adventurer") begin}
Hello, {name} the {title}!
{end function}
{greet("Aria")} Call (renders text)
{set dmg = damage(10, 1.5)} Call (returns value)Built-ins: abs min max round random(1,6) clamp length upper lower trim contains replace split join append remove shuffle sort
Extensions (.rext)
{use "extensions/inventory" as inv} Import a bundled extension (path omits .rext)
{inv.total_weight()} Call an exported function
{use "std/dice" as dice} Standard library — always available, offline
{dice.roll(2, 6)} std/dice: d(sides) roll(n,sides) advantage/disadvantageSee When rules differ in .rext files for the language rules inside a .rext, and the engine's .reast package format reference for archive mechanics.
Localization & Dates
{plural(count, one="{} coin", other="{} coins")} CLDR plural, host locale
{select(pronoun, he="his", she="her", other="their")}
{ordinal(3)} "3rd" (en only); other locales get "3"
{formatNumber(1234567, "sk")} Locale number format (2nd arg = locale)
{formatDate(world.date, "long")} style: iso | short | medium | long | full
{formatTime(now(), "short")} {formatDateTime(now(), "iso")}The host supplies locale and formatting policy. calendar() is specified but not yet implemented.
Dialogue
@elena: "Follow me!" Speaker attribution (with quotes)
@narrator: The path grew dark. Narrator (no quotes needed)Narrative Tools
{once begin} First visit. {then} Return visit. {end once}
{first|second|third} Sequence (stops at last)
{&a|b|c} Cycle (loops forever)
{!once|twice|done} Once-only (then empty)
{~opt1|opt2|opt3} Shuffle (random)Cooperative Reading
{define role scout begin} Role definition
max: 1
{end define}
{vote timeout=60 begin} Group voting
* [Go left] * [Go right]
{end vote}
{whisper to="captain" begin} Secret message
I see guards.
{end whisper}
{broadcast begin} Everyone hears. {end broadcast}
{wait readers=all begin} Waiting... {end wait}
{set shared.score = shared.score + 1} Shared variableReal-World Interactions
{require gps} Require sensor
{require nfc optional} Optional sensor
{waypoint bridge, @@48.14;17.10/50 begin}
You stand on the old bridge.
{end waypoint}
{timer duration=30, on_expire="-> timeout" begin}
Hurry!
{end timer}Voice & Audio
{voice speed=5, pitch=5, emotion="whisper" begin}
The cave echoed with whispers.
{end voice}
{stop ambient_music}Cards (Characters, Items)
{define character elena begin}
name: Elena Voss
image: media/elena.png
{end define}
[@elena] Character reference
[$golden_key] Item reference
{give golden_key} Give item to reader
{take golden_key} Remove item from reader
{play ability_card} Play a card → runs its on_use hook{coins gold="Dukát" silver="Groš" bronze="Halier"} Rename coin tiers
{coins silver_per_gold=5 bronze_per_silver=4} Redefine ratios
{earn gold 2} Add 2 gold (1 gold = 10 silver = 100 bronze)
{spend bronze 3} Spend 3 bronze (breaks higher coins as needed)
{if reader.coins.total >= 100 begin} ... {end if} Check wallet value{define cardset ability begin} Declare a custom card set/category
name: Ability Cards
use: Play to apply the bonus.
{on_use begin} Hook runs for every card of the set
{set ability_count = ability_count + 1}
{end on_use}
{end define}
{define ability spinach begin} A card belonging to the set
name: Spinach
strength: +2
{end define}{define action door begin} Real-world activation fields
scan: ^REAST-DOOR-.* QR/barcode payload (regex)
mark: emb1:Zk3q… Drawn mark signature (opaque — never hand-edit)
listen: open the door Speech transcript (regex)
{end define}Input & Interaction
{input name=player_name, placeholder="Your name"}
{input name=guess, type="number", min=1, max=100}
{input type="action", placeholder="What do you do?"} Free text matched to the pending choices
{button label="Continue", target=next_chapter}Comments & Author Tools
{// Single-line comment}
{comment begin}
Multi-line comment — readers never see this.
{end comment}
\{not a command\} Backslash escaping
{raw begin} Everything literal. {end raw}
{todo: Fix this scene} Warning in dev mode
{strict on} Show all warningsRules to Remember
{ }= action,[ ]= reference — that's the whole languagebegin/end— all block commands use this pair- Single
=for comparison (not==), assignment is always{set x = ...} - Domain prefixes separate author variables (
player.*) from platform (reader.*) *= one-time choice,+= sticky choice,-= gather (reconverge)->= jump,->->= tunnel (jump + automatic return)- First char in
[ ]decides media/anchor:!image,>video,?audio,#anchor; in a link, the target prefix^= footnote,*= hint - Plain text is a valid story — you add syntax only when you need it