Authoring Guide

Visuals — Images, Icons & Diagrams

Images with zoom and dark-mode variants, the Iconify icon set, and Mermaid diagrams for flows, sequences and architecture.

A diagram or a well-placed icon does what a paragraph can't. This page covers raster/vector images, icons, and live Mermaid diagrams.

Images

Drop files in public/ and reference them with an unprefixed path (no locale). Plain Markdown works, and images get click-to-zoom by default.

![KLSTR.one front panel](/images/klstr-one.png)

For finer control use :img (set width/height, or disable zoom):

:img{src="/images/klstr-one.png" alt="KLSTR.one front panel" width="480" zoom="false"}
Need a different image per theme? :color-mode-image{light="/diagram-light.svg" dark="/diagram-dark.svg" alt="…"} swaps automatically with the light/dark toggle. SVG illustrations in public/ stay crisp at any size and theme.

File downloads

To offer a file (firmware image, PDF, archive), drop it in public/ and link it with a button carrying external and download:

:u-button{label="Download sniffer.klstr.nano" icon="i-lucide-download" to="/firmware/sniffer.klstr.nano" external download="sniffer.klstr.nano"}
Give download the filename, never write it bare. MDC turns a valueless prop into the string "true", and the download attribute's value is the suggested filename, so a bare download saves the file as true with no extension. Always write download="the-real-filename.ext".
Never put a button inside a callout.::note / ::tip / ::warning style every descendant link with arbitrary variants like [&_a]:text-success. Those compile to a descendant selector, which outranks the button's own text-inverted, so the label takes the callout's colour and becomes unreadable against the button fill. Put buttons in the page body and use plain prose for the surrounding note.
external is not optional, and its absence is the whole trap. i18n rewrites every internal link to include the current locale, so to="/firmware/x.bin" renders as href="/en/firmware/x.bin" and 404s. This happens to a plain Markdown link ([text](/firmware/x.bin)) and to a raw <a href> too, because MDC routes both through the same link component. external makes it render a plain anchor and the path survives untouched. download then saves the file instead of navigating to it.Images are exempt: they go through the image pipeline (/_ipx/…), which is why ![alt](/images/x.png) needs no special treatment.
public/ is not tiered. Every build ships the whole folder, so a file placed there is reachable by URL on the public site as well, even when the page linking to it is cloud or internal only. It is unlisted, not protected. Anything that must be restricted needs a real gate, not a public/ path.

Icons

Any Iconify icon works via :icon{name="…"}. This site uses the Lucide set by default (i-lucide-*); other collections work with their prefix (i-simple-icons-gitlab, i-logos-cloudflare, …).

:icon{name="i-lucide-cpu"} :icon{name="i-lucide-network"} :icon{name="i-lucide-shield-check"} :icon{name="i-simple-icons-cloudflare"}

The same i-lucide-* names are what you put in .navigation.yml icon: and on ::card / ::callout icon props.

Mermaid diagrams

::mermaid renders diagrams from text — flowcharts, sequences, state machines, ER, Gantt and more. It follows the site's light/dark mode. Pass the definition as a YAML code: | block so Markdown leaves the arrows alone.

Flowchart

Loading diagram…

::mermaid
---
code: |
  graph TD
    A[Browser request] -->|JWT cookie| B(Worker middleware)
    B --> C{app_role}
    C -->|admin| D[Render internal docs]
    C -->|other| E[302 → /login]
---
::

Sequence diagram

Loading diagram…

Architecture / graph

Loading diagram…

Mermaid renders client-side only (it needs a browser), so on the prerendered build you'll see a brief "Loading diagram…" before it paints. Syntax reference: mermaid.js.org.
Copyright © 2026