Commit b3b458f
committed
fix(shader-transitions): harden capture against visibility, scrub, Safari taint
Three interrelated fixes for the live-player path in
@hyperframes/shader-transitions (Studio preview, <hyperframes-player>
embeds, Claude Design in-pane iframe). Zero changes to engine mode —
initEngineMode is byte-identical; producer render pipeline and CLI
hyperframes render produce byte-identical output.
1. captureIncomingScene now forces visibility:visible during capture.
The HF runtime sets visibility:hidden on [data-start] elements outside
their playback window. With centered shader timing (transition.time =
boundary - duration/2), html2canvas captures the incoming scene while
it's still hidden → blank texture → visible blink mid-transition.
Fix saves, overrides, captures, and restores visibility only for the
capture window. Empirically validated via a direct html2canvas probe:
captures of visibility:hidden elements return blank; with override,
they return real content.
2. post-capture.dom guards on tl.time() window before mutating DOM.
On scrub across multiple shader transitions, tl.call() fires several
transitions' callbacks in rapid succession; each launches async
html2canvas; each .then() unconditionally set all .scene opacities to
0, enabled shader canvas, and pointed state at that transition. The
last to resolve won — often for a transition the playhead had left.
Result: scenes stuck opacity:0 mid-scene; blank screen until the next
transition's end.call ran. Fix: check tl.time() is still inside
[T, T+dur] before applying state; otherwise skip.
3. .catch fallback does CSS crossfade instead of hard cut.
When capture fails (Safari canvas taint from SVG data URLs, CORS
errors, extreme DOM complexity) the old catch snapped all scenes to
opacity:0 then set incoming to opacity:1 — jarring instant jump. Fix
uses gsap.to/fromTo on opacity over the intended transition duration;
smooth 0.5s fade is strictly better UX. Hard cut preserved as
last-resort if elements are missing.
Also adds defensive useCORS: true and allowTaint: true to the
html2canvas call. No behavior change in Chrome (capture normally
succeeds); adds resilience for cross-origin images with CORS headers
and SVG-tainted canvases respectively.
Known limitations (out of scope, follow-up tracked):
- Safari + cross-origin iframe: html2canvas is 10-12x slower than Chrome
due to WebKit's DocumentCloner.cloneNode perf (html2canvas#3108),
causing perceptible per-transition freezes (1.5-2s each) in Claude
Design's in-pane preview. Needs pre-capture architecture (cache
incoming-scene textures at init) to eliminate per-transition cost.
- SVG filter data URLs fundamentally taint html2canvas output in Safari;
WebGL's texImage2D has no framework opt-out (WebGL spec). Addressed
at the composition level via the Claude Design skill's anti-pattern 4
in a parallel PR.
Made-with: Cursor1 parent 3089c8e commit b3b458f
2 files changed
Lines changed: 84 additions & 15 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
33 | 33 | | |
34 | 34 | | |
35 | 35 | | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
36 | 50 | | |
37 | 51 | | |
38 | 52 | | |
| |||
41 | 55 | | |
42 | 56 | | |
43 | 57 | | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
44 | 70 | | |
45 | 71 | | |
46 | 72 | | |
| |||
49 | 75 | | |
50 | 76 | | |
51 | 77 | | |
| 78 | + | |
52 | 79 | | |
53 | 80 | | |
| 81 | + | |
54 | 82 | | |
55 | 83 | | |
56 | 84 | | |
57 | 85 | | |
58 | 86 | | |
59 | 87 | | |
| 88 | + | |
60 | 89 | | |
61 | 90 | | |
62 | 91 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
17 | 23 | | |
18 | 24 | | |
19 | 25 | | |
20 | 26 | | |
21 | 27 | | |
22 | 28 | | |
| 29 | + | |
23 | 30 | | |
24 | 31 | | |
25 | 32 | | |
| |||
271 | 278 | | |
272 | 279 | | |
273 | 280 | | |
274 | | - | |
275 | | - | |
276 | | - | |
277 | | - | |
278 | | - | |
279 | | - | |
280 | | - | |
281 | | - | |
282 | | - | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
283 | 307 | | |
284 | 308 | | |
285 | 309 | | |
286 | 310 | | |
287 | | - | |
288 | | - | |
289 | | - | |
290 | | - | |
291 | | - | |
292 | | - | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
293 | 333 | | |
294 | 334 | | |
295 | 335 | | |
| |||
0 commit comments