Files
ttrpg-tools/docs/reference.md
T

9.7 KiB

tttk syntax reference

Generated from src/cli/validate/known.ts by npm run gen:reference. Do not edit by hand.

Complete catalog of the custom elements, inline directives, and code block roles that tttk understands. Everything not listed here is standard GFM markdown. Element names are prefixed md- and must match exactly.

Contents

Directive syntax

:name[content]{key="value" .class #id}
Part Meaning Example
:name Registered element name :md-dice
[content] Directive body [2d6+d8]
{attrs} Attributes {key="attack"}
{.class} Shorthand for class {.text-red-500}
{#id} Shorthand for id {#my-dice}

Container directives:

::: container
Content here, including nested directives.
:dice[1d20]
:::

Nest with more colons (::::, :::::).

Custom elements

Directive Body Key attributes
:md-dice dice formula key
:md-table CSV path or inline id roll, remix
:md-deck CSV path size, grid, layers
:md-print markdown path, optional #section columns, margin, gap, font, title, pageNumbers, timestamp, cutMarks
:md-link path, optional #section —
:md-embed path, optional #section headingBase
:md-bg image path or CSS color fit
:md-border color or border image width, slice
:md-font font family source, weight, color
:md-pins image path pins, fixed, labelStart
:md-yarn-spinner Yarn Spinner file start

:md-dice

Clickable dice roller; key stores the result in the URL.

Clicking the text rolls; clicking the 🎲 resets to the formula. With key, the result is stored in the URL as ?dice-<key>=<value>.

  • Body: dice formula
  • Attributes: key
:md-dice[1d20+5]{key="attack"}
:md-dice[2d6+3]
:md-dice[3d6kh1]

:md-table

Tab-separated view of a CSV with optional group tabs.

roll adds a 🎲 random-tab button; remix makes {{prop}} references pull from a random row. A group column in the CSV produces group tabs automatically.

  • Body: CSV path or inline id
  • Attributes: roll, remix
:md-table[./npcs.csv]
:md-table[./encounters.csv]{roll=true}
:md-table[./quests.csv]{roll=true remix=true}

:md-deck

Card layout from a CSV (legacy; prefer yaml role=tag).

Prefer the yaml role=tag form — it is the only form that supports template layers, per-layer alignment, and card backs. The directive form is legacy and only supports the compact layers string.

  • Body: CSV path
  • Attributes: size, grid, layers
:md-deck[./cards.csv]{size="63x88" grid="5x5" layers="title:1,1-5,1f8 body:1,5-5,8f3"}

:md-print

Paginates a markdown document into A4 landscape sheets for printing.

Each sheet holds two A5 pages side by side, and each A5 page flows the markdown into columns columns. margin, gap, and font are in millimetres (the body font defaults to 3mm). pageNumbers adds an n / total footer in the outer corner, timestamp appends the export time to that footer, and cutMarks draws the centre cut line. The preview modal exports through the browser's print dialog (choose A4 landscape, no margins, 100% scale).

  • Body: markdown path, optional #section
  • Attributes: columns, margin, gap, font, title, pageNumbers, timestamp, cutMarks
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="3"}
:md-print[./rules.md]{timestamp=true}
```yaml role=tag
tag: md-print
body: ./rules.md
columns: 2
margin: 10
gap: 5
font: 3
title: 规则书
timestamp: true
```

Clickable link that expands the target article inline.

  • Body: path, optional #section
:md-link[./rules.md]
:md-link[./rules.md#combat]

:md-embed

Renders the target article or section inline.

headingBase shifts the heading levels of the embedded content.

  • Body: path, optional #section
  • Attributes: headingBase
:md-embed[./rules.md#combat]{headingBase=1}

:md-bg

Sets the surrounding article card background.

fit is one of cover (default), contain, fill, none, scale-down.

  • Body: image path or CSS color
  • Attributes: fit
  • Body may also be a CSS color (e.g. #2a1a3a, crimson).
:md-bg[./images/dungeon-bg.jpg]{fit="cover"}
:md-bg[#2a1a3a]

:md-border

Applies a border to the article card.

Body is a CSS color or a border-image path. Class flags select sides (t b l r all), style (solid dashed dotted double groove ridge inset outset none), and image repeat (stretch repeat round space).

  • Body: color or border image
  • Attributes: width, slice
  • Body may also be a CSS color (e.g. #2a1a3a, crimson).
:md-border[crimson]{.b}
:md-border[./frame.png]{width="2mm" slice="10" .all.round}

:md-font

Sets the article font.

source is google, emfont, or local (default).

  • Body: font family
  • Attributes: source, weight, color
:md-font[Noto Sans SC]{source="google" weight="700" color="#1a1a2e"}

:md-pins

Numbered markers on an image.

pins is a space-separated list of label:x,y (percent coordinates). fixed makes it read-only; otherwise click to add and click a pin to remove. labelStart sets the first label (letter or number).

  • Body: image path
  • Attributes: pins, fixed, labelStart
:md-pins[./images/battle-map.png]{pins="A:25,50 B:75,30 C:50,80" fixed}
:md-pins[./images/dungeon.png]{labelStart="1"}

:md-yarn-spinner

Runs a Yarn Spinner dialogue file.

start names the entry node (default start).

  • Body: Yarn Spinner file
  • Attributes: start
:md-yarn-spinner[./story.yarn]{start="start"}

Inline directives

:[name]

Inserts an icon looked up under assets/ (searching upward from the file).

Default extension is .png; .svg, .gif, .jpg, .jpeg, and .webp are also supported. label overlays text, repeat duplicates N times, and join places a tag name between repeats.

  • Body: icon name
  • Attributes: label, repeat, join, class
:[attack]  :[shield.svg]  :[potion]
:[attack]{label=ATK repeat=3 join=br}

:cmd[command]

Renders a clickable span that dispatches a journal command.

  • Body: journal command
  • Attributes: label
:cmd[roll 1d20+5]{label=Roll initiative}
:cmd[spark dungeon room-type]{label=Random room}

Code block roles

The role= attribute on the info string determines how a fenced block is handled.

Fences may use backticks or tildes (~~~); the closing fence must reuse the opening marker. Fence attribute keys may contain hyphens (e.g. data-foo=bar).

role=spark-table

CSV (or markdown pipe table) rendered as :md-table.

The first column header must be a dice formula; each row's first cell is the roll value (a number, or a range like 1-3). Extra fence attributes are forwarded to the generated :md-table, e.g. ```csv role=spark-table roll=true.

```csv role=spark-table
d6,结果
1,遭遇强盗
2,平安无事
```
```markdown role=spark-table
| d6 | 结果 |
|----|------|
| 1  | 遭遇强盗 |
| 2  | 平安无事 |
```

role=declare

Reactive variable / tag-modifier definitions.

YAML with two optional maps. vars: maps a $name to its expression. tags: maps a tag name to a map of thresholds to $target modifiers: at that tag count the target gains the value, so sibling thresholds stack. Tag names may be written with or without the leading #. YAML resolves bare numbers to numbers and everything else to strings; both become expression text.

```yaml role=declare
vars:
  $hp: $con*5 + $mod_hp
  $ac: 10 + $dex
tags:
  warrior:
    1:
      $mod_hp: 20
    2:
      $mod_str: 1
```

role=file

Stored as inline text content and stripped.

Referenced by the derived inline id, e.g. :md-embed[./text_<hash>].

```text role=file
Stored as inline content.
```

role=tag

YAML rendered as a custom element.

tag: names the element, body: becomes its content, and any other key becomes an attribute. Fence-line attributes override the YAML body. See yaml-tag.md.

```yaml role=tag
tag: md-deck
body: ./cards.csv
size: 63x88
grid: 5x5
```

No role / unknown role

No role → a normal visible code block. Unknown role → warned about and stripped.

Dice notation

Used by :md-dice, spark-table headers, and the journal /roll:

Notation Meaning
2d6 two six-sided dice
1d20+5 d20 plus modifier
d20 one twenty-sided die (count optional)
3d6kh1 keep highest 1
3d6dl2-1 drop lowest 2, minus 1
{d4, d8} choose one of the listed dice

CSV data files

Keep CSV files clean — a header row and data rows. Put deck configuration and templates in a yaml role=tag block's data-config.

  • label — unique row id (number or text).
  • body — main content, supports markdown.
  • Any other columns are custom fields.
  • {{prop}} in body interpolates another column (or front-matter key) from the same row; with {remix} it pulls from a random row.
  • Wrap values containing ,, ", or newlines in double quotes; escape " as "". Lines beginning with # are comments.