Skip to main content
Fonts and images follow the same rule: put the file under 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 width and height (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 root assets/ 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 (no fonts 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:
Entries in fonts can be:
  • an asset-import URL (.woff2, .ttf, .otf under the doc’s assets),
  • an absolute https: URL,
  • a { name?, data, weight?, style? } byte descriptor.
The engine reads family name, weight, and style from the file when not given.
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

  • fontFamily naming a font that was never registered. It silently falls back.
  • Registering fonts “just in case”. They displace the default for all unstyled text.
  • <img> without width and height.
  • 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.