Repository navigation
Description
Problem
There is no way to hand the render's Chrome an extra launch flag. buildChromeArgs in packages/engine/src/services/browserManager.ts assembles the whole list, and nothing a project or a user sets (CLI flag, environment variable, hyperframes.json) reaches it. Only the binary can be swapped (HYPERFRAMES_BROWSER_PATH).
The case that needed one: on Windows, small text on an opaque layer renders with ClearType subpixel antialiasing, so every stem carries a blue edge on one side and a red-brown edge on the other. Video frames are scaled, composited and watched on other screens, so display-specific subpixel AA is never wanted in them.
Measured on Windows 11 (ClearType on, 125 % scaling, Chrome 152.0.7977.30), on a 22 px mono label on a solid card, as a red-versus-blue edge split on the glyphs (0 = neutral):
| build | plain | with --disable-lcd-text |
|---|---|---|
| 0.8.105 | 0.004 | |
| 0.9.40 | 0.500 | 0.003 |
In our runs it starts at 0.8.112. A solid card that is not on its own compositing layer already read 0.406 on 0.8.105, so the older builds were not immune either. Text over transparency, and anything under will-change: transform, is unaffected. macOS is unaffected. It is not specific to this flag set: a plain puppeteer launch on the same machine fringes the body text of a captured web page the same way (0.42 to 0.48, and 0.000 to 0.002 with the flag, with no glyph or line moving), so hyperframes capture is probably affected too, though we did not measure it.
Proposed solution
Two parts, either one would have solved it:
- Add
--disable-lcd-texttobuildChromeArgs. The engine's own motion blur fixture already launches with it (packages/engine/src/services/__fixtures__/motionBlur/blurPage.ts). With the flag on, the only other change we saw is that rotated text rasterises slightly crisper. - An escape hatch for flags in general, appended at the end of
buildChromeArgsand counted in the browser launch fingerprint, for example:
HYPERFRAMES_CHROME_ARGS="--disable-lcd-text --some-other-flag" npx hyperframes render ...
npx hyperframes render --chrome-arg=--disable-lcd-text ...or a render.chromeArgs array in hyperframes.json. It should reach render, snapshot, check and capture alike, since they should draw the same pixels.
Alternatives considered
- CSS on the composition.
will-change: transformon the root moves text off the LCD path but resamples embedded captures;opacity: 0.999on the root shifts moving overlays by a sub-pixel. Neither is a safe global fix. - No existing render flag changes it.
- What we run today: a Node preload (
NODE_OPTIONS=--require ./lcd-off.cjs) that wrapschild_process.spawnand friends and appends the flag when the spawned program is a Chrome. It works on macOS and on Windows (Git Bash, PowerShell, cmd), but it patches a built-in to reach a launch call the CLI owns, and every script that renders has to remember to load it.
Additional context
Checked against 0.9.42: buildChromeArgs has no user-supplied arguments and no --disable-lcd-text. Happy to test a build on the Windows machine that measured this.
Activity