The journal now owns command history and tracking, so retire the md-commander widget. Its dice engine was extracted to src/components/dice in the previous commit. Removes the custom element, tracker/command stores, completions, useCommander, Emmet parser, the doc entry, test fixtures, and the known-element catalog entry (reference docs regenerated). BREAKING CHANGE: :md-commander is no longer a known element; content using it now fails tttk check with TTTK-D001.
139 lines
6.5 KiB
Markdown
139 lines
6.5 KiB
Markdown
---
|
|
name: tttk-authoring
|
|
description: Author and edit TTRPG game design documents for the tttk (Tabletop Toolkit) CLI. Use when writing or modifying markdown content that uses tttk custom elements (:md-dice, :md-table, :md-deck, :md-pins, etc.), custom fenced code blocks (role=spark-table / declare / file / tag), companion CSV data files, or when previewing content with `tttk serve` and validating it with `tttk check`.
|
|
---
|
|
|
|
# Authoring tttk game design documents
|
|
|
|
`tttk` (Tabletop Toolkit) renders a folder of markdown into an interactive TTRPG
|
|
web app. A game design document is **ordinary GFM markdown** plus exactly two
|
|
extensions:
|
|
|
|
1. **Custom elements** written with `marked-directive` syntax: `:name[content]{attrs}`.
|
|
2. **Custom fenced code blocks** whose info string carries a `role=` attribute.
|
|
|
|
Everything else — headings, lists, tables, blockquotes, alerts, mermaid — is
|
|
standard markdown. Do not invent element names, props, or roles; check
|
|
`reference.md` when unsure. Deeper topics have their own files: `yaml-tag.md`
|
|
(deck config), `csv.md` (data files), `layout.md` (columns), and `markdown.md`
|
|
(alerts and mermaid).
|
|
|
|
## Workflow
|
|
|
|
- Content lives in a directory (commonly `content/`). Preview with hot reload:
|
|
`npx tttk serve ./content` (default port 3000, override with `-p 8080`).
|
|
- **Validate after every edit:** `npx tttk check ./content`. It exits `1` when
|
|
there are errors and prints `file:line` diagnostics. Use `--json` for
|
|
machine-readable output and `--quiet` for errors only. This is the primary
|
|
verification loop: write → check → fix.
|
|
- The scanner picks up `.md`, `.csv`, `.yarn`, and `.svg` files.
|
|
- All paths in directives are **relative to the current markdown file**
|
|
(`./data.csv`, `../shared/npcs.csv`, `./images/map.png`).
|
|
- A typical game/adventure folder:
|
|
```
|
|
my-adventure/
|
|
├── design.md # design notes (plain markdown)
|
|
├── adventure.md # the document players/GM read
|
|
├── locations.csv # data referenced by :md-table
|
|
├── cast.csv
|
|
└── route.csv
|
|
```
|
|
|
|
## Directive syntax
|
|
|
|
```
|
|
:name[content]{key="value" .class #id}
|
|
```
|
|
|
|
- `[content]` is the directive body — a path, dice formula, color, etc.
|
|
- `{key="value"}` sets attributes. `{.class}` and `{#id}` are shorthands.
|
|
- Container directives use `::: name` … `:::`; nest deeper with `::::`, `:::::`.
|
|
|
|
Use the **registered element names**: `:md-dice`, not `:dice`. The full list is
|
|
in `reference.md`.
|
|
|
|
## Code block roles
|
|
|
|
Fenced blocks are dispatched by the `role=` attribute in the info string:
|
|
|
|
| Info string | Behavior |
|
|
|---|---|
|
|
| ` ```csv role=spark-table ` | Body is CSV; replaced with `:md-table[./csv_<hash>]`. First column header must be a dice formula (`d6`, `2d6+1`, …). |
|
|
| ` ```markdown role=spark-table ` | Body is a GFM pipe table; converted to CSV, then same as above. |
|
|
| ` ```yaml role=declare ` | YAML `vars:` / `tags:` maps defining reactive variables and tag modifiers. Block is stripped. |
|
|
| ` ```<lang> role=file ` | Body stored as text content, block stripped, referenced by its derived id. |
|
|
| ` ```yaml role=tag ` | Kept intact; rendered as a custom element from YAML (`tag:`, `body:`, …). |
|
|
| ` ```<lang> ` (no role) | Rendered as a normal visible code block. |
|
|
| unknown role | Warned about and stripped. |
|
|
|
|
## Rules that prevent broken output
|
|
|
|
- Quote any attribute value containing spaces or `"`:
|
|
`{pins="A:30,40 B:10,30"}`.
|
|
- In CSV, wrap fields containing `,`, `"`, or a newline in double quotes and
|
|
escape `"` as `""`. Lines starting with `#` are comments.
|
|
- `label` and `body` are the conventional CSV columns. Put titles inside `body`
|
|
as markdown headings; use **bold labels** for sub-fields, not headings.
|
|
- A `group` column in a table CSV automatically produces group tabs — no
|
|
attribute needed.
|
|
- Reference each CSV once per document; don't repeat the same `:md-table`.
|
|
- For card decks, use the `yaml role=tag` form with `tag: md-deck` (see
|
|
`yaml-tag.md`). The `:md-deck[...]{...}` directive is legacy and can't express
|
|
template layers or card backs.
|
|
- Keep CSV files clean — header row plus data. Put deck config and templates in
|
|
the YAML block's `data-config`, not in CSV front matter (see `csv.md`).
|
|
- `{{prop}}` in a CSV `body` interpolates another column (or front-matter key)
|
|
from the same row; with `{remix}` it pulls from a random row instead.
|
|
|
|
## Validation
|
|
|
|
`npx tttk check ./content` validates against the same content registry the app
|
|
uses, so a clean check means the app resolves the content too. Errors exit `1`:
|
|
|
|
| Code | Meaning |
|
|
|---|---|
|
|
| `TTTK-S002` | container directive `:::` never closed |
|
|
| `TTTK-D001` | unknown `:md-*` element name |
|
|
| `TTTK-D002` | malformed attribute block (e.g. an unquoted value with a space) |
|
|
| `TTTK-R001` | unknown code-block `role=` (the block is silently dropped) |
|
|
| `TTTK-R003` | `role=declare` failed to parse |
|
|
| `TTTK-R005` | `role=tag` YAML is invalid |
|
|
| `TTTK-R006` | `role=tag` missing or naming an unknown element |
|
|
| `TTTK-C001` | content reference does not resolve |
|
|
| `TTTK-C004` | `:md-embed` cycle |
|
|
| `TTTK-L001` | link target file does not exist |
|
|
| `TTTK-V001` | CSV failed to parse (e.g. an unclosed quote) |
|
|
|
|
Warnings are usually real too:
|
|
|
|
| Code | Meaning |
|
|
|---|---|
|
|
| `TTTK-R002` | spark-table first header is not a dice formula |
|
|
| `TTTK-R004` | `role=declare` block declares nothing |
|
|
| `TTTK-C002` | reference resolves to an unexpected file type |
|
|
| `TTTK-L002` | `#section` matches no heading |
|
|
| `TTTK-A001` | icon missing under `assets/` |
|
|
| `TTTK-A002` | image missing |
|
|
| `TTTK-V002` | CSV row column count differs from the header |
|
|
| `TTTK-V003` | duplicate `label` values |
|
|
| `TTTK-V004` | `{{prop}}` is not a CSV column or front-matter key |
|
|
| `TTTK-V005` | spark-table roll value is not a number or range |
|
|
|
|
`TTTK-C003` (info) flags the same CSV referenced twice by `:md-table` in one
|
|
document. Icon checks assume no `assets/` directory exists above the checked
|
|
directory. The full code catalog lives in `reference.md`.
|
|
|
|
## Reference
|
|
|
|
- `reference.md` — **generated** catalog of every custom element, inline
|
|
directive, code block role, and dice notation. Do not edit by hand;
|
|
regenerate from the repo with `npm run gen:skill-reference`.
|
|
- `yaml-tag.md` — `role=tag` blocks, `data-config` layers, card backs, and the
|
|
legacy `:md-deck` layer syntax.
|
|
- `csv.md` — CSV authoring: columns, `{{prop}}` interpolation, quoting, and the
|
|
discouraged front-matter form.
|
|
- `layout.md` — column layout markers.
|
|
- `markdown.md` — GitHub alerts and mermaid diagrams.
|
|
- `examples/adventure.md` and `examples/encounters.csv` — a complete minimal
|
|
document and its data file.
|