# 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-=`. - 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_]`. ````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.