Appendix · Playground
Type it. Watch it parse.
The left pane is an ANVIL fence. The right pane is what the reference renderer makes of it, redrawn as you type. Underneath, every complaint the parser had.
- RUNS IN
- This tab. No request leaves the page, and nothing you type is stored.
- USING
- @anvil-md/parser and @anvil-md/render-html, unmodified, from source.
- DISPLAY
- Controls are inert by design - this draws a block, it does not run one.
Examples
streaming passes false as the second argument to renderAnvilFence, which is the state a fence is in while the model is still typing it: rendered, visibly provisional, and never answerable.
Source
Rendered
An agent writes one of these inside a fenced anvil block, mid-sentence.
Edit the source on the left. The right-hand pane redraws as you type.
Parse report
The parser never throws. It complains.
A fence arrives token by token, so every prefix of every block is a real input. Malformed input degrades to a renderable block plus a warning - try the malformed example above.
3 blocks · 0 warnings · fence closed
| Block | Kind | Diagnostics |
|---|---|---|
| a49b3ab81 derived | @note | accepted, no warnings |
| deploy-target | @choice | accepted, no warnings |
| tone | @scale | accepted, no warnings |
Wiring
Nothing on this page is special.
// the playground is these three lines, in a keyup handler
out.innerHTML = renderAnvilFence(textarea.value, fenceIsClosed)
const doc = parseAnvil(textarea.value, { partial: !fenceIsClosed })
// doc.blocks[n].warnings is what the report below is reading
Both packages are zero-dependency and DOM-free, so they run in a browser tab, in a Worker, or in whatever renders your transcript. The blocks above were drawn at build time by the same call, from the same string, which is why the page works with JavaScript off. Back to the specification.