fix(engine,shader): handle matrix3d transforms and hide non-first scenes#374
fix(engine,shader): handle matrix3d transforms and hide non-first scenes#374vanceingalls merged 2 commits intomainfrom
Conversation
f328731 to
79b029f
Compare
4f4682b to
78a6af9
Compare
79b029f to
e78f981
Compare
3838031 to
95df8c6
Compare
45009c4 to
cb840e7
Compare
jrusso1020
left a comment
There was a problem hiding this comment.
Two real fixes, both structural:
matrix3d in parseTransformMatrix — previously returned null for any 3D matrix, which meant every GSAP composition with force3D: true (GSAP's default for transform tweens) fell off the deterministic engine path and rendered with identity transforms on the HDR compositor. The spec-correct approach is: parse the 16-element column-major matrix, extract the 2D affine components (a=m[0], b=m[1], c=m[4], d=m[5], tx=m[12], ty=m[13]), drop Z-translation, and validate all six extracted components are finite. Tests pin the three common GSAP emission shapes (identity, translate3d, scale + translate3d, rotateZ) plus malformed rejection (wrong arg count, NaN values). Exactly the right coverage.
Worth documenting in code (or the plans doc) that this is a 2D projection of the 3D transform — any composition that actually uses Z-depth (perspective, 3D rotation around X/Y axes) will silently lose those components in the engine path. For force3D: true with a flat Z this is invisible; for a genuine 3D scene the engine just doesn't support it, which was already the case before this PR but is now hidden behind a "parses successfully" result instead of a null. If a Z-significant transform ever shows up in a regression test, the engine will render it flat without flagging that it threw away the Z info. Non-blocking, but worth a log warning when m[8..11] are non-identity.
Non-first scenes start at opacity: 0 in hyper-shader.ts — the fix for the Window F corruption in #365. Without this, non-first scenes were visible during scene-A capture and bled into the HDR compositor's first frame. Cleaner than the alternative (hiding scenes via DOM manipulation) because it stays inside the shader-transitions package's opacity contract.
CI failures here are the stack-wide Format and Render on windows-latest — not specific to this change. The Windows failure across the whole upper stack is worth running down separately (could be LFS-check issue after #376, or could be unrelated).
Approved.
— Rames Jusso
7f0411c to
d233789
Compare
44ff16f to
aa8b9be
Compare
d233789 to
404ec3f
Compare
aa8b9be to
c623430
Compare
404ec3f to
cf5c309
Compare
c623430 to
ba25661
Compare
cf5c309 to
13d8aa7
Compare
ba25661 to
ccc725f
Compare
13d8aa7 to
ff96886
Compare
ccc725f to
5589417
Compare
ff96886 to
b841366
Compare
5589417 to
6d73142
Compare
b841366 to
a56ed28
Compare
6d73142 to
52c6034
Compare
a56ed28 to
7f5f8ae
Compare
263d844 to
13b88d2
Compare
7f5f8ae to
41c8c36
Compare
13b88d2 to
3d8b1dd
Compare
13b88d2 to
a3d7cc1
Compare
41c8c36 to
ea64bc3
Compare
ea64bc3 to
f09f4f9
Compare
| return values; | ||
| } | ||
|
|
||
| const match3d = css.match(/^matrix3d\(\s*([^)]+)\)$/); |
Address jrusso1020's nit on PR #365 (non-blocking review): both READMEs now explain where the tolerance values come from. - hdr-regression/README.md: add a budget-breakdown table that derives the 30 frames from the deltas in PRs #369 (window C fix → 5) and #375 (window F fix → 0). The table doubles as a contract: if a future change forces the budget back up, exactly one bucket has regressed and the table tells you which one to investigate first. - hdr-hlg-regression/README.md: add a 'Tolerance' section explaining why 0 is the right floor (HLG is a pure pass-through path, HEVC over rgb48le is byte-deterministic on the same fixture, so any drift is a real regression). The regeneration command for generate-hdr-photo-pq.py was already documented at README lines 67-71, so no changes needed there.
f09f4f9 to
b3c7f8f
Compare
Merge activity
|

Summary
Two correctness fixes in the HDR transform & clipping pipeline:
parseTransformMatrixnow handlesmatrix3d(...)(GSAP's defaultforce3D: true), and shader-transitions sets every non-first scene toopacity: 0att=0so the engine doesn't over-composite at the start.Why
Chunk 4ofplans/hdr-followups.md. Transform extraction and border-radius computation existed but were dead — an HDR video withrotation: 45rendered un-rotated, and 3-scene compositions ghosted att=0because every scene defaulted to CSSopacity: 1and contributed to the first frame.What changed
Matrix3d support in
parseTransformMatrix.DOMMatrix.toString()emitsmatrix3dwhenever any ancestor in the chain has used a 3D transform — most importantly GSAP's defaultforce3D: true, which convertstranslate(...)intotranslate3d(..., 0). Without this, every GSAP-driven transform was silently dropped during HDR compositing becausevideoFrameInjector.getViewportMatrix()would returnmatrix3d(...)and the blit path would parse it asnulland fall back to identity. The 16-value column-major form is converted to its 2D affine projection (indices 0, 1, 4, 5, 12, 13 → m11, m12, m21, m22, m41, m42); Z, perspective, and out-of-plane rotation components are dropped.Initial-state opacity in
initEngineMode. The browser preview branch uses a GL canvas overlay during transitions, so scene opacity att=0doesn't matter visually. The engine branch reads scene opacity directly viaqueryElementStacking()to decide which layers to composite. Without an explicit initial-state tween, every scene defaulted to CSSopacity: 1and contributed to the very first frame, causing ghosting/overlap until the first transition fired.tl.set()at position 0 anchors the initial state in the timeline graph so reverse seeks from inside a later transition restore it correctly.These two fixes together make
el.transformandel.borderRadius(already wired in Chunk 7A'scompositeHdrFrame) actually flow through the GSAP-animated case, and keep the engine's per-frame compositing aligned with what the user sees in browser preview.Test plan
alphaBlit.test.tscases (identity matrix3d, translate3d, scale + translate3d, rotateZ, malformed arg count, non-finite values).hdr-regressionWindow H already CSS-sets#scene-b { opacity: 0 }as a fallback; the newtl.setis redundant for that case but harmless and removes the need for compositions to remember the CSS workaround.rotation: 45) appears rotated;border-radius: 50%clips to circle; 3-scene composition has no overlap att=0.Stack
Chunk 4 of
plans/hdr-followups.md. Window F of the regression suite documents the bug; the next PR in the stack tightens themaxFrameFailuresbudget to 0.