How to add a node or renderer
A practical guide to extending Wit's vocabulary and emitting new output formats. For developers.
Three ways to get a new node
- A user definition — no code. Write
#name … name#and use it. This is the right answer for almost every "new node." - A core-vocabulary addition — code in the runtime and every renderer. Reserve this for shapes that belong to the language itself.
- The opaque pass-through —
@node(type …)carries its parameters straight to the renderer, which dispatches on thetypeconvention. This is the seam for renderer-specific widgets.
Adding to the core vocabulary
A core node is a commitment: every renderer must handle it. The cadence is test-first.
- Register the name in
core-vocab.tsso the resolver stops requiring a definition for it. - Add a handler in each renderer — the HTML and Markdown renderers both need a branch.
- Add a fixture under the core-vocab fixtures, with its snapshot, beforethe change — the fixtures are the executable spec, and a core node without one breaks that contract.
Writing a custom renderer
Walk the expanded AST and dispatch on each node's kind. The kinds form
a stable, serializable, exhaustive union — you can enumerate them with wit tour. A minimal skeleton switches on kind, recurses
into children, and handles a node use by its name.
The opaque escape valve
When you need a renderer-specific widget — a chart, a map, a game-state panel — @node(type …) passes its parameters through untouched. The
resolver skips binding lookup and the expander emits the node intact, so your
renderer sees every parameter and can build whatever it likes. User-defined
wrappers compose over it cleanly, so authors get a friendly name and the renderer
gets the raw payload.
Wiring it in
Whether you drive the CLI or your own program, the shape is the same: parse, resolve, expand, then your renderer. A
document that loads external data adds loadExternalData before resolve.
Common mistakes
- A core node without a fixture. It breaks the executable-spec contract — add the fixture and snapshot first.
- Lifting stale prose. Older reference files predate recent features; verify any snippet against current renderer code and a real build before copying it.
See also
Architecturemaps the stages you hook into; Write a custom renderer and Embed the Wit parser are the worked versions; Design principles explains why the core stays small.