Skip to content

perf(producer): renders embed local fonts as-is instead of re-compressing them - #5865

Merged
miguel-heygen merged 2 commits into
mainfrom
hfcloud/render-raw-local-fonts
Oct 19, 2026
Merged

miguel-heygen merged 2 commits into
mainfrom
hfcloud/render-raw-local-fonts

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What

Renders now embed a project's local .ttf / .otf fonts into the compiled HTML as-is, instead of re-compressing them to woff2 first.

Why

woff2 compression is slow (seconds for a large font) and its cache lives on the local disk, so every fresh render machine pays it again for each local font. The compiled HTML is only a render-time artifact, so the smaller woff2 payload buys nothing there.

Related work

None.

How

  • fontToDataUri (core) gains a compress: false option that returns data:font/ttf / data:font/otf with the original bytes, skipping compression and the cache. Its default is unchanged, so every other caller still gets woff2.
  • The producer's local @font-face embed passes compress: false. woff2, ttc and the file-backed path for fonts over 5 MiB are untouched.
  • Cost: the compiled HTML grows by roughly the raw-minus-woff2 size of each local font.

Test plan

  • Unit tests added/updated: a core test (raw ttf/otf URIs, compressor never called, cache untouched) and a producer test (compiled HTML carries data:font/ttf / data:font/otf whose decoded bytes equal the files; the font cache dir stays empty). Both fail with the code change reverted.
  • Manual testing performed: rendered a fixture with a local TrueType .ttf and a CFF .otf (large text in each) to PNG frames with this branch and with main. Every frame is byte-identical (same sha256); a control render without the fonts differs, so the fonts are in effect. No visible change.
  • Cold-cache compile of that fixture: about 1.2 s on main, about 35 ms here (compiled HTML about 310 KB to 570 KB).
  • htmlCompiler.test.ts + htmlCompiler.fontEmbed.test.ts (148 pass), core src/fonts/ (261 pass), core and producer typecheck clean.
  • Documentation updated (if applicable): not applicable.
  • Comments follow CONTRIBUTING.md "Comments"

…sing them

Local ttf/otf fonts in a render were woff2-compressed on every cold font
cache, which costs seconds per font. The compiled HTML is a render-time
artifact, so embed them raw. fontToDataUri gains a compress: false
option; its default is unchanged.
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 271 (base branch 271), smooth 158 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (0)

Unstable (2)

  • seqheldtwice-tlhold-px-r0-root-z100: tracking 59.92, pressJump 0.11, drop 0.35, reload 0.35, render 0.02, renderKey -, undo true, teleport true / tracking 0.08, pressJump 0.11, drop 0.35, reload 0.35, render 0.02, renderKey -, undo true, teleport true / tracking 0.08, pressJump 0.11, drop 0.35, reload 0.35, render 0.02, renderKey -, undo true, teleport true
  • seqheldtwice-tlhold-px-r0-nested-z100: tracking 41.92, pressJump 0.11, drop 0.07, reload 0.07, render 0.02, renderKey -, undo true, teleport true / tracking 0.09, pressJump 0.11, drop 0.39, reload 0.39, render 0.02, renderKey -, undo true, teleport true / tracking 0.09, pressJump 0.11, drop 0.39, reload 0.39, render 0.02, renderKey -, undo true, teleport true

@vanceingalls vanceingalls left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed at d5e5abe8. All 8 required checks are green at this head, and the branch merges cleanly with main.

What's solid

  • The opt-out is narrow. fontToDataUri keeps woff2 as its default, and only the producer's local @font-face embed (htmlCompiler.ts:1846) passes compress: false. woff2 inputs, ttc, and the file-backed path for fonts over MAX_LOCAL_FONT_DATA_URI_BYTES are unchanged. That limit was already measured on the raw file, so no font crosses it differently now.
  • With compress: false the raw path skips both the compressor and the cache. The tests pin both, and the PR body shows the frames byte-identical to main.

Important (non-required checks red at this head)

  • Comments fails: fontCompression.ts 5.0% → 5.8% and htmlCompiler.ts +2 lines ("A file's comment share may only go down"). The check isn't in the required set, but the PR body ticks "Comments follow CONTRIBUTING.md". The new JSDoc on compress and the two-line "Raw, not woff2" comment are what trip it.
  • Studio: timeline viewport gate fails against base (interaction p95 66.7 vs 50.0 ms). I don't think it's this change: neither gate fixture (timeline-virtualization, studio-open) has an @font-face or a font file, and Studio doesn't go through the producer's embedLocalFontFaces. The gate ran only because the core change sets the studio path filter.

Nit

  • ext can be woff (/\.(woff2?|ttf|otf|ttc)$/). With compress: false it now goes straight to rawMimeType("woff") → font/ttf. Before, it reached the same label only after a failed woff2 compress, so this predates the PR. Chrome sniffs font data, so it still loads, but woff: "font/woff" in RAW_MIME_TYPES would label it correctly.

Verdict: APPROVE
Reasoning: The change is correct and its scope is narrow. Every required check is green. The red non-required Comments check and the unrelated Studio perf gate don't block it.

— Via

@vanceingalls vanceingalls left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-review at b1f4f296. I approved the previous head, d5e5abe8, earlier.

Delta since d5e5abe8: one commit (b1f4f296) stacked on top of the head I reviewed. It changes 3 files, +4/−7, and only does what it says:

  • fontCompression.ts:36: the option compress?: boolean is renamed compressToWoff2?: boolean and its doc comment is dropped. The guard at :98 now reads options.compressToWoff2 === false. Behaviour is unchanged: woff2 passes through, ttc and the opt-out stay raw, and everything else still compresses through the cache.
  • htmlCompiler.ts:1844: the call site moves to { compressToWoff2: false }, and its two-line comment is removed.
  • fontCompression.test.ts:144: the raw-embed test uses the new key.

No old compress: false/true caller is left anywhere under packages/, so the rename can't silently fall back to the default. It merges cleanly into current main.

CI at b1f4f296: all 8 required checks are green (Build, Render on windows-latest, Semantic PR title, Test, Test: runtime contract, Tests on windows-latest, Typecheck, regression). The Comments ratchet that was red at d5e5abe8 is green now, and so is Studio: timeline viewport gate.

Nit, non-blocking: the option key is now spelled the same as the exported compressToWoff2() function in the same module (:20). That's legal, since one is a property and the other a binding, but a grep for the function now also hits the option.

Verdict: APPROVE
Reasoning: The incremental diff is a mechanical rename plus comment removal with every call site updated, and CI is fully green at this exact head.

— Via

@miguel-heygen
miguel-heygen added this pull request to the merge queue Oct 19, 2026
Merged via the queue into main with commit 2b57809 Oct 19, 2026
90 of 92 checks passed
@miguel-heygen
miguel-heygen deleted the hfcloud/render-raw-local-fonts branch October 19, 2026 03:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants