fix(paint): include box-shadow and descendant ink in the layer bounds - #223
Merged
LeadcodeDev merged 1 commit intoSep 22, 2026
Merged
Conversation
LeadcodeDev
force-pushed
the
fix/layer-bounds-outset-shadow
branch
from
September 21, 2026 23:39
baafd53 to
7c9e21a
Compare
53 tasks
LeadcodeDev
force-pushed
the
fix/layer-bounds-outset-shadow
branch
2 times, most recently
from
September 22, 2026 08:33
ee0e0e8 to
6890377
Compare
bleed is derived only from node.css.filter (FilterFn::Blur / DropShadow in filter_bleed, line 610). It ignores the node's own box_shadow, which step 5 paints *inside* this layer (line 411-418) at layout.x + dx - spread, width + spread*2 — i.e. outside the border-box — and it ignores the whole subtree painted at steps 9-10, which with the default overflow: visible may legitimately extend past the parent box (absolutely-positioned children, a child's own scale/pulse transform, a child glow, marquee, which CLAUDE.md explicitly documents as "exempté (leur rôle est de bleed)"). The file's own comment on filter_bleed (line 605-609) states the rule: "a *too-tight* one would silently clip filter bleed, trading a perf bug for a correctness one". Concretely: a card with box-shadow: 0 20px 40px rgba(0,0,0,.5) loses its shadow the moment any fade_in drives opacity below 1.0, and regains it on the frame opacity reaches 1.0 — a visible pop mid-entrance. The repo already treats this exact invariant as load-bearing for overflow: hidden (test overflow_hidden_does_not_clip_own_outset_box_shadow, line 2909); the opacity layer violates it for the same shadow. Fix: Compute the layer bounds from the union of: the border-box, the filter bleed, the outset box_shadow extents (|offset| + blur*1.5 + spread per shadow), and — when overflow is visible — the descendants' layout union. Alternatively move the outset box-shadow painting outside the opacity layer and multiply its paint alpha by opacity, and fall back to an unbounded layer when overflow: visible and children exist. Refs #220
LeadcodeDev
force-pushed
the
fix/layer-bounds-outset-shadow
branch
from
September 22, 2026 08:43
6890377 to
7aa0de5
Compare
LeadcodeDev
added a commit
that referenced
this pull request
Sep 22, 2026
…#223) bleed is derived only from node.css.filter (FilterFn::Blur / DropShadow in filter_bleed, line 610). It ignores the node's own box_shadow, which step 5 paints *inside* this layer (line 411-418) at layout.x + dx - spread, width + spread*2 — i.e. outside the border-box — and it ignores the whole subtree painted at steps 9-10, which with the default overflow: visible may legitimately extend past the parent box (absolutely-positioned children, a child's own scale/pulse transform, a child glow, marquee, which CLAUDE.md explicitly documents as "exempté (leur rôle est de bleed)"). The file's own comment on filter_bleed (line 605-609) states the rule: "a *too-tight* one would silently clip filter bleed, trading a perf bug for a correctness one". Concretely: a card with box-shadow: 0 20px 40px rgba(0,0,0,.5) loses its shadow the moment any fade_in drives opacity below 1.0, and regains it on the frame opacity reaches 1.0 — a visible pop mid-entrance. The repo already treats this exact invariant as load-bearing for overflow: hidden (test overflow_hidden_does_not_clip_own_outset_box_shadow, line 2909); the opacity layer violates it for the same shadow. Fix: Compute the layer bounds from the union of: the border-box, the filter bleed, the outset box_shadow extents (|offset| + blur*1.5 + spread per shadow), and — when overflow is visible — the descendants' layout union. Alternatively move the outset box-shadow painting outside the opacity layer and multiply its paint alpha by opacity, and fall back to an unbounded layer when overflow: visible and children exist. Refs #220
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Severity High, category correctness. Location:
crates/rustmotion-core/src/engine/paint_pass.rs:390Impact
bleedis derived only fromnode.css.filter(FilterFn::Blur / DropShadow infilter_bleed, line 610). It ignores the node's ownbox_shadow, which step 5 paints inside this layer (line 411-418) atlayout.x + dx - spread, width + spread*2— i.e. outside the border-box — and it ignores the whole subtree painted at steps 9-10, which with the defaultoverflow: visiblemay legitimately extend past the parent box (absolutely-positioned children, a child's own scale/pulse transform, a child glow,marquee, which CLAUDE.md explicitly documents as "exempté (leur rôle est de bleed)"). The file's own comment onfilter_bleed(line 605-609) states the rule: "a too-tight one would silently clip filter bleed, trading a perf bug for a correctness one". Concretely: a card withbox-shadow: 0 20px 40px rgba(0,0,0,.5)loses its shadow the moment anyfade_indrivesopacitybelow 1.0, and regains it on the frame opacity reaches 1.0 — a visible pop mid-entrance. The repo already treats this exact invariant as load-bearing foroverflow: hidden(testoverflow_hidden_does_not_clip_own_outset_box_shadow, line 2909); the opacity layer violates it for the same shadow.Fix
Compute the layer bounds from the union of: the border-box, the
filterbleed, the outsetbox_shadowextents (|offset| + blur*1.5 + spreadper shadow), and — whenoverflowisvisible— the descendants' layout union. Alternatively move the outset box-shadow painting outside the opacity layer and multiply its paint alpha byopacity, and fall back to an unbounded layer whenoverflow: visibleand children exist.Evidence the audit read
Part of the September 2026 audit remediation chantier. Refs #220 (RM-01).