Measured 2026-09-24 on hyperframes 0.8.71 (origin/main 58c873d) with the AE exporter's retro-wave export, HF_VFX=1 HF_VFX_REF=1.
Symptom
hyperframes check → Runtime ✗ check_runtime_failure: Runtime.callFunctionOn timed out after "Runtime did not become render-ready within 3000ms" / "Shader transitions did not finish pre-rendering"; hyperframes snapshot --at 2.6 hangs >500 s with no output. Zero console lines are collected in the failing runs (the renderer main thread is blocked, not slow).
Bisect (seven serialized check runs on hand-edited copies)
| copy |
noise+backdrop |
ref wrapper |
ext map |
nested layoutsubtree canvases |
result |
| unmodified |
✓ |
✓ |
✓ |
2 |
FAIL |
noise chains + data-vfx-for wrappers removed |
✗ |
✓ |
✓ |
1 |
FAIL |
map param dropped, ref wrapper kept |
✓ |
✓ |
✗ |
2 |
FAIL |
| ref wrapper unwrapped |
✓ |
✗ |
✗ |
1 |
FAIL |
| both shapes gone |
✗ |
✗ |
✗ |
0 |
PASS |
| E: both shapes kept verbatim; the two INNER self-capture triads removed |
✓ |
✓ |
✓ |
0 |
PASS |
F: = E with the two inner layoutsubtree canvases put back |
✓ |
✓ |
✓ |
2 |
FAIL |
E vs F differ by exactly two elements: a <canvas layoutsubtree class="hf-vfx-src"> nested inside another capture wrapper's subtree (a data-vfx-ref-visible ref wrapper around a host that runs its own displacement-map chain; a data-vfx-for backdrop wrapper whose preceding-sibling prefix contains a self-capture host). Every runtime path involved — findBackdropWrapper, resolveRefSource, data-vfx-ref-visible, CAPTURE_VISIBLE_SOURCE — is live in E and works. Every await in runtime/vfx.ts is bounded (CAPTURE_PAINT_TIMEOUT_MS), so this is Chrome refusing drawElementImage on a subtree containing another layoutsubtree canvas, not a JS promise.
The exporter is being fixed to never emit the nest (withdraw the chain with a gap). Three runtime items remain:
- Design gap: a
map/matte ref that names a layer which runs its own kernel cannot be expressed — wrapAsVfxRefSource's precondition "it runs no kernel of its own" is unsatisfiable for such layers. A ref param that may name a HOST and bind its .hf-vfx-out texture directly would remove the need for an outer wrapper.
- Latent (M2): host→src/out lookups are unscoped descendant queries —
runtime/vfx.ts:486 owner.querySelector("canvas.hf-vfx-src") and :263 host.querySelector("canvas.hf-vfx-out") — while :487 uses :scope > .hf-vfx-in and the comment at :475 states the immediate-child rule. On a nested shape this binds entry.src to the OUTER wrapper and entry.out to the INNER out, so captureSource would draw the canvas the entry paints into. Hidden today only because the nest hangs first.
- Latent (M3):
resolveCaptureSource hardcodes visible:false (:512) while resolveRefSource reads the attribute (:387) — a doubly-reached canvas gets two VfxCaptureSource objects with opposite keepBitmap; registry order decides.
Suggested runtime hardening independent of the exporter fix: reject (with a reportVfxError) any .hf-vfx-src whose subtree contains another .hf-vfx-src, rather than hanging; and scope the two lookups to :scope >.
Repro copies and logs are on the AE-export machine (/tmp/hf71-bisect-{a,b,b2,c,e,f}, /tmp/fable-coord/hf71-bisect-*.log); exporter-side record: hyperframes-ae-exporter spec §Task 3.8 (2026-09-24).
🤖 Generated with Claude Code
Measured 2026-09-24 on hyperframes 0.8.71 (
origin/main58c873d) with the AE exporter's retro-wave export,HF_VFX=1 HF_VFX_REF=1.Symptom
hyperframes check→Runtime ✗ check_runtime_failure: Runtime.callFunctionOn timed outafter "Runtime did not become render-ready within 3000ms" / "Shader transitions did not finish pre-rendering";hyperframes snapshot --at 2.6hangs >500 s with no output. Zero console lines are collected in the failing runs (the renderer main thread is blocked, not slow).Bisect (seven serialized
checkruns on hand-edited copies)maplayoutsubtreecanvasesdata-vfx-forwrappers removedmapparam dropped, ref wrapper keptlayoutsubtreecanvases put backE vs F differ by exactly two elements: a
<canvas layoutsubtree class="hf-vfx-src">nested inside another capture wrapper's subtree (adata-vfx-ref-visibleref wrapper around a host that runs its owndisplacement-mapchain; adata-vfx-forbackdrop wrapper whose preceding-sibling prefix contains a self-capture host). Every runtime path involved —findBackdropWrapper,resolveRefSource,data-vfx-ref-visible,CAPTURE_VISIBLE_SOURCE— is live in E and works. Everyawaitinruntime/vfx.tsis bounded (CAPTURE_PAINT_TIMEOUT_MS), so this is Chrome refusingdrawElementImageon a subtree containing anotherlayoutsubtreecanvas, not a JS promise.The exporter is being fixed to never emit the nest (withdraw the chain with a gap). Three runtime items remain:
map/matteref that names a layer which runs its own kernel cannot be expressed —wrapAsVfxRefSource's precondition "it runs no kernel of its own" is unsatisfiable for such layers. A ref param that may name a HOST and bind its.hf-vfx-outtexture directly would remove the need for an outer wrapper.runtime/vfx.ts:486owner.querySelector("canvas.hf-vfx-src")and:263host.querySelector("canvas.hf-vfx-out")— while:487uses:scope > .hf-vfx-inand the comment at:475states the immediate-child rule. On a nested shape this bindsentry.srcto the OUTER wrapper andentry.outto the INNER out, socaptureSourcewould draw the canvas the entry paints into. Hidden today only because the nest hangs first.resolveCaptureSourcehardcodesvisible:false(:512) whileresolveRefSourcereads the attribute (:387) — a doubly-reached canvas gets twoVfxCaptureSourceobjects with oppositekeepBitmap; registry order decides.Suggested runtime hardening independent of the exporter fix: reject (with a
reportVfxError) any.hf-vfx-srcwhose subtree contains another.hf-vfx-src, rather than hanging; and scope the two lookups to:scope >.Repro copies and logs are on the AE-export machine (
/tmp/hf71-bisect-{a,b,b2,c,e,f},/tmp/fable-coord/hf71-bisect-*.log); exporter-side record: hyperframes-ae-exporter spec §Task 3.8 (2026-09-24).🤖 Generated with Claude Code