Skip to main content
Narration is more useful when the words stay connected to the code. If a sentence mentions order, a viewer should be able to highlight every other mention of order. If it mentions notifyFinance, a click should jump to that function. Narrator keeps that connection by embedding small markup tokens inside each line’s text.

The five kinds

Each token has a kind, an optional payload (usually the original identifier), and the display text. The tokens use characters from Unicode’s private use area (U+E000 to U+E002), so they never collide with real text. You will rarely need to look at them directly. Use one of the renderers in @usenarrator/core instead.

Rendering

markup.ts
Output
  • plain(text) strips the markup and wraps type names in parentheses. This is what renderText uses by default.
  • toHtml(text, resolve) wraps each token in a <span> with the kind as its class. Your resolve callback can return a link for function and value references, or null to leave them unlinked. Values also get a data-n attribute so a viewer can highlight every use of the same name.
  • toAnsi(text) colours tokens for a terminal. The CLI uses it unless you pass --plain.

Writing markup in a plugin

When a plugin builds a phrase, it receives arguments that are already rendered markup strings, so in most cases you never create tokens yourself. If you do need one, mk(kind, text, payload) creates it, and the engine’s e.ref(name) and e.prop(key) helpers create value tokens with the right display words.
Grammar helpers in a locale must be markup aware. For example, English possessive adds 's after the closing token marker, not inside it. If you write a locale, test with names, not only plain words.