Skip to content

fix(core): the filter tier's svg no longer changes which child is last in the root - #7293

Merged
vanceingalls merged 1 commit into
mainfrom
fix/blur-filter-svg-outside-root
Nov 6, 2026
Merged

vanceingalls merged 1 commit into
mainfrom
fix/blur-filter-svg-outside-root

Conversation

@vanceingalls

Copy link
Copy Markdown
Collaborator

What

The filter tier appended its hidden <svg><defs> (the per-mover SVG filters) to the composition root and left it there until teardown, so #root > :last-child or :last-child selectors on the root's children matched the injected svg and a stray square could draw at (0,0) (sweep defect I: 1980 px differ from the oracle). The svg now goes under document.documentElement instead (not document.head: a display:none subtree can stop a filter reference resolving in Chrome). One line in filterTier.ts layerOf.

Removal still works from the new parent (teardown calls defs.remove()), and at most one filter tier exists at a time, so filter ids (hf-mb-<n>) cannot collide across two svgs.

Tests

  • index.test.ts: keeps the filter tier's svg out of the root and removes it on teardown: none inside the root, exactly one in the document after a paint, still one after re-init, zero after teardown.
  • The filter-tier last-child-selector sweep case loses its bug field and S.I and passes as an ordinary outside-the-trail check. The plain filter case in the same file is what proves the filter reference still resolves from documentElement.
  • With only the one-line move reverted, the new unit test and the un-pinned sweep case both fail. Core captureMotionBlur 213 pass; engine sweep + differential 90 pass on Chrome 153.

Limits

  • The svg now sits under <html>, outside <body>, while the filter tier is active. Nothing in core, engine, cli or studio clones or serialises the live documentElement.
  • html > :last-child and body:last-child author selectors now see the svg as a sibling of body; far less likely than the #root case.

🤖 Generated with Claude Code

…t in the root

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Edit accuracy: accurate 267 (base branch 267), smooth 123 of those

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

Quarantined, measured but not gated (8)

@heygengenesis heygengenesis Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: APPROVE · 0 blocker · 0 important · 0 nits · head fe037536

Scope
  • Read filterTier.ts end to end. teardown removes the svg from any parent, and the tier was already building it with the global document (same as createElementNS and landThenUndoDom(…, document)), so moving it under documentElement adds no new document assumption. Nothing else in captureMotionBlur/ appends to root. The canvas tier wraps the root and doesn't add children to it.
  • Checked locally: core index.test.ts passes 125/125. With only the one line reverted, the new test fails.
  • CI: the first Studio: edit accuracy (14/15) failure was a puppeteer WS-endpoint launch timeout, unrelated to this change. After a rerun the whole CI run is green. captureMotionBlur.sweep.browser.test.ts ran in Test (17 passed). Windows render verification and Safari perf were still running when this was posted.
  • The html > :last-child / body:last-child exposure is documented in the PR body. I accept it as is.

— Genesis

@vanceingalls
vanceingalls added this pull request to the merge queue Nov 6, 2026
Merged via the queue into main with commit 2066a2f Nov 6, 2026
156 of 160 checks passed
@vanceingalls
vanceingalls deleted the fix/blur-filter-svg-outside-root branch November 6, 2026 04:51
SanHsien added a commit to SanHsien/hyperframes that referenced this pull request Nov 6, 2026
…view

Adopts heygen-com#7294 (line_unread findings carry the measured frames), heygen-com#7271
(blur mutes discrete callbacks instead of undoing them), heygen-com#7293 (the
filter tier's svg keeps the last child), heygen-com#7292 (a mover holding a fixed
child stays sharp), heygen-com#7288 (auto motion blur draws with the filter tier)
and heygen-com#7298 (Shift no longer re-renders the timeline). The fork's seek
recovery in captureMotionBlur stays. Defers heygen-com#7134 (no packages/share)
and heygen-com#7295 (needs the heygen-com#7080 crop pipeline). Watermark advances to
66cbabc.

Co-authored-by: Miguel Ángel <miguel.sierra@heygen.com>
Co-authored-by: Vance Ingalls <vance@heygen.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SanHsien added a commit to SanHsien/hyperframes that referenced this pull request Nov 6, 2026
…-com#7288)

537b88d adopted heygen-com#7288, which makes auto motion blur draw with the
filter tier, but left out the engine side. Pixel tests that expect the
capture tier then failed on Windows CI. Take upstream e2bb7da's
change to captureMotionBlur.pixels.browser.test.ts, which asks those
tests for the capture tier explicitly. The other engine files that
heygen-com#7271/heygen-com#7288/heygen-com#7292/heygen-com#7293 touch (fixtures, thresholds, sweep and
differential tests) do not exist in this fork.

Co-authored-by: Vance Ingalls <vance@heygen.com>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <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