Woodcut figures are data, not drawings. You choose a diagram type, emit a JSON payload, and the component renders it on-grammar: hover cards, fullscreen expand, variants, and scenario replay come free.
Read GRAMMAR.md in this repo before your first figure.
| The prose asks | Type | Element |
|---|---|---|
| Where does it live? What talks to what? | block diagram | <wc-block-diagram> |
| What can happen? What are the states? | state machine | <wc-state-machine> |
| Which way does it go? What decides? | flowchart | <wc-flowchart> |
| Who does what? Where does responsibility move? | swimlane | <wc-swimlane> |
| In what order? Who calls whom? | sequence | <wc-sequence> |
Flowchart and swimlane use the block-diagram data shape: flowchart
adds node shapes (pill, diamond, end); swimlane adds lanes.
Sequence uses actors, activations, and messages.
Embed a JSON payload in the element. See docs/index.html for one
worked example of every type. The shape:
<wc-state-machine>
<script type="application/json">
{
"label": "FIG 2 · PROPOSAL LIFECYCLE",
"hint": "pick a scenario · step or play",
"caption": "One sentence that states a fact.",
"variants": [ { "name": "lifecycle", "viewBox": [600, 212],
"states": [...], "transitions": [...], "scenarios": [...] } ]
}
</script>
</wc-state-machine>
Rules for the payload:
title and body instead of log.Any diagram type can tell a story one step at a time. Use narration when the prose explains a process that unfolds, and the reader must follow what changes at each step: a request moving through a system, a document moving through review, a release moving through its gates. Skip it when the figure answers its question at a glance. A plain replay with a log line per step is enough for short paths.
A scenario becomes a walkthrough when any step carries title,
body, record or summary, or when the scenario sets reveal.
The fields:
| Field | Where | What it does |
|---|---|---|
title |
step | A short headline for the step, in sentence case. |
body |
step | One or two plain sentences. Say what happens and why. |
record |
step | Rows of [key, value]: what the system holds after this step. Add true as a third item to mark a row the step changed. |
denied |
step | Element ids to mark as denied or blocked: a dashed danger border. |
deniedLabel |
step | Short caps text for a badge on each denied node, for example "1.3.2 EXISTS". |
summary |
step | { "title", "head": [...], "rows": [[...]] }. A table under the figure. Use it on the last step only. |
reveal |
scenario | true hides each element until the step that reaches it. |
recordLabel |
scenario | The heading of the record panel, in caps. |
{ "name": "a clean release", "reveal": true, "recordLabel": "WHAT THE RELEASE HOLDS",
"steps": [
{ "active": ["e1", "ci"], "name": "test",
"title": "CI tests the commit",
"body": "The workflow runs the tests. A failure stops the run here.",
"record": [["version", "1.4.0"], ["tests", "212 passed", true]] },
{ "active": [], "denied": ["yes", "registry"], "deniedLabel": "1.3.2 EXISTS",
"name": "refused", "title": "The path to the registry is closed",
"body": "A registry accepts each version once." }
] }
Rules for a walkthrough:
active. The arrow draws itself, then its label appears.name to one lowercase word. It labels the tracker pill.— for a value that does not exist yet.denied for a refusal, never for emphasis. The danger color
is the one exception to the single accent.reveal, every element no step names stays hidden. Name
every element the story needs.reveal walkthrough is the exception: its
first step must still make sense on its own.If any check fails, fix the data, not the component.