# Document format: directives

> The ::: directives: containers, columns, paper, page breaks, numbering, space, verse, contents and index, line breaks, and the markup of comic pages

- HTML version: https://postext.dev/en/docs/document-format-directives
- Last updated: 2026-10-16
- Reading time: 34 min
- Other languages: [es](https://postext.dev/es/docs/document-format-directives.md), [ca](https://postext.dev/ca/docs/document-format-directives.md), [de](https://postext.dev/de/docs/document-format-directives.md), [fr](https://postext.dev/fr/docs/document-format-directives.md), [it](https://postext.dev/it/docs/document-format-directives.md), [pt](https://postext.dev/pt/docs/document-format-directives.md), [zh](https://postext.dev/zh/docs/document-format-directives.md), [ja](https://postext.dev/ja/docs/document-format-directives.md), [ar](https://postext.dev/ar/docs/document-format-directives.md)

## In short

A directive is a block that starts with three colons, such as :::callout or :::columns. This page lists every directive and what it does. Some put text in a box, set it in columns or print it on another kind of paper. Others start a new page, change the numbering, add space, set a poem line by line, or print the table of contents and the index. The last section covers the marks for comic pages, panels and the words of the characters.

## Directives

Directives are single-line control tags written as `:::name` or `:::name{attrs}` on their own line. They produce no visible output — they drive the placement and numbering pipeline.

| Syntax | Effect |
| --- | --- |
| `:::pagebreak` | Force the next block to open on a new page. |
| `:::pagebreak{parity="odd"}` | Same, plus ensure the new page is odd (right-hand). Inserts a blank padding page when needed. |
| `:::pagebreak{parity="even"}` | Same, but targeting an even (left-hand) page. |
| `:::pagebreak{parity="always-odd"}` | Guarantee at least one mandatory blank separator page before landing on an odd page. The separator blank belongs to the preceding content; any further parity padding belongs to what follows. Useful when every chapter must start on a fresh spread. |
| `:::pagebreak{parity="always-even"}` | Same, but targeting an even page. |
| `:::numbering{format="decimal" startAt=1}` | At the next page boundary, switch the page-numbering sequence. Both attributes are optional — omit `format` to keep the format, omit `startAt` to continue the counter. |
| `:::columnbreak` | End the current column here: the next block opens in the next column of the same page (or on a new page when the directive lands in the last column). A no-op in an empty column, so it never produces a blank column or page. The column it ends keeps its bottom gap — column balancing does not stretch it. |
| `:::space` | Leave one blank body line here — the explicit way to add a little air between two blocks. `:::space{lines=2}` leaves two (fractions such as `0.5` work too). It adds to the margin between the blocks and is dropped at the top of a column or page. See [below](https://postext.dev/en/docs/document-format-directives.md#space). |
| `:::toc` | Print the table of contents here: one entry per heading of the listed levels (title, number, page number, optionally the chapter authors) and one row per part divider, typeset per the `toc` configuration. The entries follow the document — rename, move or renumber a chapter and the contents follow. |
| `:::index` | Print the back-of-book index here: every term marked with `:index` in the book, sorted and grouped by letter, with the pages it falls on, typeset per the `index` configuration. `:::index{index="names"}` prints a named index. See [Back-of-book index](https://postext.dev/en/docs/document-format-notes-references.md#back-of-book-index). |
| `:::page{…}` … `:::` | A comic page: its `::panel` lines and their script lines, laid out as panels and lettered balloons on a page of its own. See [Comics](https://postext.dev/en/docs/document-format-directives.md#comics). |
| `:::strip{…}` … `:::` | A comic strip in the text flow, a column or a page wide. See [`:::strip`](https://postext.dev/en/docs/document-format-directives.md#strip). |
| `:::verse` … `:::` | A poem, set line by line as written (each line a line of verse, blank lines between stanzas, leading spaces an indent), or in the classical Arabic layout when its lines part their hemistichs with `\|\|`. See [below](https://postext.dev/en/docs/document-format-directives.md#verse). |

Attribute values may be double-quoted (`"…"`), single-quoted (`'…'`), or bare (`startAt=17`). A bare key without `=` is treated as a present-but-empty flag.

Only `pagebreak`, `numbering`, `columnbreak`, `space`, `toc` and `index` are recognized as single-line directives today (and `references`, `verse`, `page` and `strip` as fenced blocks) — any other `:::name` line that is not a container (below) is parsed as a paragraph and surfaces an **Unknown directive** warning in the sandbox. The engine records it too, as an `unknownDirective` entry in the document's `contentWarnings` (see [Configuration › Warnings in the document](https://postext.dev/en/docs/configuration-programmatic-usage.md#warnings-in-the-document)).

### Attribute values

The same `key="value"` syntax is read by heading attributes, directive and container fences (`:::name{…}`), inline references (`:ref{…}`), chips (`:chip[…]{…}`), swatches (`:swatch{…}`) and index marks (`:index[…]{…}`). Its rules:

- **Keys** start with an ASCII letter or `_` and go on with ASCII letters, digits, `_` or `-`. Spaces around `=` are fine, the fullwidth `＝` a Chinese input method types works as `=`, a repeated key keeps its last value, and a key without `=` is a flag with an empty value. A key in another script (`作者=曹雪芹`) is not read and raises an `attributeKeyInvalid` warning; the other keys of the block still apply. Values may be in any script.
- **Quoted values.** A double-quoted value may hold anything but `"`, single quotes included; a single-quoted one anything but `'`. So a value with double quotes goes in single quotes: `lead='He said "hi"'`. There are no escapes — a backslash is an ordinary character — so a value that needs both ASCII quotes takes typographic ones (`“…”`, `’`). A value may also open with the curly `“` or the corner bracket `「` a Chinese input method types, and then runs to the matching `”` or `」`, spaces included: `title=“甲戌本 眉批”`, `title=「脂批」`.
- **Bare values** (`startAt=17`, `year=1998`) run to the next space: `title=Hello world` is `title="Hello"` plus a flag `world`.
- **No braces.** `{` and `}` never go in a value. The first `}` ends the block: a fence whose value holds one is no longer a directive but a paragraph, and inline the rest of the value spills into the text. In a heading, a brace in a value leaves the whole block in the title: `# Title {note="a {b"}` is set as written. (Up to postext 1.8 a `{` after a space started the block over and `b` was read as a flag.)
- **Dollar signs are plain text.** Attributes are read before inline maths, so `lead="from $5 to $6"` is just text.
- **One line.** An attribute block never spans lines.

```markdown
# The Long Road {lead='A "road novel", they said' price="$18"}

:::callout{type="note" title='The "fast" path'}
…
:::
```

`::resource{id="…"}` is stricter: the id in double quotes and no other attribute (see [Resources](https://postext.dev/en/docs/document-format-resources.md#resources)).

### Containers

A container wraps a run of blocks in a fence: an opening line `:::name` or `:::name{attrs}`, then any ordinary content — paragraphs, headings, lists, blockquotes, formulas, even other directives — and a closing line holding a bare `:::`. Containers may nest; each closing `:::` closes the innermost open one.

```
:::callout{type="note"}
Keep the lantern lit **every** night.

- Check the wick.
- Trim it at dusk.
:::
```

Five container names are recognized in the text flow. What each one renders is set in its own section of the configuration:

| Syntax | Effect |
| --- | --- |
| `:::callout{…}` … `:::` | Boxed content — a note, tip or warning set apart from the body in a bordered or tinted box. |
| `:::paragraphs{…}` … `:::` | A run of paragraphs typeset with a named paragraph style (a lead-in, an epigraph, a set of small-print notes) instead of the body style. `align`, `indent` and `endIndent` set the alignment and indents with or without a style: `:::paragraphs{align=end endIndent=1}` sets a date one character up from the end of the line (地から1字上げ). `dropcap` switches a [drop cap](https://postext.dev/en/docs/document-format.md#drop-caps) on its first paragraph. |
| `:::part{…}` … `:::` | A part or section opener: the enclosed heading and prose form the opener page of a major division. |
| `:::paper{…}` … `:::` | A run of pages printed on another paper stock, such as a section of gloss plates in a matte book. Only the Folio viewer shows it. |
| `:::columns{…}` … `:::` | Blocks set in several columns of their own: inside a box, in the text column, or across a page of several columns. See [`:::columns`](https://postext.dev/en/docs/document-format-directives.md#columns) below. |

The attributes accepted by each container, and how it is styled, are documented in [Configuration](https://postext.dev/en/docs/configuration.md). Attribute values follow the same grammar as directives. A `:::callout` fence takes `type` (the id of a configured callout style — unknown or missing types fall back to the first style), `title` (overrides the style's default title), and `span` / `placement` (`column`, `page` or `side`; `here`, `top`, `bottom` or `fixed`) to override the style's extent and position for that box:

```
:::callout{type="objectives" title="What you will learn" span="page" placement="top"}
- Name the parts of the lantern.
- Trim the wick without touching the glass.
:::
```

A floated box (`placement` `auto`, `top` or `bottom`) also takes `columns`, how many adjacent columns it spans on a page of several, as in `:::callout{placement="top" columns="2"}` (since postext 1.18).

A box may also run the text after it beside it: `wrap` (`left`, `right`, `start` or `end`), `width` (its share of the column, 0 to 1; `layout.wrap.defaultWidth` when unset) and `wrapGap` (a length, such as `6pt`), as in `:::callout{wrap="right" width=0.4}` (see [Text wrap](https://postext.dev/en/docs/document-format-resources.md#text-wrap); since postext 1.24).

A callout is laid out as a box — an optional title, then its content typeset with the style's own body and list typography. It keeps together by default, moving whole to the next column or page when it does not fit (a box taller than a whole column splits all the same, rather than overflow); a style with `keepTogether: false` lets it split between its blocks, or between lines, leaving at least `splitMinLines` text lines — or a figure, table, display formula or nested box — on each side of the cut (a cut inside a paragraph or list item also leaves at least `layout.boxChildSplitMinLines` of its lines on each side: two by default, `splitMinLines` when that is lower; books saved before 1.5 whose chapters hold a box are read with 1, the 1.4 cut). Each part after the first opens without the icon, though its text keeps the icon's column, and without the title unless the style repeats it (`repeatTitle`: "Key points (cont.)"); a style can also set a "Continued" marker under every part that goes on (`continuesMarkerEnabled`) — see [Marks on a split box](https://postext.dev/en/docs/configuration-callouts.md#marks-on-a-split-box). Full-width boxes (`span="page"`) cut the page into column bands; `span="side"` boxes leave the flow into the float-only side column of a one-and-a-half layout (`layout.sideColumnRole: 'floats'`), stacked beside the text they interrupt, and lay out as column boxes where there is no such column; `placement="fixed"` boxes leave the flow and are pinned to page coordinates (a self-assessment badge in the bottom-left corner of a chapter's last page, say), the columns they cover giving up that zone; floating boxes (`placement="top"` / `"bottom"`) leave the flow where they occur and take the first free band after that position — the foot of the page, or the head or foot of the next — while the text after them fills the page they left. A style with `floatBarrier: true` (a chapter's closing "key points" box, typically) makes the box a **float barrier**: every figure or table referenced before it is placed before it — in the page's free slots, or on pages opened ahead of the box — so no float escapes past the end of its chapter. An unknown `:::name` fence is not a container — the line is treated as text, exactly like an unknown directive.

A `:::part` fence takes `number` (as you want it printed — `"I"`, `"IV"`, `"3"`; it is also parsed so the design can re-format it) and `title`; both are optional. A third attribute, `palette="band=#hex"` (several `id=#hex` pairs, comma-separated), recolours every design colour linked to those palette ids — running heads, opener band, part designs — and the text-flow colours that share their base value (headings, bold, references, bullets, captions, tables, boxes, chips) for the part and the chapters that follow it, until the next part; see [Configuration › Parts](https://postext.dev/en/docs/configuration-styles.md#parts). The container always opens a page of its own: a page break of the configured parity before it, a single body column at the `parts.margins`, the opener design over the whole page, and another page break after the closing fence. The body — usually the list of the chapters the part groups, or nothing at all — is typeset with `parts.bodyStyle`:

```
:::part{number="I" title="Foundations"}
1. The lantern and its parts
2. Trimming the wick
:::

# The lantern and its parts
```

With the default heading settings this produces the classic sequence: part page on a right-hand page, blank left-hand page, chapter on the next right-hand page. The page is reported as `role: 'part'` so headers and footers can skip it, and `{partTitle}` / `{partNumber}` resolve to the current part on every following page. See [Parts](https://postext.dev/en/docs/configuration-styles.md#parts) in the configuration reference.

A fence does not need a blank line before it: an opening or closing fence glued directly under a paragraph, list or blockquote ends that block. A container left open at the end of the document is closed automatically there, and the sandbox reports an **Unclosed container** warning pointing at the opening line. A stray `:::` with no container open is left in the text as a visible paragraph rather than dropped silently.

### `:::columns`

A `:::columns{count=2}` … `:::` group sets the blocks between its fences in `count` columns of equal width (2 to 6), the text after it taking the full width again. Inside a `:::callout` the columns share the box's inner width, the style's `columnGap` apart, in the box's body and list typography, and the box grows to the tallest column. In the running text (since postext 1.25) they share the text column, a body line apart, and the blocks keep the text's own typography; with `span="page"`, on a page of several columns, the group cuts the page into a band as a page-span box does: the columns above it close level, the group is set across the content width (the gutter apart) and the text goes on in every column under it. On a one-column page `span="page"` sets it in the column. Headings inside a group keep their style, number and entry in the contents, a footnote cited in it goes to the foot of the text column, and figures it cites float as usual.

| Attribute | Effect |
| --- | --- |
| `count` | How many columns, 2 to 6. Default 2. |
| `gap` | The space between the columns, a length (`12pt`, `1em`, `4mm`). Default: the box style's `columnGap` in a box, a body line in the text column, `layout.gutterWidth` across the page. |
| `rule` | Draw a rule down each gap, in the colour and width of `layout.columnRule`: `:::columns{count=3 rule}`. |
| `breaks` | The blocks that open each column after the first, instead of balancing: `breaks="4"` opens the second column at the group's fourth block (a comma list for more columns). See below how it counts. |
| `flow` | How a group that does not fit goes on: `snake` (the default without `breaks`) or `parallel` (the default with `breaks`). See [Splitting a group](https://postext.dev/en/docs/document-format-directives.md#splitting-a-group). |
| `span` | In the running text only: `column` (the default) or `page`. |
| `marginTop` | The space above the group, a length as `gap` takes. It merges with the space pending above the group; none at the head of a column, or when the group opens its box. Since postext 1.28. |
| `marginBottom` | The space under the group, a length; `0` asks for none. In the running text it takes the place of the body's paragraph spacing; in a box it is the space before the next block. Since postext 1.28. |

A group set whole is cut where its columns level best — between blocks, or between the lines of a paragraph or list item, whose tail goes on at the head of the next column without its bullet — unless `breaks` fixes the column starts, with no cut inside a paragraph: a text column beside a figure column.

**The space around a group.** In the running text a group is followed by the body's paragraph spacing (a line with `bodyText.paragraphSpacing`, none without it), and inside a box by no space of its own. `marginTop` and `marginBottom` on the fence set it: `:::columns{count=3 span="page" marginBottom="0.75em"}`. Each is a minimum that merges with the space the block beside it keeps for itself, as a box's margins do. In the running text the flow returns to the baseline grid under the group, so the space comes out in whole lines, and a group divided between columns or pages keeps the top margin for its first part and the bottom one for its last. An `em` is the size of the text the group stands in; a value that is not a length, or a negative one, is ignored.

```md
:::callout{type="summary"}
:::columns{count=2}
- Every element is one kind of atom.
- Electrons live in orbitals.
- A bond shares or transfers electrons.
:::
:::
```

**How `breaks` counts.** `breaks` numbers the group's blocks in order — paragraphs, list items (one block each), display formulas, figures and tables — and a nested `:::callout` counts as one block however many it holds. Directives are not blocks: a `:::space` between two stanzas does not shift the count. A number below 2, past the group's last block, or not after the previous break is ignored. Inside a group `:::space` separates two blocks as anywhere else in a box, and it vanishes at the top of the group and at the head of each of its columns (a `breaks` position or a levelling cut) — to open the group lower, put the space before the `:::columns` fence. Two columns that carry the same spacing therefore line up stanza by stanza:

```md
:::callout{type="verse"}
:::columns{count=2 breaks="4"}
The lamp is lit at dusk,

and trimmed before the dawn.

:::space

The keeper sleeps by day.

La lámpara se enciende al anochecer,

y se despabila antes del alba.

:::space

El farero duerme de día.
:::
:::
```

Here the fourth block, "La lámpara…", opens the second column; the two `:::space` lines are not counted and leave the same gap in both columns.

#### Splitting a group

Since postext 1.25 a group that does not fit the room it has — the rest of its column in the running text, or the part of a box that splits (`keepTogether: false`, or a box taller than a column) — is cut between its columns and goes on in the next column or page, in a box of its own for a group in a box:

- **`flow="snake"`**, the default without `breaks`: the group's blocks run as one galley, like the text of a newspaper story. A part that goes on fills its columns in turn, as level as the cuts allow, cutting between blocks or between the lines of a paragraph or list item (at least `layout.boxChildSplitMinLines` lines of it on each side, two by default); the last part is balanced as a whole group is.
- **`flow="parallel"`**, the default with `breaks`: each run the breaks start is a stream that keeps its own column. A part fills every stream down to the room it has, and each one goes on in the same column of the next part, so a poem and its translation set side by side stay level stanza by stanza. A parallel group without `breaks` goes on as a snake group.

A nested box in a group stays whole, moving to the next part, and a group inside a nested box is never cut. A group that fits is set exactly as before. `layout.flowColumns: false` keeps the rules of postext 1.24: a fence outside a box is ignored and a group is never cut; books saved before 1.25 that hold a `:::columns` group are read that way. The Sandbox reports a `flow` it does not know (**Unknown column flow**) and columns narrower than six ems of their text (**Columns too narrow**).

```md
## Briefs

:::columns{count=3 span="page" rule}
**Harbour.** The new pier opens on Monday…

**Market.** Stall rents stay as they are…

**Weather.** Rain from the west by the evening…
:::
```

A `:::callout` fence also accepts `label="…"`: the text a style with a `label` tab prints on the box's top corner (`:::callout{type="box" label="BOX 1-1" title="The octet rule"}`).

A `:::callout` inside another one is a box of its own — a worksheet card holding answer boxes, say. It takes its own style (background, border, radius, padding, title, icon) at the full inner width of the outer box and stacks among its other blocks; its `span` and `placement` are ignored, since a nested box always flows inside its parent. Each fence closes the innermost box still open:

```md
:::callout{type="card"}
The statement of the exercise.

:::callout{type="answer"}
A white answer box with its own border and padding.
:::

:::callout{type="answer"}
A second answer box.
:::
:::
```

When the outer box splits across columns or pages (`keepTogether: false`, or taller than a column), a nested box moves whole to the next fragment unless its own style lets it split too; every fragment redraws the frames it holds, and a continued nested box drops its icon, and its title unless its style repeats it (`repeatTitle`).

### `:::paper`

A book can change paper stock for a run of pages: a section of plates on coated gloss paper in a book printed on uncoated wove, a card insert, a few leaves of tinted paper. Wrap that content in a `:::paper` container:

```md
:::paper{type=coatedGloss grammage=130}
## Plates
::resource{id="plate-1"}
::resource{id="plate-2"}
:::
```

A stock covers whole sheets, so the content inside the fences starts on a new page, and whatever follows the closing `:::` starts on a new page too. A run that ends the document leaves no blank page after it. Figures and tables cited inside the run are placed before it closes. Every page set with content from inside the container carries the stock in the layout (`VDTPage.paper`, the attributes as the fence writes them); pages outside it carry nothing. The Folio viewer reads it and draws those leaves with the paper's colour, surface, thickness and stiffness. The canvas, PDF and HTML outputs ignore it: the pages are set and printed like any other.

The attributes are those of the `folio.paper` settings, and all of them are optional. One the fence leaves out follows the document's paper, and past that the stock's defaults:

| Attribute | Value |
| --- | --- |
| `type` | The stock: `uncoated`, `bookWove`, `coatedMatte`, `coatedSilk`, `coatedGloss`, `bible`, `newsprint`, `cardStock`, `board`. It sets the defaults of the attributes below. |
| `grammage` | Weight in g/m², a number above 0. Heavier paper is thicker, stiffer and more opaque. |
| `bulk` | Thickness per weight in cm³/g, a number above 0 (caliper in µm = grammage × bulk). |
| `finish` | The surface: `auto`, `uncoated`, `matte`, `silk`, `gloss`. |
| `texture` | The relief of the surface: `auto`, `smooth`, `vellum`, `wove`, `laid`, `linen`, `felt`. |
| `textureStrength` | How strongly the texture shows, from 0 to 2. |
| `shade` | The colour of the paper: `#rgb`, `#rrggbb` or the id of a `colorPalette` entry. |
| `showThrough` | `true` or `false`: whether the reverse page shows faintly through. A bare `showThrough` means `true`. |

A `:::paper` inside another one overrides only the attributes it sets, and it also starts and ends on a page break. Inside a `:::callout` the fences are ignored. A value the engine cannot read is dropped, and the sandbox lists it as an **Invalid paper attribute** warning (`paperAttributeInvalid` in the document's `contentWarnings`).

### `:::pagebreak`

The directive itself does not force parity on its own — only the next block's layout. Use it to end a preface, force a dedication onto its own page, or mark the end of a section. When both a page break and a numbering reset are wanted at the same point, compose `:::pagebreak` followed by `:::numbering` — the numbering switch applies at the fresh page the `:::pagebreak` just created.

A page break on a page that is still empty does nothing, so it never adds a blank page. Nor does it replace the `breakBefore` of a heading right after it (level 1 has one by default): the heading still applies its parity, which can add a blank page after the one the directive opened. To start a heading exactly there, turn its break off (see **Configuration → Heading styles**). After a cover heading that fills its page the break is optional: the cover already claims the rest of its page, in single- and multi-column layouts alike, and a `:::pagebreak` right after it does no harm. It is needed only after a cover whose design stops short of the page foot, when the text should still start on the next page (see **Configuration → Reserved height**).

```md
The old chapter ends here.

:::pagebreak{parity="odd"}

# A new chapter
```

The flag `center` (`:::pagebreak{center}`, off with `center=false`) centres the text of the page the break opens between the head and the foot of the type area, across the page in vertical text: the ページの左右中央 of a Japanese part title or dedication. Floats, notes and running heads stay where they are, and a page already full is left alone. The flag does not end the page: close it with another `:::pagebreak`.

```md
:::pagebreak{center}

# 上　先生と私

:::pagebreak
```

#### Parity attribute

The `parity` attribute accepts the same five values as `headings.levels[*].breakBefore.parity`:

- `'any'` — the default: no parity constraint; the break simply opens a new page.
- `'odd'` / `'even'` — the new page opens on the requested side of the spread; a single blank is inserted only when the natural next page is on the wrong side.
- `'always-odd'` / `'always-even'` — guarantee at least one mandatory blank separator page between the previous content and the new page, then enforce parity. The separator blank belongs to the **previous** chapter; any further parity padding belongs to whatever follows.

#### Blank-page ownership

The two kinds of blank pages `:::pagebreak` (and `breakBefore`) can introduce are distinguished in the `VDTPage` model:

- `blankForParity: true` — inserted to satisfy a parity constraint. In `{chapterTitle}` headers this page carries the **upcoming** chapter's title, because the blank exists only to push that chapter onto the right parity.
- `blankForForce: true` — the mandatory leading separator of an `'always-*'` mode. It belongs to the **previous** chapter — a deliberate end-of-chapter breath, not parity padding for the next chapter.

The same two rules give a blank page the running heads and palette of a styled section — see [Configuration › Heading styles](https://postext.dev/en/docs/configuration-styles.md#heading-styles).

#### Document-start exception

When `:::pagebreak` is the very first construct in a document (or a heading with `breakBefore` would pull one in), parity enforcement is skipped while the first page is still empty. The next block lands on page 1 as written, regardless of the requested parity — no spurious leading blank.

### `:::numbering`

`:::numbering` is how you restart the page counter mid-document. The canonical book example:

```md
---
title: "A Book With Front Matter"
---

# Preface

…

:::pagebreak{parity="odd"}
:::numbering{format="decimal" startAt=1}

# Chapter 1
```

Preface pages are labelled `i`, `ii`, `iii`, …; the first chapter opens on a right-hand page labelled `1`.

Format-only changes (no `startAt`) keep the counter flowing — useful for, say, switching from `lower-alpha` to `upper-alpha` without resetting.

`format` takes any spelling of a numbering format — `roman-lower` and `i` work as well as `lower-roman`, `arabic` as well as `decimal`, `一` and `あ` as well as `japanese-informal` and `hiragana` (see [Configuration › Numbering format spellings](https://postext.dev/en/docs/configuration-page-layout.md#numbering-format-spellings)). A value that is none of them leaves the format as it was, and the sandbox flags it.

`lines` restarts the count of [line numbers](https://postext.dev/en/docs/configuration-notes-references.md#line-numbers), not the page counter: the next line that is counted takes the number given, whatever `lineNumbers.restart` says. A value that is not a whole number of 0 or more is ignored.

```md
## Act II

:::numbering{lines=1}
```

### `:::space`

`:::space` leaves vertical space between two blocks: to separate a closing line from the text above it, to push an epigraph or a signature down a little, or to open a *space break* between two runs of text. Extra blank lines in the Markdown do not do this — as in any Markdown, a run of blank lines is just one paragraph separator, which keeps a document from changing layout when an editor or formatter adds or trims whitespace.

```md
The last paragraph of the scene.

:::space

A new scene begins one line lower.

:::space{lines=2}

Two lines lower still.
```

- **`lines`** — how much space, in body lines (the baseline grid). Default `1`. Whole numbers keep every line of text on the grid, so the columns still line up across the page; a fraction (`lines=0.5`) is honoured exactly, at the cost of that alignment until the next block that snaps to the grid. A value that is not a number greater than 0 and at most 20 falls back to one line, and the sandbox flags it (**Invalid space size**).
- **It adds up.** The space is added to the margin that already separates the two blocks — a heading's top margin, a list's bottom margin — instead of collapsing into it. Two `:::space` lines in a row add two lines.
- **It is dropped at a break**, like LaTeX's `\vspace`: at the top of a column or page it vanishes, so a page never opens with a hole; and when it does not fit at the foot of a column it simply ends that column, without carrying the rest over.
- **The paragraph after it is set flush.** When `bodyText.indentAfterHeading` is off, a paragraph right after `:::space` loses its first-line indent, as it does after a heading — the usual convention for text resuming after a blank line.
- **Inside a callout** (or a `:::columns` group) it separates the box's children the same way, measured in the box's own body lines. Before the box's first block it is dropped, like at the top of a column — the padding already sets the content off the frame — except in two cases where it opens that much room: right under the box's title, and in a box that holds nothing else (an answer box, a space to write in, sized in lines). It always vanishes at the top of a `:::columns` group, at the head of each of its columns, and at the top of the part of a split box that continues on the next column or page. Inside a `:::paragraphs` container it works as between body paragraphs.
- **Keep-with-next** counts it: a heading followed by `:::space` moves on when the space and the first lines of its text do not fit under it.

An answer box of a worksheet is a box whose only content is space: the question in its title, four lines of room below it.

```md
:::callout{type="answer" title="1. Name the three parts of the lantern."}
:::space{lines=4}
:::
```

For a fixed break rather than space, use `:::columnbreak` or `:::pagebreak`.

### `:::verse`

A poem. `:::verse` sets it in one of two layouts: **line by line**, as most poems are printed, or the **classical Arabic layout** of a qaṣīda, each bayt in two hemistichs side by side. A poem whose lines carry a hemistich separator (`||`, or a spaced `\\`) takes the Arabic layout and any other the line layout; `layout=lines` or `layout=bayt` on the fence names one.

#### Line by line

Write the poem as it is printed: one line of verse a line of Markdown, a blank line between stanzas, and spaces before a line to indent it.

```md
:::verse
Whose woods these are I think I know.
His house is in the village though;
  He will not see me stopping here
  To watch his woods fill up with snow.

My little horse must think it queer
To stop without a farmhouse near
:::
```

- **Lines.** Every non-blank line is a line of verse, read as inline Markdown on its own: italics, small capitals, notes and references all work. A run of blank lines is one stanza break.
- **Indents.** Each leading space is `indentStep` wide, 0.5 em by default, so two spaces indent a line one em; a tab counts four spaces and an ideographic space (U+3000) two.
- **Turnovers.** A line a little wider than the measure first tightens its word spaces, down to `bodyText.minWordSpacing` of their natural width (the limit justified text shrinks to), and stays on one line; `tighten=false` on the fence, or `bodyText.verse.tighten: false`, turns it over instead. A line still wider turns over at a word space. With `turnover=hang` (the default) the rest hangs on the next line, `hang` in from the line's own start: the `hangingIndent` of the poem's paragraph style, else 2 em (`bodyText.verse.hang`). With `turnover=right` it is set flush with the end of the measure behind an opening bracket (`turnoverMark`, `[` by default), the custom of English and Spanish editions. Verse is not hyphenated unless its paragraph style sets `hyphenation: true` itself. A line and its turnover never part at a column or page break.
- **Stanzas.** The space between two stanzas is one line of the poem's leading; `stanzaSpace=0.5` makes it half a line, and a length (`stanzaSpace=6pt`) sets it exactly. On the baseline grid it comes out whole grid lines. Columns and pages break between stanzas first; inside a stanza they break by the orphan and widow rules, which then count the stanza's lines. `keepStanzas=N` keeps any stanza of N lines or fewer whole: a haiku takes `keepStanzas=3`, a tanka `keepStanzas=5`.
- **Placement.** The poem is centred in the measure on its longest line, every line flush with the poem's start (`align=center`, the usual setting for a poem quoted in prose); `align=start` sets it flush with the start of the measure, the default in vertical text. The paragraph that introduces the poem keeps its last line with the first lines of verse.
- **Stepped lines.** A line written `+ …` starts where the line above ended, a word space on, as a line of dramatic verse shared between two speakers. Write `\+` for a line that opens with a plus sign.
- **Caesuras.** With `keepSpaces` on the fence, a run of two or more spaces inside a line keeps its width; without it, spaces collapse as in any paragraph.
- **Type and direction.** `style` names a paragraph style, which gives the face, size, leading, `indent`, and the space above and below the poem. `dir` and `lang` set its direction and language: a Latin poem in an Arabic book (`dir=ltr`) is indented from its own start side. In vertical text each line of verse is a column, indented from the head.

| Attribute | Default | Description |
| --- | --- | --- |
| `layout` | `auto` | `lines`, `bayt`, or `auto`: the bayt layout when a line carries a separator. |
| `indentStep` | `0.5em` | Width of one leading space. |
| `turnover` | `hang` | `hang` or `right`. |
| `hang` | the style's `hangingIndent`, else `2em` | Indent of a hanging turnover from its line's start. |
| `turnoverMark` | `[` | The mark before a turnover set flush right. |
| `stanzaSpace` | `1` | Space between stanzas: a bare number counts lines of the poem's leading, a length is that length. |
| `keepStanzas` | `0` | Keep stanzas of this many lines or fewer whole; 0 is off. |
| `tighten` | `true` | Tighten the word spaces of a line a little too wide, down to `bodyText.minWordSpacing`, before turning it over. |
| `keepSpaces` | off | Keep runs of two or more spaces inside a line. |
| `align` | `center` (`start` in vertical text) | Centre the poem on its longest line, or set it flush with the start. |
| `style`, `dir`, `lang` | — | Paragraph style, direction and language of the poem. |
| `numbered` | `true` | `false` leaves the poem out of the line numbers: its lines are not counted. |
| `lineStart` | — | The line number of the poem's first line. The count starts again there, whatever `lineNumbers.restart` says. |
| `interval` | `lineNumbers.interval` | The poem's own interval: print the number of every Nth line. |

`bodyText.verse` sets the defaults for every poem (see [Configuration › Verse](https://postext.dev/en/docs/configuration-text.md#verse)). The plain text keeps the poem as written, a line feed between lines and a blank line between stanzas, so a copied passage and a search read it line by line; the reflowable EPUB sets a stanza an element whose lines hang their turnovers, and the tagged PDF tags a stanza a paragraph.

**Line numbers.** With `lineNumbers` on, the lines of a poem are counted (see [Configuration › Line numbers](https://postext.dev/en/docs/configuration-notes-references.md#line-numbers)). Each line of verse counts once: a turnover takes no number, and the space between stanzas is not counted. By default every fifth line prints its number in the outer margin and the count starts again at each poem. A poem in the classical Arabic layout counts one line per bayt. The fence adjusts one poem: `lineStart=N` gives its first line a number, `interval=N` its own interval, and `numbered=false` leaves it out.

```md
:::verse{lineStart=37}
…
:::
```

With the default interval of 5, this poem prints 40, 45 and so on beside its lines.

#### Classical Arabic layout

A poem in the classical Arabic layout (a qaṣīda, a qiṭʿa): each verse, the *bayt*, on one line in two halves, the *ṣadr* on the start side (the right in Arabic) and the *ʿajuz* on the end side, with a gap between them. Write one bayt a line, its hemistichs separated by `||` (a `\\` with a space on each side, as in Wikisource texts, works too). A line without a separator is a single hemistich, centred on the poem.

```md
فأنشد يقول:

:::verse
يَا حُرْقَةَ الدَّهْرِ كُفِّي || إِنْ لَمْ تَكُفِّي فَعِفِّي
فَلَا بِحَظِّيَ أُعْطِي || وَلَا بِصَنْعَةِ كَفِّي
:::
```

- **One width.** Every hemistich of the poem is set to one width, so each ṣadr starts on the same vertical and each ʿajuz ends on another, and the rhyme letters line up down the poem. The width is that of the widest hemistich, at most half the measure less the gap; `width` sets it (`width=55mm`). Each hemistich is brought to it with kashidas first (verse elongates more than prose: twice `bodyText.kashidaMaxLength`), then its word spaces; a hemistich of one word that cannot fill it leaves the rest in the gap.
- **The gap** is 2 em by default; `gap` sets it (`gap=3em`, a bare number is in ems). `ornament` prints a mark in its middle (`ornament="٭"`), which is not part of the text.
- **Too wide.** A hemistich wider than the common width first tightens its word spaces to `bodyText.minWordSpacing`. If it still does not fit, its bayt is set staggered: the ṣadr flush with the start side on its own line, the ʿajuz flush with the end side on the next.
- **Placement.** The poem is centred in the column; `align=start` sets it flush with the start side. A bayt is never split between columns or pages, and the poem follows the orphan and widow rules of paragraphs (a poem of three bayts or fewer stays whole). The paragraph before the poem, which introduces it («فأنشد يقول:»), keeps its last line with the first bayts.
- **Type.** The poem takes the body text's face, size and leading; `style` names a paragraph style for it (`style="verse"`), which is how a vocalised poem gets the extra leading its harakat need. `dir=ltr` or `dir=rtl` sets its direction like any block; a poem in Latin script in a left-to-right book has its ṣadr on the left.

The plain text of the poem keeps the hemistichs and bayts apart (a tab and a line break), so a search or a copied passage reads it as written; the kashidas and the ornament are left out.

### `:::toc`

`:::toc` prints the table of contents where it stands. It expands into ordinary blocks — one per heading of the levels `toc.levels` lists (level 1 by default) and one per `:::part` — so the contents flow through columns and pages like any other text and a click on an entry lands on the directive line. An entry shows the heading's number (its `numberingTemplate` output, else the chapter ordinal), its title, a dotted leader and the label of the page it starts on, and, when `toc.subtitle` is enabled, a second line with a heading attribute such as the chapter's `{author="…"}`. A part gets a row of its own, designed by `toc.parts.design` and coloured with the part's own `palette`. Headings whose style has `numbered: false` are listed without a number; `{toc="false"}` on a heading keeps it out (the contents' own heading, typically).

```md
# Contents {style="front-matter" toc="false"}

:::toc
```

Two attributes change what one contents prints, whatever the configuration says. `levels` lists the heading levels it names: a range (`levels="1-2"`), one level (`levels="2"`) or a list (`levels="1,3"`); a level `toc.levels` gives no style takes the style of the nearest level above it. `keep` keeps each block of the contents on one column and page, as [`toc.groups.keepTogether`](https://postext.dev/en/docs/configuration-notes-references.md#table-of-contents) does: `keep="part"` keeps a part row with its chapters, `keep="1"` (to `"6"`) a heading of that level with the entries under it, and `keep="none"` turns the configured keep off. A block that does not fit moves whole to the next column or page; one taller than a column is cut, and the column it goes on in opens with its head row again, followed by a continuation mark such as *(cont.)*.

```md
# Contents {style="front-matter" toc="false"}

:::toc{keep="part" levels="1-2"}
```

The page numbers are the ones the document actually prints. A document laid out on its own is laid out again with the labels of the previous pass until they no longer move — with the numbering restarting after the front matter (the `:::numbering` recipe above) one extra pass settles it. A chapter laid out on its own (the sandbox previews) receives the whole book's outline from its host instead. See [Table of contents](https://postext.dev/en/docs/configuration-notes-references.md#table-of-contents) in the configuration reference.

### `:::index`

`:::index` prints the back-of-book index where it stands: the terms marked with `:index[…]` or `:index{term="…"}` across the book, with their pages, which follow the text as it moves. It is described with the marks in [Back-of-book index](https://postext.dev/en/docs/document-format-notes-references.md#back-of-book-index). A column never ends after the first entry of a group, nor before its last one: two entries of the group stay and two go on, or the group moves whole (`index.groups.splitMinEntries`).

```md
# Index {style="index"}

:::index
```

### Line breaks

The lines of a paragraph join with a space. To end a line inside a paragraph without starting a new one (an address, the greeting of a letter, a dedication), end the source line with a backslash, CommonMark's hard break, or write `\\` followed by a space:

```md
To the keeper of the lighthouse,\
at the end of the northern pier.

Ana Ruiz \\ Calle Mayor 4 \\ 28013 Madrid
```

- The line before a break is set at its natural width, as the last line of a paragraph is, never stretched to the measure. The text after it opens a new line of the same paragraph, with no first-line indent and no space above; under a hanging indent it hangs like any line after the first.
- Paragraphs, quotations (`> First line\` over `> second line`), footnotes and list items take it. A list item is one line of source, so it breaks at `\\`.
- A backslash that ends the paragraph prints, as in CommonMark, and two breaks in a row make one: for an empty line, start a new paragraph or add a [`:::space`](https://postext.dev/en/docs/document-format-directives.md#space).
- A `\\` glued to the next character is no break: `\\*` prints a backslash and an escaped asterisk, `C:\\Temp` both backslashes. In inline code and in a formula the backslashes belong to the code and to the formula.
- Two spaces at the end of a line, CommonMark's other hard break, are not one: they cannot be seen in an editor, and many editors leave them behind, so they would break lines nobody meant to break.
- Text copied from the HTML viewer has a line feed at the break, the reflowable EPUB a `<br/>`, the text of the PDF a line end, and a Word export a manual line break (Shift+Enter), which the Word import reads back as a break.
- A poem keeps its lines, indents and stanzas in a [`:::verse`](https://postext.dev/en/docs/document-format-directives.md#verse) block, with no backslash on every line.

Up to postext 1.22 the backslash printed and the lines joined with a space. A book stored then whose text ends a line with a backslash, or sets `\\` before a space, keeps that reading (`bodyText.hardLineBreaks: false`, see [Configuration › Bundles written by postext 1.4 or earlier](https://postext.dev/en/docs/configuration-bundles.md#bundles-written-by-postext-14-or-earlier)).

### Line breaks in titles

Write `\\` inside a heading (or inside a part's `title` attribute) to force a line break where the title is displayed as a title: the in-column heading keeps flowing and shows a space there, while an opener design's `{titleText}` breaks the line at that point (in every `overflow` mode of the text element). Running heads, `{chapterTitle}`, `{partTitle}` and the PDF outline always render the title on one line. In Chinese or Japanese the break reads as an ideographic space between two characters of the script (a couplet title); where one of them meets a digit or Latin text (`关于举办 \\ 2026年…`) the page sets the Han–Latin space, and the PDF bookmarks and document title join the two halves with nothing, as plain Chinese text is written.

```md
# Concepts of health and illness. \\ Community health {author="I. Zango Martín"}
```

## Comics

Comic pages, strips and spreads are written in two fenced blocks whose bodies the engine reads itself, line by line: `:::page` and `:::strip`. Inside them, `::panel` lines start the panels and script lines letter them. The guide, with the layout rules, the lettering and the outputs, is [Comics](https://postext.dev/en/docs/comics.md); the settings are in [Configuration › Comics](https://postext.dev/en/docs/configuration-comics.md#comics).

### `:::page`

```md
:::page{split="30 [30 | 20 | *] / *" gutter=4mm}
::panel{art=lh-arrive}
caption: Every summer, Maya spent a week at the lighthouse.
maya: Grandpa! I'm here!
::panel{art=lh-radio focus="40% 50%"}
tomas: Just in time.
::panel{art=lh-maya}
maya{thought}: That valve looks loose…
::panel{art=lh-beam bleed}
sfx{rotate=-8}: KRAK
:::
```

A `:::page` block is one comic page: it opens a fresh page, takes all of it, and the text after its closing `:::` starts on the next page. Its attributes are `split` (how the page is cut into cells: sizes in percent separated by `/` for tiers and `|` for panels side by side, a bracketed list to cut a cell again, `*` for the rest, `a~b` for a slanted line), `gutter` (one length, or two: between tiers and between panels; a bare number is in millimetres), `style` (a named panel style), `bleed`, `direction` (`ltr` or `rtl`, also written `dir`) and `spread` (see [Spreads](https://postext.dev/en/docs/document-format-directives.md#spreads)). Without `split` the panels are stacked in equal tiers. Markdown blocks, containers and directives are not read inside the block; `<!-- comments -->` are.

### Panels

A line `::panel{…}` starts a panel, which fills the next cell in reading order and runs to the next `::panel` line or the closing fence:

| Attribute | Effect |
| --- | --- |
| `art=<id>` | The picture: a bitmap or SVG resource. Without it the panel is empty. |
| `fit=cover`, `fit=contain` | Crop the picture to fill the cell (never into its safe area), or show it whole. |
| `focus="x% y%"` | The point to keep centred where the safe area leaves room. |
| `style=…`, `border=none`, `border=0.5mm`, `bg=#hex` | A named panel style, the border, the background (a colour, a palette id or `none`). |
| `bleed`, `bleed="top start"`, `bleed=false` | Run the sides that touch the frame out to the trim and the bleed. |
| `pad="…"` | Make the panel smaller than its cell: one to four lengths or percentages (top, end, bottom, start). |
| `inset="x y w h"` | Lay the panel over the previous one, at that box in percentages of it, instead of giving it a cell. |
| `pop=<id>` | A transparent cut-out drawn over the border with the art's crop (a broken border). |
| `mirror`, `mirror=false` | Flip the picture, or keep it as drawn on a mirrored page. |
| `alt="…"`, `id=…` | The text alternative (else the resource's `altText`) and an anchor id. |

### Script lines

Each line of a panel is one balloon, caption or sound effect, written `key{attributes}: text`:

```md
maya: Grandpa! I'm here!
tomas{whisper}: Shh. Listen.
caption{at=bottom-end}: Three streets away.
sfx{at="62% 40%" rotate=-8 size=1.4}: KRAK
ben{tail=start}: (from off the panel) Over here!
sfx{vertical size=2.6 font="Dela Gothic One"}: ドン
maya: This line goes on
  on the next line,\
  and breaks here.
```

- The **key** is a speaker id (letters, digits, `_`, `.`, `-`), the same in every translation; `caption`, `sfx` and `note` are reserved. The colon may be the full-width `：`.
- A bare word in the braces is a **balloon style** (`thought`, `whisper`, `shout`, `radio`, `inner` or one of `comics.balloonStyles`); `style=` says the same.
- `at` pins the balloon: a point in percentages of the panel's picture (`at="62% 40%"`), or a corner or edge (`top-start`, `top-end`, `bottom-start`, `bottom-end`, `top`, `bottom`). `to` points the tail at a point of the picture; `tail=none` drops it and `tail=top|bottom|start|end|left|right` points it off the panel. `join` and `join=false` join the balloon to the previous one of the same speaker or keep it apart; `break` lets it cross the border, and the crossing is not reported as an overflow. `rotate` (degrees), `size` (a scale, for sound effects), `color` and `font` change its lettering.
- `vertical` and `horizontal` (or `mode=vertical`, `mode=horizontal`) set the line's writing mode over the book's: an untranslated `ドン` set in a column in a horizontal edition, a sign written across set in a row in a vertical one. A column in a book of another language follows the rules of its own text (with kana, those of Japanese). In a vertical book a line with no Chinese or Japanese characters is set in a row anyway.
- A line indented by two spaces or a tab continues the balloon above; a backslash at the end of a line breaks the text there. Blank lines are ignored.
- The text is inline Markdown: emphasis (lettered bold italic), `:tcy`, `:ruby` (its reading set over the base, except over a right-to-left base), `:ltr` and `:rtl` (a run kept in its own direction). Footnotes and `:ref` marks are not read.

### `:::strip`

```md
:::strip{split="* | * | *" aspect=3 span=page placement=top}
::panel{art=pip-1}
pip: Morning, Otto!
::panel{art=pip-2}
::panel{art=pip-3}
otto: Is it?
:::
```

A `:::strip` has the body of a page but sits in the text as one unbreakable box, cut into panels: `span` (`column`, the default, or `page`), `placement` (`here`, the default, where it is written; or `top`, `bottom`, `auto`, floated like a figure), and its size, either `height` (a length, a bare number in millimetres) or `aspect` (width over height: `3`, `4/1`, `4:1`; by default the proportions that make its panels square). A page-wide strip set `here` on a page of several columns cuts the columns where it stands, as a page-wide box does. `width` makes it narrower than the measure it spans (`60%` of it, or a length) and `align` sets it at the `start`, `center` (the default) or `end` of that measure, along the text direction. `caption="…"` sets a caption under it in the caption style; with `type=figure` (a resource type) the caption takes the type's label and number and the strip counts in that type's sequence, and with `id=…` a `:ref` names it. Without `split` the panels sit side by side. Strips are read at the top level of a chapter only.

### Spreads

`:::page{spread}` lays one page across two facing pages: the split covers both text areas joined at the spine, without their inner margins, and a panel may cross the spine. The spread opens on an even page, after a blank page when needed. See [Comics › Spreads](https://postext.dev/en/docs/comics.md#spreads).

## Composed pages

A composed page is laid out from a page template of the configuration (`pageTemplates`), its content poured into the template's frames by name. The guide, with the warnings, is [Composed pages](https://postext.dev/en/docs/composed-pages.md).

- `::::page{template="…"}` … `::::` is the page: four or more colons, closed by a bare fence of as many. Three-colon fences inside it (`:::frame`, `:::callout`, `:::figure`…) work as they do everywhere, and a bare `:::` never closes the page. A three-colon `:::page` stays a comic page.
- `:::frame{slot="…" label="…"}` … `:::` holds the content of the frame of that name: any Markdown.
- `slot="…"` on a heading (`## Retos {slot="retos-titulo"}`), on `::resource{id="…" slot="…"}`, on a code fence or on a `:::` container sends that block alone. Content with no slot goes to the template's flow frame.
- `:::figure{resource="…" slot="…"}` … `:::` places one resource with its `::label[TEXT]{at="…" style="…"}` lines, `at` being an anchor of the picture or a point `"x% y%"`. A figure works in the running text too.
