Skip to content

feat(hdr): GSAP transforms and border-radius masks on HDR video#290

Open
vanceingalls wants to merge 1 commit intofeat/hdr-phase-2from
feat/hdr-phase-3
Open

feat(hdr): GSAP transforms and border-radius masks on HDR video#290
vanceingalls wants to merge 1 commit intofeat/hdr-phase-2from
feat/hdr-phase-3

Conversation

@vanceingalls
Copy link
Copy Markdown
Collaborator

@vanceingalls vanceingalls commented Apr 16, 2026

Summary

HDR video elements with GSAP animations (position, scale, rotation, opacity) and CSS border-radius rendered without any transforms applied — the video just sat at (0,0) full-size. This PR adds affine transform support and rounded-corner masking for natively-composited HDR video.

What it does

Affine blit with bilinear interpolation:

  • blitRgb48leAffine() — Takes a 4x4 DOMMatrix and maps each destination pixel back to source coordinates via the inverse transform. Bilinear interpolation between the 4 nearest source pixels produces smooth edges under rotation and non-integer scaling. Optional opacity and border-radius parameters.
  • parseTransformMatrix() — Parses CSS matrix(a,b,c,d,e,f) strings into [a,b,c,d,e,f] tuples.

Accumulated viewport matrix:

  • getViewportMatrix() — Walks the offsetParent chain from element to viewport, accumulating position offsets and CSS transforms at each level. Correctly handles transform-origin using the CSS sandwich: translate(origin) × M × translate(-origin). This is critical because GSAP animates transforms on wrapper divs, not directly on the video element.

Effective opacity:

  • getEffectiveOpacity() — Multiplies opacity values walking up the ancestor chain. Uses Number.isNaN() (not || 1) so opacity:0 isn't incorrectly treated as 1.

Border-radius masks:

  • roundedRectAlpha() — Per-pixel anti-aliased rounded-rectangle mask with support for independent corner radii.
  • getEffectiveBorderRadius() — Walks ancestors for overflow:hidden + border-radius. Resolves percentage values (e.g., 50% for circles) via offsetWidth/offsetHeight.

Layout dimensions for extraction:

  • Uses offsetWidth/offsetHeight (unaffected by CSS transforms) instead of getBoundingClientRect() (which returns the transformed bounding box and wobbles under rotation).

Files changed

File What changed
packages/engine/src/utils/alphaBlit.ts blitRgb48leAffine(), parseTransformMatrix(), roundedRectAlpha(), cornerAlpha()
packages/engine/src/services/videoFrameInjector.ts getViewportMatrix(), getEffectiveOpacity(), getEffectiveBorderRadius(), layoutWidth/layoutHeight on ElementStackingInfo
packages/producer/src/services/renderOrchestrator.ts Affine blit path, extraction at layout dimensions, border-radius parameter passing

How to test

Render a composition with an HDR video that has GSAP scale + rotation animation and a border-radius: 50% wrapper (circle mask). The video should rotate smoothly with round edges — no wobble, no sharp corners.

Stack position

5 of 6 — Stacked on #289 (z-ordered layers). Adds transform and masking support to the HDR blit that the layer compositor uses.

🤖 Generated with Claude Code

Copy link
Copy Markdown
Collaborator Author

vanceingalls commented Apr 16, 2026

@vanceingalls vanceingalls force-pushed the feat/hdr-phase-2 branch 2 times, most recently from 1ea1b2b to 528ea17 Compare April 16, 2026 00:51
@vanceingalls vanceingalls force-pushed the feat/hdr-phase-3 branch 2 times, most recently from 3e571ca to c8cb0d0 Compare April 16, 2026 00:54
@vanceingalls vanceingalls marked this pull request as ready for review April 16, 2026 00:54
@vanceingalls vanceingalls changed the title fix(hdr): extract at element display dimensions, not composition dimensions feat(hdr): GSAP transforms and border-radius masks on HDR video Apr 17, 2026
Affine blit with bilinear interpolation for GSAP-animated HDR video.
Accumulated viewport matrix via DOMMatrix chain with transform-origin
handling. Effective opacity ancestor walk. Rounded-rectangle mask with
anti-aliased corners and percentage resolution. Layout dimensions for
extraction (unaffected by CSS transforms). SDR visibility fixes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

1 participant