The book pipeline
Keel’s preview is not a “reading mode” — it is the book, typeset for
real. Press F5 (or run keel render) and roughly a second later a
B-format trade paperback exists as a PDF: front matter, running heads, folios, justified
and hyphenated EB Garamond on an exact line grid. This chapter explains how a folder
of one-sentence-per-line leaves becomes that object.
Derived, not guessed
Words-per-page is not a configured estimate. Keel derives the page from
volume.toml — trim, margins, face, size, leading — so a chapter that reads
as fourteen pages is fourteen printed pages:
| trim | B-format, 129 × 198 mm (UK trade paperback) |
| margins | 18 inner · 14 outer · 16 top · 18 bottom (mm) — asymmetric so the gutter doesn’t swallow text |
| text block | 97 × 164 mm |
| measure | 97 mm → 274.96 pt ÷ (0.422 em × 10.5 pt) ≈ 62 characters per line |
| lines / page | 164 mm → 464.88 pt ÷ 13.6 pt leading = 34 lines |
| words / page | 62 × 34 ÷ 6 chars-per-word × 0.85 fill ≈ 300 effective — 150,000 words → ~500 pages |
One honest asterisk: the 0.422 em average advance is a calibrated constant, not something read from font tables. It is pinned by rendering: 62 characters of prose must fit the measure, and the true capacity flip (67 fits, 68 doesn’t, for the canonical sample) is asserted so a font or Typst update that moves it fails a test instead of silently reflowing your book.
The line grid itself is exact by construction. Typst’s default line box is cap-height to baseline, which makes leading font-dependent; the template pins the text box edges to exactly 1 em and 0, so every line advances by precisely 1 em + leading = 13.6 pt — the baseline grid, independent of any font’s metrics, verified at 34 lines on a filled page.
What your markup becomes
The mapping targets semantic functions the template defines, so rendering decisions live in the template, not the emitter. One-sentence-per-line maps naturally: Typst joins single newlines into a paragraph and breaks on blank lines — exactly the source’s convention.
| *em* · **strong** · ~~struck~~ | italic · bold · strikethrough |
| @sc @u @sup @sub | small caps · underline · super/subscript |
| @think | italic — semantically distinct from emphasis |
| @note | a real printed footnote |
| @redact | solid black bars |
| @lang fr | correct hyphenation and language metadata for the span |
| @quote · @epigraph | inset blocks; credit="…" becomes a right-aligned attribution |
| @verse · @song | line breaks preserved, inset (song in italic) |
| @letter @journal @email @chat @transcript @terminal … | inset documents; terminal in monospace |
| @break | the scene break — centred asterisks |
| @ref @fact | render as nothing but their text — they exist for the index and the Ledger |
| @cut | vanishes entirely — author-only material never reaches the page |
The book’s furniture
Structure is emitted from the spine, never typed, and the template does the book-setting a compositor would:
- Front matter — half-title (recto), blank, title page, copyright page with a dynamic year, generated table of contents from the frames, then the body opening on a recto.
- Running heads — author on the verso, title on the recto, suppressed on part and chapter openers and front matter.
- Folios — at the outer edge, old-style figures, suppressed on openers.
- Part pages land recto, with the blank inserted automatically; chapter openers are sunk — the drop from the head is a template constant (28 mm), not something set per chapter.
- Gaps are honest — a chapter whose beats have no prose yet renders as its opener plus a stated page estimate from the word budgets, so the book’s true shape stays visible.
The live loop
Renders read the canon head revisions and land at
.keel\render\book.pdf, the same file every time — use a viewer that reloads
on change (SumatraPDF on Windows does; Acrobat will fight you) and the loop is genuinely
live: F5, glance at the page, keep writing. Unproofread leaves are named (✂) after
every render, so nothing ships unread by accident.