Skip to content

Pattern reference

Daniel Stirba edited this page Oct 6, 2026 · 1 revision

Pattern reference

Everything that can go inside {…} in a pattern (or in a list row). Braces can nest: {#if $x > 5: {Drinks} | {Food}}.

Quick rule: # starts logic. With a : it all happens inside those braces (short form, for sentences); without one it's a block that ends with {/…} (for whole passages).

Picking

Write Does Example
{List} one item from ## List {First} {Family}
{A|B} one item from either list (plain and meaning lists) {First|Nickname}
{3 x List} 3 different items On tap: {2-4 x Drinks}.
{List: key} the row with that key (keyed rows, meaning rows, or a number on a die table) {Shops: Small}
{List.meaning} the meaning side of a meaning list {Land.meaning}
{List + 2} {List with d6} roll a die table with a modifier or another die {Wealth + $bonus}
{again} inside a die-table row: roll that table again (without this row) - 20: {again} and {again}
{@Key} another generator's result {@InnsTaverns}

{3 x List} layout: alone on its line, it makes a bullet list; inside a sentence, "a, b and c". The count can be dice, a range, a $value or a lookup: {1d4 x Item}, {$n x Item}.

Numbers and maths

Write Gives
{2d6} {d20} a dice roll
{1-4} a number from 1 to 4
{1d8 + 4} {$wealth - 10} sums
{$wealth * 3 / 2} {(1 + 2) * 3} maths with *, / and brackets, in the usual order

Division rounds down ({7 / 2} is 3). Dividing by 0 is an error.

Remembering values

Write Does
{$x = 2d6} remember a number (prints nothing)
{$race = Race} remember a pick from a list
{$race = "Dwarf"} remember exact words
{$x = {#if $w > 5: big | small}} remember the result of any pattern
{$x += 2} {$x -= 2} change a number
{$x ?= 1d100} set $x only if it has no value yet (a fallback for values passed in)
{$x} print it

A value that was never set prints 0. Values belong to one result: the next result starts fresh.

If / else

Short form (in a sentence):

The sign is {#if $wealth > 60: freshly painted | {#if $wealth <= 20: missing | peeling}}.
  • The first | (outside other braces) starts the else part. The else part is optional: {#if $last: (last)}.
  • Both parts are trimmed, so put spaces outside the braces: {$item} {#if $last: (last)}.
  • A literal | inside a branch: \|.

Block form (whole passages):

{#if $wealth > 60}
Text for rich places.
{else if $wealth > 20}
Text for middling places.
{else}
Text for poor places.
{/if}

A tag alone on its line takes the whole line with it, so blocks don't leave blank lines.

Conditions

Write True when
$x > 5 $x >= 5 $x < 5 $x <= 5 comparing numbers
$x = 5 (or ==) $x != 5 equal / not equal
$race = Dwarf $name = "Old Bell" text, ignoring capitals (quotes for spaces or symbols)
$a and $b $a or $b not $a combine (and before or)
$x alone $x is set and isn't empty or 0
{List} = Dwarf a pattern works as a side too (it's rolled each time)

An unset value counts as 0 next to a number and as empty text next to text.

Loops

Write Does
{#repeat 1d4: [{$i}]} a pattern several times (the count can be dice or a $value)
{#each List: {$item}} once per row of a list, in order
{#repeat 3} … {/repeat} block form
{#each List} … {else} … {/each} block form; {else} shows when the list is empty

Inside a loop: $i (1, 2, 3…), $first and $last (1 or 0), and in #each also $item (the row as it prints) and $meaning (for meaning lists). They belong to their loop: after it, they're back to what they were.

Layout of short loops: alone on its line, one line per round; inside a sentence, "a, b and c". Rounds that print nothing are left out, so {#each Drinks: {#if $item != Water: {$item}}} works.

A loop runs at most 100 rounds. There are no "while" loops: a count is always known.

a / an

{a Race} prints "an elf" or "a dwarf"; {A Race} capitalises it ("An elf"). Works with any pick: {a $race}, {a {@Drinks}}.

It goes by the first letter, with common exceptions: an hour, an honest, a unicorn, a one-eyed, an 8, an 18. A list actually named "A something" wins over this.

Calling other generators with values

{@Tavern $wealth=$wealth $race=Dwarf $name="Old Bell" $kind={Kind}}
  • Write values as $name=value with no spaces around =. Values: a $value, a number or dice (rolled here, once, so both sides agree), a word, "quoted text", or {a pattern}.
  • The called generator starts with those values. Inside it, {$wealth ?= 1d100} keeps a passed value, or rolls one when it's called on its own.
  • A $value that isn't set isn't passed, so the fallback runs.
  • Values stay inside the call: only its text comes back. Pass what the other generator needs; don't expect values back.

Escapes and limits

  • \{ \} \| print the character itself.
  • Generators can call each other at most 10 deep, repeats and loops make at most 100 items, and a pattern that makes far too much text stops with a message, so a mistake never freezes Obsidian.
  • The problems list (Settings › Custom generators) checks lists, conditions and loops before you run anything.

Clone this wiki locally