chore(skill): Own tttk-authoring in the repo
Move the skill to .agents/skills/tttk-authoring and point gen:skill-reference at it. Activate it by symlinking ~/.agents/skills/tttk-authoring to the in-repo copy. Extend the reference drift guard to cover the skill copy now that it is versioned, and document activation in docs/development.md.
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
---
|
||||
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, :md-commander, 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. |
|
||||
| ` ```csv role=declare ` | Defines reactive variables / 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` row skipped (empty `key` or `expr`) |
|
||||
| `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.
|
||||
Reference in New Issue
Block a user