Skip to content

fix(producer): skip @font-face injection for OS system fonts#311

Closed
Pran-Ker wants to merge 1 commit intoheygen-com:mainfrom
Pran-Ker:fix/system-font-detection
Closed

fix(producer): skip @font-face injection for OS system fonts#311
Pran-Ker wants to merge 1 commit intoheygen-com:mainfrom
Pran-Ker:fix/system-font-detection

Conversation

@Pran-Ker
Copy link
Copy Markdown

Problem

GENERIC_FAMILIES only covers CSS generic keywords (sans-serif, serif, monospace, etc.) but not named OS system fonts. When a composition uses a font-family stack like:

font-family: 'Courier New', Courier, monospace;

The compiler extracts Courier New and Courier as unresolved web fonts and attempts Google Fonts resolution for them. In headless render environments (the primary use case for hyperframes render) this produces [non-blocking] Failed to load resource: 404 for every system font in every stack — one per font name per composition.

The noise appears in the render output like this:

[Compiler] Injected deterministic @font-face rules for 2 requested font families
[non-blocking] Failed to load resource: the server responded with a status of 404 (Not Found)
[non-blocking] Failed to load resource: the server responded with a status of 404 (Not Found)

Even when the fallback to the OS font works correctly, this is misleading and wastes resolution time. For fonts without an alias (e.g. Arial, Tahoma, Georgia, Helvetica Neue) the compiler hits Google Fonts — which always fails in a sandboxed headless renderer — before falling back.

Fix

Add a SYSTEM_FONTS constant covering ~120 well-known pre-installed fonts across Windows, macOS, and Linux. Extend the skip guard in extractRequestedFontFamilies() to bail on these alongside the existing GENERIC_FAMILIES check.

if (!normalized || GENERIC_FAMILIES.has(normalized) || SYSTEM_FONTS.has(normalized)) {
  continue;
}

System fonts are already present on the render machine — injecting @font-face for them is unnecessary and actively harmful in headless environments.

Fonts covered

  • Windows: Arial, Calibri, Cambria, Comic Sans MS, Consolas, Courier New, Georgia, Impact, Palatino Linotype, Segoe UI, Tahoma, Times New Roman, Trebuchet MS, Verdana, and ~30 more
  • macOS: Helvetica, Helvetica Neue, SF Pro, SF Mono, Menlo, Monaco, Optima, Futura, Gill Sans, Baskerville, and ~20 more
  • Linux: DejaVu, Liberation, Ubuntu, Cantarell, Droid, Noto families

Testing

Reproduce before this fix by creating a composition with font-family: 'Courier New', Courier, monospace and running npx hyperframes render. The 404 noise disappears after this change.

The GENERIC_FAMILIES set only covers CSS generic keywords (sans-serif,
serif, monospace, etc.) but not named system fonts like Courier New,
Arial, Helvetica, or Georgia. When a composition uses a font-family
stack such as `'Courier New', Courier, monospace`, the compiler picks
up "Courier New" and "Courier" as unresolved web fonts and attempts
Google Fonts resolution. In headless render environments this produces
[non-blocking] 404 errors for every system font in every stack.

Add a SYSTEM_FONTS constant covering ~120 well-known pre-installed
fonts across Windows, macOS, and Linux. Extend the skip guard in
extractRequestedFontFamilies() to bail on these alongside the existing
generic-family check.

Fixes the spurious 404 noise reported when rendering compositions that
use common font stacks like Courier New, Tahoma, Verdana, Helvetica
Neue, etc.
jrusso1020 added a commit that referenced this pull request Apr 18, 2026
Chrome's "Failed to load resource" message text does not include the failing
URL — it's only on msg.location().url. The previous filter in frameCapture.ts
only checked msg.text(), so every font 404 (e.g. Google Fonts <link> tags
in sandboxed render environments) fell through to the "[non-blocking]"
prefix instead of being suppressed.

Extract the classifier into isFontResourceError() and match against both
text and location.url, and extend the extension match to .ttf/.otf. Adds
a unit test covering the URL-in-location, URL-in-text, and non-font cases.

This is a targeted fix for the render-output noise that PR #311 attempted
to address by adding a ~120-entry SYSTEM_FONTS skip list. That approach
silently shadowed existing FONT_ALIASES (arial→inter, helvetica→inter,
courier new→jetbrains-mono, segoe ui→roboto, etc.) and changed render
output on Linux fleets that don't have those fonts installed. Fixing the
console-log filter here suppresses the noise without changing any font
resolution behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jrusso1020
Copy link
Copy Markdown
Collaborator

@Pran-Ker Thanks for raising this PR and surfacing the issue! After a deeper look I put up a PR here #313 to help suppress the noisy log.

The concern with the approach you took is that it could change our font resolution logic leading to visual inconsistencies between preview and render, so we wanted to take a slightly safer route!

jrusso1020 added a commit that referenced this pull request Apr 18, 2026
…#313)

Chrome's "Failed to load resource" message text does not include the failing
URL — it's only on msg.location().url. The previous filter in frameCapture.ts
only checked msg.text(), so every font 404 (e.g. Google Fonts <link> tags
in sandboxed render environments) fell through to the "[non-blocking]"
prefix instead of being suppressed.

Extract the classifier into isFontResourceError() and match against both
text and location.url, and extend the extension match to .ttf/.otf. Adds
a unit test covering the URL-in-location, URL-in-text, and non-font cases.

This is a targeted fix for the render-output noise that PR #311 attempted
to address by adding a ~120-entry SYSTEM_FONTS skip list. That approach
silently shadowed existing FONT_ALIASES (arial→inter, helvetica→inter,
courier new→jetbrains-mono, segoe ui→roboto, etc.) and changed render
output on Linux fleets that don't have those fonts installed. Fixing the
console-log filter here suppresses the noise without changing any font
resolution behavior.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@jrusso1020 jrusso1020 closed this Apr 18, 2026
@Pran-Ker Pran-Ker deleted the fix/system-font-detection branch April 18, 2026 20:58
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