Describe the bug
Text elements that inherit color from a parent (via CSS inheritance) are invisible in the rendered MP4 output, even though they display correctly in hyperframes preview. Explicitly setting color on the element itself resolves the issue.
This affects any composition where text relies on CSS color inheritance rather than an explicit inline color: declaration. The bug occurs on the pageScreenshotCapture render path (macOS/Windows), which uses Page.captureScreenshot CDP.
Link to reproduction
I cannot share the full repo publicly. I can create a minimal reproduction project if needed.
Steps to reproduce
- Create a composition with a root element that sets
color: #e8e8e8
- Add a child text element that does NOT declare
color explicitly (relies on inheritance)
- Animate the text with a GSAP
tl.from() or tl.fromTo() tween
- Run
npx hyperframes render
- The inherited-color text is invisible in the output
Minimal example:
<!-- index.html -->
<div id="root" data-composition-id="main" data-start="0" data-duration="10"
style="width:1920px;height:1080px;background:#0a0a0a;color:#e8e8e8">
<div class="clip" data-composition-id="s1" data-composition-src="compositions/s1.html"
data-start="0" data-duration="10" style="position:absolute;inset:0;z-index:1">
</div>
</div>
<!-- compositions/s1.html -->
<template id="s1-template">
<div data-composition-id="s1" style="width:1920px;height:1080px;color:#e8e8e8;background:#0a0a0a">
<div id="title" style="position:absolute;left:92px;top:100px;font-size:76px;font-weight:950">
This text is invisible in render
</div>
<div id="subtitle" style="position:absolute;left:24px;bottom:16px;color:#67e8f9;font-size:32px">
This text is visible in render
</div>
</div>
</template>
<script>
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({paused: true});
tl.from('#title', {opacity: 0, y: 34, duration: .55, ease: 'power3.out'}, .1);
window.__timelines.s1 = tl;
</script>
Expected behavior
Text inheriting color from a parent element should be visible in the rendered MP4, matching the preview.
Actual behavior
Inherited-color text is invisible in the rendered output. Explicit color on the element fixes it.
Diagnostic steps taken:
- Text IS in the DOM and positioned correctly — visible with
background:rgba(0,255,0,0.5) + color:#ff0000
- Removed all GSAP tweens → still invisible (rules out GSAP animation bug)
- Removed Three.js entirely → still invisible (rules out WebGL compositing)
- Added explicit
color:#e8e8e8 → text becomes visible
Root cause hypothesis:
GSAP's tl.from() uses immediateRender: true, which sets inline opacity:0; transform:translateY(34px) on the element at timeline creation. When the animation completes and GSAP cleans up these inline styles, the element returns to a bare state relying on CSS inheritance for color. On Chrome's Page.captureScreenshot CDP path, the compositor does not properly resolve the inherited color value. Only color inheritance is affected — other inherited properties like font-family resolve correctly.
Environment
✓ Version 0.6.71
✓ Node.js v22.x.x (darwin arm64)
✓ CPU 10 cores · Apple M2 Pro @ 2400MHz
✓ OS macOS arm64
✓ Chrome system: Google Chrome 148.0.7778.216
✗ Docker Not found
Additional context
The relevant screenshot code is in packages/engine/src/services/screenshotService.ts, pageScreenshotCapture():
await client.send("Page.captureScreenshot", {
format: isPng ? "png" : "jpeg",
fromSurface: true,
captureBeyondViewport: true,
clip: { x: 0, y: 0, width: options.width, height: options.height, scale: dpr },
});
The BeginFrame path (HeadlessExperimental.beginFrame) is Linux-only and may or may not exhibit the same issue.
Workaround: Add explicit color to every text element in your compositions instead of relying on inheritance.
Describe the bug
Text elements that inherit
colorfrom a parent (via CSS inheritance) are invisible in the rendered MP4 output, even though they display correctly inhyperframes preview. Explicitly settingcoloron the element itself resolves the issue.This affects any composition where text relies on CSS
colorinheritance rather than an explicit inlinecolor:declaration. The bug occurs on thepageScreenshotCapturerender path (macOS/Windows), which usesPage.captureScreenshotCDP.Link to reproduction
I cannot share the full repo publicly. I can create a minimal reproduction project if needed.
Steps to reproduce
color: #e8e8e8colorexplicitly (relies on inheritance)tl.from()ortl.fromTo()tweennpx hyperframes renderMinimal example:
Expected behavior
Text inheriting
colorfrom a parent element should be visible in the rendered MP4, matching the preview.Actual behavior
Inherited-color text is invisible in the rendered output. Explicit
coloron the element fixes it.Diagnostic steps taken:
background:rgba(0,255,0,0.5)+color:#ff0000color:#e8e8e8→ text becomes visibleRoot cause hypothesis:
GSAP's
tl.from()usesimmediateRender: true, which sets inlineopacity:0; transform:translateY(34px)on the element at timeline creation. When the animation completes and GSAP cleans up these inline styles, the element returns to a bare state relying on CSS inheritance forcolor. On Chrome'sPage.captureScreenshotCDP path, the compositor does not properly resolve the inheritedcolorvalue. Onlycolorinheritance is affected — other inherited properties likefont-familyresolve correctly.Environment
Additional context
The relevant screenshot code is in
packages/engine/src/services/screenshotService.ts,pageScreenshotCapture():The
BeginFramepath (HeadlessExperimental.beginFrame) is Linux-only and may or may not exhibit the same issue.Workaround: Add explicit
colorto every text element in your compositions instead of relying on inheritance.