Structure & layout
Headings give a document its outline; sectioning wrappers give it a skeleton; lists, quotes, and rules set pieces apart; rows and columns place blocks side by side. Every one is a node.
Two ways to write a node
A node that fits on one line uses the parenthesis form, (name … name). A container that spans several lines uses the
block form, @name on its own line and name@ to
close. They mean the same thing:
(h2 Methods h2) @section The survey ran from May to September. section@
Methods
The survey ran from May to September.
Parameters glue to the name in either form: (span(class: lede) … span), @div(class: card).
Headings
Six levels, h1 through h6. Level one is the title;
deeper levels nest under it.
(h1 Coastal survey 2024 h1) (h2 Methods h2) (h3(id: calibration) Tide-gauge calibration h3)
Each renders straight into its tag — <h1>Coastal survey 2024</h1> —
and an id becomes an anchor you can link to. Don't skip a level for
a smaller heading; size is a styling concern.
Sectioning wrappers
Semantic containers describe the shape of the page. Each maps to the same-named
HTML element: article (a self-contained piece), section (a thematic division), header and footer (opening and closing blocks), nav, aside (supporting content), and main.
@article @header (h1 A survey of the northern reef h1) header@ @section The season opened early this year. section@ @footer (small Published 2024. small) footer@ article@
A survey of the northern reef
The season opened early this year.
That builds an <article> holding a <header>, <section>, and <footer>. Prose inside a container
is wrapped in paragraphs for you, so don't add an inner (p … p).
Generic containers
When no semantic wrapper fits, use the block div or the inline span. Give either a class or id to hook it for CSS:
@div(class: callout-card) A boxed note, grouped for styling. div@ An (span(class: lede) opening clause span) inside a sentence.
A boxed note, grouped for styling.
An opening clause inside a sentence.
The block becomes <div class="callout-card">, the inline one a <span class="lede">.
Bulleted & numbered lists
A list holds one li per item. The theme draws the markers — never
type a dash or a number yourself.
@ul (li Salt marsh li) (li Mud flat li) (li Shingle bank li) ul@
- Salt marsh
- Mud flat
- Shingle bank
Swap ul for ol and the items are numbered;
reorder them and they renumber.
Definition lists
A dl pairs a term (dt) with its description
(dd) — a glossary, a field key:
@dl (dt Transect dt) (dd A fixed line along which measurements are repeated. dd) (dt Datum dt) (dd The reference level all heights are measured from. dd) dl@
- Transect
- A fixed line along which measurements are repeated.
- Datum
- The reference level all heights are measured from.
Nested lists
An item can carry marks, links, or a whole list. When an item holds a nested list it spans several lines, so write it in the block form:
@ul (li The _daily_ readings, taken at dawn. li) @li Supplies aboard the tender: @ul (li spare batteries li) (li calibration weights li) ul@ li@ ul@
- The daily readings, taken at dawn.
Supplies aboard the tender:
- spare batteries
- calibration weights
Block quotations
A blockquote lifts a passage off the page — an epigraph, a pulled
quote, a cited paragraph:
@blockquote "The sea, once it casts its spell, holds one in its net of wonder forever." — Jacques Cousteau blockquote@
"The sea, once it casts its spell, holds one in its net of wonder forever." — Jacques Cousteau
For a short quoted phrase inside a sentence, plain quotation marks are enough.
Preformatted text
A pre block renders monospaced and keeps its line breaks and
indentation. Its body is still read as Wit, so _x_ would turn
italic. For code, use the verbatim form @@pre … pre@@, which shows
its body exactly as typed:
@@pre def read(): return gauge.level_m # 2.41 pre@@
def read():
return gauge.level_m # 2.41Horizontal rule
A divider — a visual break with no heading. It takes no body and no closer:
The first movement ends here.
@hr
The second begins.The first movement ends here.
The second begins.
That produces a plain <hr> between two paragraphs.
Side-by-side: rows & columns
A row lays its columns out horizontally. @col(size: 260) fixes a column's width; a bare @col fills whatever space is left.
Put anything in a column — prose, an image, a table:
@row @col(size: 260) @img(src: ./gauge.png, alt: The tide gauge) col@ @col The gauge logged every hour of every tide, its readings the backbone of the season's survey. col@ row@
Two bare columns split the row evenly — here it is live:
The lamp room. Glass on every side and a lens that threw the beam twenty miles out to the shipping lanes.
The watch room. Below the light, a desk, a barometer, and the log where every hour of every night was accounted for.
A size takes a named preset (small, medium, large — 220, 380, 600 pixels), a pixel number, or a percentage. The row wraps: when the screen or page is too narrow, the columns stack. Separate a row from surrounding prose with blank lines.
See also
- Writing text — the inline marks these blocks hold.
- Tables — a captioned table to place inside a column.
- Images & media — sizing a figure in a fixed column.