← All updates

Symbols always render — per-character font fallback

A stray check mark, bullet or arrow in your text no longer renders blank. Characters your chosen font lacks are drawn automatically from the embedded symbols font, at the same size and colour.

renderingfontsmarkdowndsl

Symbols now render in any font. If your document contains a character the chosen font has no glyph for — ☑ ☐ ✓ and friends at the top of the list — the renderer draws that character from the embedded NotoSansSymbols2 subset instead of leaving it blank. Size, colour and decoration all carry over, and the switch happens per character, mid-word if needed.

You do not change anything: font-family stays what it was, and the fallback only fires for characters the font actually lacks. ★ and •, for instance, are already in Inter, so they render from Inter exactly as before. A task list (- [x]) in Markdown and a list({ checked }) in a DSL template both benefit.

A few details worth knowing:

  • Grapheme clusters stay whole. Emoji ZWJ sequences, variation selectors, skin-tone modifiers and regional-indicator pairs are never split across fonts — a cluster goes to one font or none, never half and half.
  • What no font has is reported, not silent. A character no available font can draw still renders blank exactly as before, and the render now reports one glyph-missing layout warning naming the codepoints and a count — no document text. Emoji are the common case today; emoji font support is a follow-up.
  • Nothing changes for text that does not need it. Documents without fallback characters lay out byte-for-byte identically, and fallback fonts are loaded only when a document contains a character that can use them.

The mechanics — the chain, lazy loading through the isolate cache, and the coverage lookup — are documented in docs/font-fallback.md, and the fonts skill covers what to expect when there is no fallback yet.