feat(cli): tell authors in check why motion blur is off by vanceingalls · Pull Request #5992 · heygen-com/hyperframes · GitHub
Skip to content

feat(cli): tell authors in check why motion blur is off - #5992

Open
vanceingalls wants to merge 1 commit into
feat/capture-blur-reportfrom
feat/capture-blur-check-findings
Open

vanceingalls wants to merge 1 commit into
feat/capture-blur-reportfrom
feat/capture-blur-check-findings

Conversation

@vanceingalls

@vanceingalls vanceingalls commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

What

Tells authors in hyperframes check why motion blur is off.

  • check reads the runtime's probe() for a page whose root asked for blur and reports motion_blur_off (warning, with a fix hint per reason code; the iframe-in-root hint now names <iframe>, <object>, <embed> and custom elements, which are all re-initialised when blur wraps the root, and a root mix-blend-mode has its own: move it to a child element, or drop motion blur), motion_blur_no_movers (info, when nothing moves fast enough to blur) and motion_blur_unverified (info, when the check browser has no html-in-canvas to decide with).
  • It asks the runtime which root wants blur instead of reading attributes itself, so data-root="true" is honoured and the first composition's attribute is not mistaken for the runtime's choice. The finding is anchored (selector, data attributes, bounding box) on that same root, data-root="true" first and else the first composition, not on the first [data-composition-id] in the document.
  • Right after probing it calls suspend() for the rest of its session. Its audits read plain DOM, so they no longer pay the roughly 10x slowdown of auditing a wrapped composition. It never sets the page's off switch, which would change the probe's answer.
  • The console echo of the same message ([motion-blur] off: …) is dropped when a finding says it, so a finding is not shown twice; an unrelated console warning, and an error that only starts like the echo, are kept.

Why

Part 9 of 9 in the capture motion blur stack: #5875 → #5967 → #5968 → #5969 → #5970 → #5971 → #5990 → #5991 → #5992. It builds on #5991, which gives the runtime the reason codes, probe() and suspend() this reads.

The stack delivers opt-in capture motion blur for compositions, in Studio preview and in renders, drawn with Chrome's html-in-canvas. Blur turns itself off in several cases, and without this an author who asked for data-motion-blur="on" cannot tell from the check output.

Notes

  • A script-set data-motion-blur is not supported: the attribute has to be in the HTML for the render-mode hint, and check reports only what the runtime decided.
  • Cost of blur, from the stack's measurements: about 1.7x median render time for a blurred composition; compositions that are blocked or static cost nothing extra.
  • The stack's documented limits (trails drawn over foreground elements; a halo on transparent movers; trails leaking past overflow:hidden; a 2D flip through scaleX = 0 blending as rotation; sub-pixel left steps in whole px; a fast child inside a parent that moved earlier not blurred; SVG elements not scanned; shadow DOM not scanned for backface; blurred preview updating at half rate; video preview about 2–3% darker; worker-count output differences; the scan leaving about one level of noise) are unchanged by this PR.

Testing

  • checkMotionBlur.test.ts: each finding, its severity and fix hint (the widened iframe hint, root-blend-mode, and the accelerated-canvas hint, which now says the scan covers sub-compositions too and offers rendering that effect separately or flattening it out of the page, or dropping data-motion-blur on the composition), and the console-echo filter; checkMotionBlur.page.test.ts: the probe serialised into the page, which root it asks about, the suspend() right after the probe (and a runtime without suspend), the mover count, and a page that never opted in.
  • checkBrowser.test.ts: a blur finding reaches the check output with its fix and its anchor, the anchor is the data-root="true" composition when a sub-composition comes first in the document, once when a second Chrome shares the sampling, the runtime's duplicate console line is dropped while unrelated warnings and look-alike errors stay, and nothing is added for a page that never opted in.
  • check.test.ts still passes. bun run build and tsc --noEmit in cli pass; comment ratchet against feat(core,engine): report why blur is off, and what each render session did #5991's branch passes; every package is within its size budget.

🤖 Generated with Claude Code

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed exact head d5e218c7565b433df887c803fa4ad5de20c44b09 relative to b036deef790b8897bd6c805b94ff861182baec2a.

Audited probe-before-grid and suspend-to-plain-DOM order, severity/fixHint mapping, requested-root selection and console echo deduplication. Local authored mapping/page tests19/19 pass, including the GPU hint now requiring a separate/flattened render rather than an in-document subcomposition. Own delta has no additional demonstrated blocker; #5971's omitted animated hidden face remains invisible to this consumer.

Independent revision-bound review of the nine-PR composition. Earlier approvals/requests covered older heads. Current saved head/review/inline/check snapshot has no fresh duplicate finding and no failing/pending latest check. Stacked broad-suite skips are not executed tests.

Audited: CLI probe before grid audits, suspend to plain DOM, severity and fixHint mapping, requested-root choice and console warning deduplication.
Limits: Composed local focused run:196 authored core tests pass; separate WAAPI/CLI44 pass. Synthetic geometry/canvas controls, not fresh browser pixel/performance proof. No app/model/provider call, source fix, merge or release.

— Magi / desktop-review

Verdict: APPROVE
Reasoning: No additional blocker in this own delta. The later #5971 defect must be repaired before landing the complete stack.

Blur that turns itself off is silent in the output, so an author who asked for
data-motion-blur="on" cannot tell. Have hyperframes check read the runtime's
decision through probe() and the reason codes from the previous change.

check reports motion_blur_off as a warning with a fix hint for a root that
asked for blur and got none (an iframe in the root gets its own hint),
motion_blur_no_movers when nothing moves enough to blur, and
motion_blur_unverified when the check browser has no html-in-canvas to decide
with. The console echo of the same message is dropped so a finding is not
shown twice.

check asks the runtime which root wants blur instead of reading attributes
itself, so data-root="true" is honoured, and after probing it suspends blur
painting for the rest of the session: its audits read plain DOM, which removes
the roughly 10x slowdown of auditing a wrapped composition. It never sets the
page's off switch, which would change the probe's answer.

Tests drive a finding from the page to the check output, with its fix and
without its echo.

Folded review fixes: R9 (check hint), R12, R13 (check half), T6.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@vanceingalls
vanceingalls force-pushed the feat/capture-blur-report branch from b036dee to 7693556 Compare October 21, 2026 07:39
@vanceingalls
vanceingalls force-pushed the feat/capture-blur-check-findings branch from d5e218c to 1964007 Compare October 21, 2026 07:39

@miguel-heygen miguel-heygen left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed exact head 1964007049ed40416b05ff4e83412915b26398f3 against its actual parent 7693556e8860654d3b40dd99d238445b58996aee and the previously reviewed tree.

The restack changes only the inherited detector/test files relative to its previously reviewed tree; its CLI probe/suspend/finding implementation is unchanged. The repaired candidate scan therefore reaches the existing check consumer without a new consumer delta.

Independent verification: own-head and composed-tip synthetic computed-style controls 4/4 pass; predecessor witness remains red (inline positive passes). Exact-source authored detector suites run locally:31 own-head +47 tip tests pass, including WAAPI containment, named/multiple animations and cached-candidate retention. The computed animation-name seam is explicit because jsdom does not expand animation shorthand. These are deterministic detector controls, not fresh Chrome pixel/performance proof.

Current exact-head check snapshot has no failed or pending check. Read completed regression gate logs and executed #5991 preflight lint/format output; stacked broad-suite skips and aggregate gate success do not prove execution of the new pixel/unit suites. Author Chrome152 experiments, 26ms scan cost and package-budget margin remain attributed.

Known sampling limit remains: a short WAAPI-only face absent at every scan cannot enter the cached set. This bounded sampling residual differs from the repaired omission of ordinary animation-derived candidates; no universal detection guarantee is claimed. No new source blocker found in this successor composition. No browser/app/model call, merge or release.

— Magi / desktop-review

Verdict: APPROVE
Reasoning: The earlier animated-face candidate blocker is repaired and retained through the restacked composition; no additional blocking change was found.

This branch has not been deployed

No deployments
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.

2 participants