docs/<id>/assets/, import it, and reference the imported value. The import resolves to a URL the renderer knows how to fetch in the preview and read during export.
Images
- Always give
widthandheight(CSS px). The engine sizes the box from them; an unsized image is a layout surprise. - Doc-local images live in
docs/<id>/assets/. Assets shared across docs live in the project rootassets/and import via@assets/.... - PNG, JPEG, WebP, and GIF decode.
data:URIs also work, fine for tiny marks, wasteful for anything else. - Inline
<svg>elements render as crisp vector paths. Prefer them for rules, checkmarks, and simple charts. - Keep source images reasonably sized. A logo does not need 2000px, and image bytes embed into every rendered PDF.
Fonts
The default (nofonts entry) is the engine’s bundled Geist: full Latin coverage, weights honored, embedded and subset automatically. It stays the right choice unless you have a specific font or brand files.
To use a custom font, register it on pageOptions.fonts and reference it by the family name inside the font file:
fonts can be:
- an asset-import URL (
.woff2,.ttf,.otfunder the doc’s assets), - an absolute
https:URL, - a
{ name?, data, weight?, style? }byte descriptor.
A registered font takes priority over the bundled default for unstyled text. Register only faces you want in the document. If some text must stay on the default face while a custom face is registered, there is no way to name the default, so plan the registration around that.
Glyph coverage
Glyph coverage is a hard constraint: a character no registered font covers fails the render with a missing-glyph error. This is by design, an error beats silent tofu. For emoji, CJK, Arabic, or other scripts, register a font that covers them. Otherwise keep to Latin text and ordinary symbols. Use font files you have rights to rather than hotlinking. For a Google font, download the.woff2 into the doc’s assets.
Anti-patterns
fontFamilynaming a font that was never registered. It silently falls back.- Registering fonts “just in case”. They displace the default for all unstyled text.
<img>withoutwidthandheight.- Multi-megapixel images for a letterhead logo.
- Emoji or non-Latin glyphs without a covering registered font. The render fails, by design.
- Stock-photo filler where type and layout would carry the page.