Docs are plain markdown files in src/content/docs/ — a folder is a section,
frontmatter orders the pages, and everything on this page is available in any
.md file. This page is the living reference: every feature below is its
own demo.
- src/content/docs/
- getting-started/section = folder
- introduction.md
- installation.md
- widgets/
- your-first-widget.md
- reference/
- authoring.mdthis page
- getting-started/section = folder
Frontmatter is five fields, only title required:
title: Writing these docs
description: Shown under the title and in search.
order: 1 # position within the section
badge: NEW # optional chip in the sidebar
updated: 2026-07-21
Headings
The # h1 comes from frontmatter — start your body at ##. An ## heading
gets the gradient tick and a hairline, lands in the right-hand On this
page rail, and grows a copy-link anchor on hover (try hovering any heading
here). ### nests beneath it in the rail; #### renders as an editorial
caps label for tight groupings.
Like this one
Text, links, inline bits
Standard markdown works: bold carries the white, italics stay quiet,
and links underline on hover. Inline
code wears a chip. Keyboard keys use the :kbd directive — press
Ctrl K to search — and badges tag things inline:
NEW BETA DEPRECATED V1.
Inline icons come from the product’s own set:
.
A plain blockquote stays for quoting people and specs. For anything that gives the reader advice, use a callout instead.
Callouts
Five tones. Title is optional ({title="…"}).
Separators
Three grades: a paragraph break, a labeled separator, and the full island rule for hard topic changes.
The island rule (a plain ---):
Tables
| Component | Kind | One-liner |
|---|---|---|
row / col | container | flex layouts, gap / align / justify |
box | container | a painted panel — bg, radius, ring |
text | leaf | bound or fixed, size / weight / role |
icon | leaf | product icon set, set = "duotone" for the fancy ones |
bar | leaf | progress — track, fill, bound to a number |
Code
Fences get a frame, a language chip, a copy button, and line numbers.
title="…" adds a filename; {2,4-5} highlights lines; // [!code ++] and
// [!code --] mark diffs.
return {
card = {
type = "row", gap = 10, align = "center",
children = {
{ type = "icon", value = "heart", color = "accent" },
{ type = "icon", value = "bird", color = "accent" },
{ type = "text", bind = "label", flex = 1 },
},
},
}
Steps
-
Write the step title in bold. Then explain it. Steps take any block content — code, callouts, images.
-
Keep steps for sequences. If the order doesn’t matter, it’s a list, not steps.
-
End on the payoff. The last step should leave the reader with something running.
Tabs & details
Use tabs for the same task on different platforms or formats — never for unrelated content a reader might miss.
Use :::details for the long tail: edge cases, troubleshooting, “why is it
like this” — anything most readers should skip.
A collapsed details block
Open by choice, skimmed past by default. Takes any block content.
Charts
Charts are fenced ```chart blocks of JSON, rendered in Perch’s own
palette with tooltips, draw-in motion, and automatic legends. Six types:
bar, line, area, donut, meter, stat, plus spark for inline
trends. A single series wears the product’s viz gradient; multiple series
use the validated categorical palette in fixed order.
File trees
Two-space indentation, trailing / for folders, # for notes:
- perch-widget/
- mod.jsondata only
- displays.lua
- logic.lua
- assets/
- icon.pngserved file:// by the host
Images
Images get the product’s art radius and a click-to-zoom lightbox; a title
becomes the caption.

That’s the whole surface. When a page needs something this set can’t say, extend the system — don’t hand-roll HTML in content files.