From dfea19cdaa30f6552cbc539517aec464284b7e7d Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Fri, 23 Oct 2026 12:47:39 -0700 Subject: [PATCH] fix(core): a hidden child of a mover stays out of the blur trail The isolation CSS re-showed every descendant of a mover, so a child the author hid with visibility:hidden was cropped and smeared into the trail (240 green px in the repro; 0 in the sharp frame). The hide rule now skips the mover subtree and the mover alone is made visible, so its descendants inherit and keep their own visibility. Found by review of #6106. Co-Authored-By: Claude Sonnet 5.5 --- .../core/src/runtime/captureMotionBlur/index.ts | 4 ++-- .../captureMotionBlur.pixels.browser.test.ts | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/core/src/runtime/captureMotionBlur/index.ts b/packages/core/src/runtime/captureMotionBlur/index.ts index 460effbf72f..65a087247f0 100644 --- a/packages/core/src/runtime/captureMotionBlur/index.ts +++ b/packages/core/src/runtime/captureMotionBlur/index.ts @@ -182,8 +182,8 @@ function createInstance(host: CaptureMotionBlurHost, config: Config, form: HtmlI `[${HIDE_ATTR}] { opacity: 0 !important; }`, // The root stays visible: a rotated or scaled mover under a hidden root is captured at the origin, untransformed. `[${ONLY_ATTR}] { background: none !important; border-color: transparent !important; box-shadow: none !important; outline-color: transparent !important; }`, - `[${ONLY_ATTR}]::before, [${ONLY_ATTR}]::after, [${ONLY_ATTR}] * { visibility: hidden !important; }`, - `[${ONLY_ATTR}] [${MOVER_ATTR}], [${ONLY_ATTR}] [${MOVER_ATTR}] * { visibility: visible !important; }`, + `[${ONLY_ATTR}]::before, [${ONLY_ATTR}]::after, [${ONLY_ATTR}] *:not([${MOVER_ATTR}], [${MOVER_ATTR}] *) { visibility: hidden !important; }`, + `[${ONLY_ATTR}] [${MOVER_ATTR}] { visibility: visible !important; }`, ].join("\n"); let movers: HTMLElement[] = []; diff --git a/packages/engine/src/services/captureMotionBlur.pixels.browser.test.ts b/packages/engine/src/services/captureMotionBlur.pixels.browser.test.ts index c7dc0667a2d..7566ad1b5d6 100644 --- a/packages/engine/src/services/captureMotionBlur.pixels.browser.test.ts +++ b/packages/engine/src/services/captureMotionBlur.pixels.browser.test.ts @@ -268,6 +268,21 @@ describe.skipIf(!hasBrowser)("capture motion blur pixels in Chrome", () => { }, ); + it("keeps a visibility:hidden child of a mover out of the trail", async (ctx) => { + if (!supported) ctx.skip(); + const body = `
`; + const blurred = await frameOf(body, true, FRAME, "capture"); + expect(blurred.report).toMatchObject({ state: "on", tier: "capture", movers: 1 }); + let green = 0; + for (let y = 0; y < H; y++) { + for (let x = 0; x < W; x++) { + const [r = 0, g = 0, b = 0] = px(blurred.frame, x, y); + if (g - r > 30 && g - b > 30) green++; + } + } + expect(green).toBe(0); + }); + it("blurs with filters where capture cannot run, over a page that has a WebGL canvas", async (ctx) => { if (!supported) ctx.skip(); const gl = ``;