Files
ttrpg-tools/.agents/skills/tttk-authoring/reference.md
T
hypercross 1ce76dca64 feat(md-print): use mm font and corner page numbers
Body font size is now specified in millimetres and defaults to 3mm. Page numbers move from the centre footer to the outer bottom corners, alternating left and right per A5 page.
2026-10-23 11:28:22 +08:00

389 lines
9.5 KiB
Markdown

# 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](#directive-syntax)
- [Custom elements](#custom-elements)
- [Inline directives](#inline-directives)
- [Code block roles](#code-block-roles)
- [Dice notation](#dice-notation)
- [CSV data files](#csv-data-files)
## Directive syntax
```text
: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:
```markdown
::: 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`, `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`
```markdown
:md-dice[1d20+5]{key="attack"}
```
```markdown
:md-dice[2d6+3]
```
```markdown
: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`
```markdown
:md-table[./npcs.csv]
```
```markdown
:md-table[./encounters.csv]{roll=true}
```
```markdown
: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`
```markdown
: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 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`, `cutMarks`
```markdown
:md-print[./rules.md]{columns="2" margin="10" gap="5" font="3"}
```
````markdown
```yaml role=tag
tag: md-print
body: ./rules.md
columns: 2
margin: 10
gap: 5
font: 3
title: 规则书
```
````
### `:md-link`
Clickable link that expands the target article inline.
- Body: path, optional #section
```markdown
:md-link[./rules.md]
```
```markdown
: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`
```markdown
: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`).
```markdown
:md-bg[./images/dungeon-bg.jpg]{fit="cover"}
```
```markdown
: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`).
```markdown
:md-border[crimson]{.b}
```
```markdown
: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`
```markdown
: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`
```markdown
:md-pins[./images/battle-map.png]{pins="A:25,50 B:75,30 C:50,80" fixed}
```
```markdown
: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`
```markdown
: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`
```markdown
:[attack] :[shield.svg] :[potion]
```
```markdown
:[attack]{label=ATK repeat=3 join=br}
```
### `:cmd[command]`
Renders a clickable span that dispatches a journal command.
- Body: journal command
- Attributes: `label`
```markdown
:cmd[roll 1d20+5]{label=Roll initiative}
```
```markdown
: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 `.
````markdown
```csv role=spark-table
d6,结果
1,遭遇强盗
2,平安无事
```
````
````markdown
```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.
````markdown
```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>]`.
````markdown
```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`.
````markdown
```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.