fonts gate before composition scripts only covers faces that static markup already uses
Maintainers usually reply within 1 day
@user-github-me is already working on this.
Since Oct 8, 2026.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 48/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- html, typescript
- Domain
- frontend, performance
Research direction
Start by inspecting the composition-script font-readiness gate changed in #4980 and reproduce with the attached index.html, local font, and render --workers 1; compare script-time measurements with document.fonts.load() results. The issue outlines two possible approaches but does not choose between them, so the fix needs investigation and a decision. Done when script-built text measures with its intended font before composition scripts proceed, without breaking the existing timeout behavior.
Written by the indexing model from the issue text.
Description
Since 0.8.122 (#4980) composition scripts start only after web fonts are ready, which fixed measure-after-build layouts for fonts that static markup uses. The gate does not cover a face that only script-built text uses: it forces one layout, then awaits document.fonts.ready, and a face starts loading only when some text already in the DOM requests it. Text created by the composition script requests its face afterwards, so a getBoundingClientRect() taken at script time still sees the fallback font for that face. Which faces are loaded when a script runs therefore depends on what other scenes in the assembled page happen to show statically.
Repro (two files, attached): a local @font-face ("LocalFace", font-display: block, embedded by the compiler as a data URI) that no static text uses. The script sets a title in that face, measures it, centres it from the measurement, registers the timeline, then measures again inside document.fonts.load() and writes both numbers into the frame.
- v0.8.135,
render --workers 1:script-time width 1378.1 status unloaded/after fonts.load width 1056.5 status loaded. The title is centred from the first number, so it sits 161 px off centre in the final frame. - Control: uncomment the one static
<span>in the face and both widths are 1056.5 with statusloadedat script time.
Same mechanism with the compiler-fetched Google face: in a nine-scene project, a script-built block measured correctly only because an unrelated scene's static label happened to use the same weight; a second script-built block whose rows use a different weight measured 4 px short and was centred 2 px off. A handwritten title whose underline is drawn to the measured width rendered the underline 253 px too long and the title 114 px off centre in every render.
Two fixes look possible from the outside:
- Before releasing the scripts, call
load()on every declaredFontFace(Array.from(document.fonts).map((f) => f.load())) under the existing 5 s cap, so the stated guarantee holds for script-built text too. - A lint finding when a composition script calls
getBoundingClientRect/offsetWidth/offsetHeightoutside adocument.fonts.load()/document.fonts.readycallback, with the fix hint to measure inside it and register the timeline at the end (the documented async-build path).
Repro project (index.html, assets/fonts/local-face-700.woff2, package.json, hyperframes.json) and the rendered frame attached. Render log lines come from the page console as surfaced by the CLI.
Attachments: repro-bundle.zip (the four repro files)
- Dominant language
- TypeScript
- Stars
- 54.1k
- Forks
- 4.9k
- Avg merge
- 7h 19m
- Merged PRs (30d)
- 746
Getting set up
This project ships no dev container, Dockerfile or contributing guide, so setting up is up to you: start from its README, and see our first-contribution guide for the general steps.
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from heygen-com/hyperframes
-
Difficulty 1/5 Under an hour Newbie friendliness 84/100
heygen-com/hyperframes#5117 ·
Maintainers usually reply within 1 day
-
Docs: clarify that "Enable auto-update" is only available in the Claude Code terminal (CLI) /plugin UIPossibly taken @rumi7911 claimed this 1 day ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
heygen-com/hyperframes#5027 ·
Maintainers usually reply within 1 day
-
fix(producer): propagate useGpu to HDR layered streaming encoderPossibly taken @Monster-GM claimed this 3 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 87/100
heygen-com/hyperframes#5002 ·
Maintainers usually reply within 1 day
-
skills: remoteHeadSha() can open a Git Credential Manager dialog on Windows (GIT_TERMINAL_PROMPT does not cover GUI helpers; slug unvalidated)Possibly taken @RaphaelFakhri claimed this 8 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
heygen-com/hyperframes#4702 · 1 comment · 1 reaction ·
Maintainers usually reply within 1 day
-
Studio catalog prompt editor has no accessible namePossibly taken @lorenzozanee claimed this 14 days ago. Openbug difficulty/easy triage/ready
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
heygen-com/hyperframes#4384 ·
Maintainers usually reply within 1 day
All issues in heygen-com/hyperframes
Similar issues
-
[bug] diagnostics.dumpBody:Buffer 形态请求(透传 lane)跳过 dumps/ 落盘,仅留 raw/-unknown-Possibly taken @ranxianglei claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
ranxianglei/billion-context#2421 · 2 comments ·
Maintainers usually reply within 1 day
-
pending triage
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
nuxt/test-utils#1842 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
MoonshotAI/kimi-code#4146 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
farbenmeer/tapi#531 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 1 day