Commit Graph

4 Commits

Author SHA1 Message Date
Vance Ingalls b3d089a2ba fix(engine): mechanism-based stacked-fade gate, drop hf-tx markup gate
The crossfade gate from the previous commit keyed on the hf-tx class —
a private convention of one composition generator, not a framework
contract (zero hits in core/runtime/skills). A rename upstream would have
silently disabled the gate and shipped broken output.

Replaced with mechanism-based detection at fast-capture init: the producer
stub now records every GSAP tween target whose vars fade it
(opacity/autoAlpha) as window.__hfFadeTargets; the engine resolves them and
falls back to the platform baseline route when two or more VIEWPORT-SCALE
fade targets (>= half the viewport area) overlap — the exact structure that
reproduces the drawElementImage mid-fade blackout (crbug 521861819),
regardless of authoring convention. Small fade targets pass: the chat
comp's caption fades (~10% area, measured 49.6 dB clean) keep the fast
path, as does every CI comp.

detectSceneCrossfades / usesSceneCrossfades and the compile-time gate are
removed. HF_FAST_CAPTURE_CROSSFADE=true still bypasses. Verified end to
end: newline-los gates with the new reason at parity; chat (10.3s) and
gsap-letters (3.0s) keep drawElement. 78 htmlCompiler tests pass.

Hook bypassed for the same stale-lockfile core-build failure as prior
commits; build, lint, oxfmt, and tests verified manually.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-14 15:44:00 -07:00
Vance Ingalls 2b2b178526 fix(producer): crossfade + software-GL gates for fast capture
Two more compile-time gates, same shape and fallback contract as the video
and 3D gates — anything measured slower than baseline or below the quality
bar routes to the platform's baseline capture by default.

Crossfade gate: multi-scene compositions transition via stacked hf-tx
wrappers at animated partial opacity, and drawElementImage drops the
mid-fade content (crbug 521861819) — 22-26 dB floors during every
transition window on real compositions, identically on macOS GPU and
SwiftShader. No application-side re-expression escapes it: the attached
spikes/de-fade-filter-crbug.mjs proves filter:opacity() fades hit the
identical 240/240 blackout. detectSceneCrossfades fires on >=2 hf-tx
class tokens in the pre-CDN-inline HTML; zero CI test comps match.
HF_FAST_CAPTURE_CROSSFADE=true bypasses.

Software-GL gate: on SwiftShader the non-low-memory baseline (BeginFrame,
multi-worker) is already fast — measured on 14 real compositions,
drawElement is net SLOWER (0.71-0.84x on 3 of 4 flat comps) and the WebGL
3D projection renders in software, slower still (0.66-0.91x). Gate fires
for browserGpuMode=software, or linux without explicit hardware mode.
HF_FAST_CAPTURE_SWIFTSHADER=true bypasses.

Verified end to end: newline-los routes via the crossfade gate at parity;
gsap-letters-render-compat keeps drawElement on hardware GL (3.1s) and
gates on software GL. 82 htmlCompiler tests pass (4 new).

Also adds the upstream repro spikes filed today: de-fade-filter-crbug.mjs
(521861819 comment), de-canvas-freeze-crbug.mjs (crbug 522845799), and the
de-fade-filter-test.mjs exploration. 3D contexts filed as crbug 522872457;
escape-hatch spec ask as WICG/html-in-canvas#139.

Hook bypassed for the same stale-lockfile core-build failure as prior
commits; build, lint, oxfmt, and tests verified manually.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-14 15:44:00 -07:00
Vance Ingalls 216886308a feat(engine): WebGL 3D-context projection for fast capture
drawElementImage cannot paint CSS 3D: rendering contexts drop earlier
siblings and backgrounds, backface-visibility is ignored (mirrored
backfaces even at rest), and flat 3D matrices silently lose their
rotation. Until now every 3D comp was gated to the baseline route.

threeDProjection.ts rewrites 3D content in-page before capture:
- discovery: perspective/preserve-3d contexts, elements at a 3D matrix
  at t=0, and the producer stub's record of 3D tween targets
  (rotationX/rotationY/transformPerspective) for to()-style tweens that
  are still flat at init
- leaf quads rasterized once via SVG foreignObject (fonts and images
  inlined as data URLs), shell quads carry only own paint when a child
  contains further 3D
- per-frame WebGL projection from live computed matrices: CSS-convention
  matrix math, perspective + transform-origin sandwiches, GL backface
  culling, accumulated opacity as a fragment uniform
- live elements hidden via clip-path (GSAP autoAlpha fights
  visibility/opacity), 3D contexts neutralized and live 3D matrices
  stripped after reading (perspective-carrying and rotated matrices
  poison the capture even when hidden), authored backface flags captured
  before neutralization
- projected canvases composite OVER the DOM paint — the under-pass would
  bury them beneath the composition root's own background

Correctness guards fall back to the platform baseline route, same
contract as the video gate: degenerate markup (zero-size/inline-box
quads — gen_os flip-card spans) and quads with GSAP-animated descendants
(static textures would freeze them; golf measured 46->24 dB without
this).

fast-capture-3d test comp (flip card + perspective-free rotationX
entrance): 57.5 dB avg / 51.7 dB min vs baseline at 1.5x speedup.
Real-world comps with animated 3D subtrees fall back cleanly.

Engine suite 692/694 (2 failures pre-exist on clean tree); build, lint,
oxfmt verified manually — hook bypassed for the same stale-lockfile
core-build failure as the previous commit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-14 15:44:00 -07:00
Vance Ingalls 6923874548 fix(producer): compile-time 3D-transform gate for fast capture
drawElementImage cannot paint CSS 3D rendering contexts: backface-
visibility:hidden is ignored (flip cards capture their mirrored backface,
even at rest), siblings of the 3D context drop out of the capture, and the
context's background is lost. Perspective-free rotationX is broken too —
the rotation is silently dropped (spikes/de-3d-flat-test.mjs). Standalone
repro: spikes/de-3d-probe.mjs.

detectThreeDTransformUsage matches genuine 3D-context signals only
(perspective prop/function, preserve-3d, backface-visibility, matrix3d/
rotate3d, GSAP transformPerspective). Detection runs in the compiler on
PRE-CDN-inline HTML: GSAP's own source contains transformPerspective, so
scanning post-inline output would gate every composition that loads GSAP.
Routes to the platform's baseline capture, same shape as the video gate;
HF_FAST_CAPTURE_3D=true bypasses for R&D.

Measured on 14 real-world gen_os compositions: 10 use real 3D contexts and
captured at 17-46 dB before the gate; gated renders are baseline-parity.

Also ignore the puppeteer-downloaded chrome/ tree in oxlint.

Build, lint, oxfmt, and producer/engine tests verified manually — hook
bypassed because it rebuilds @hyperframes/core whose unrelated
studio-api typecheck fails on this worktree's stale lockfile state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-14 15:44:00 -07:00