plans/issues/issue-2491.md
Executor instructions: Verification + bookkeeping plan. The only code artifact is an optional demonstration fixture used to confirm the diagnosis — it must NOT be committed unless Step 2's diagnosis is confirmed AND the maintainer wants the fixture kept. Honor the approval gate. When done, update this issue's row in
plans/issues/README.md.Drift check (run first):
gh api repos/motiondivision/motion/issues/2491 --jq .state→open.git diff --stat 42bfbe3ed..HEAD -- packages/motion-dom/src/projection→ if large drift, re-verify the diagnosis below.
42bfbe3ed, 2026-06-1142bfbe3ed)Report: moving a layoutId element into/out of a parent with
overflow: scroll|hidden, the element "immediately disappears and doesn't
appear again until it's inside the destination element". Repro sandbox
(codesandbox zqvzdy) and the related x.com link from the 2025-11-15 comment
are both inaccessible to automation at planning time (Cloudflare 403) — but no
repro is needed to diagnose this one, because it is geometric:
transform (projection delta
applied in packages/motion-dom/src/projection/node/create-projection-node.ts;
the lead/follow promotion machinery is in
packages/motion-dom/src/projection/node/state.ts and the crossfade in
create-projection-node.ts's animationValues handling).overflow: hidden|scroll|auto on an ancestor clips descendants
including their transformed positions. While the new element is
transformed to the old container's coordinates, it is outside its own
clipping ancestor's box → fully clipped → "disappears until it's inside the
destination element". The same applies in reverse when leaving a clipped
container. No projection-side change can paint outside an ancestor's clip;
the only general solutions are reparenting to an unclipped layer (portal /
top layer) — which is the View Transitions model, available in this repo as
animateView() (packages/motion-dom/src/view/index.ts) — or
removing the clip during the transition.Workarounds to give the reporter:
overflow: visible while
animating, restore on onLayoutAnimationComplete).animateView() for cross-container moves —
snapshots paint in the browser's top layer and are not ancestor-clipped.Create a throwaway page (do not commit): two stacked containers with
overflow: hidden, a layoutId="box" element conditionally rendered in one
or the other, 2s linear layout transition. Confirm in the browser
(dev/react Vite app, see CLAUDE.md commands) that the element is invisible
while its transform places it outside its current parent, and that setting the
containers to overflow: visible makes the same transition fully visible.
If the element is invisible even with overflow: visible — the diagnosis
is wrong (possibly a visibility lead/follow bug); STOP and report, this
becomes a FIX investigation instead.
Recommend wontfix-with-guidance. Only act once this plan's row in
plans/issues/README.md is APPROVED-CLOSE. If the maintainer instead wants
a feature (e.g. opt-in portal escape for shared transitions), that is a new
feature plan — report back, do not improvise one.
Post a comment explaining the clipping geometry (Diagnosis above, in
user-facing words), the three workarounds, and that cross-container moves are
exactly what animateView()/View Transitions solve. Then:
gh api -X PATCH repos/motiondivision/motion/issues/2491 -f state=closed -f state_reason=not_planned
Verify: gh api repos/motiondivision/motion/issues/2491 --jq .state → closed.
git status clean)not_planned (only behind APPROVED-CLOSE)plans/issues/README.md row updatedAPPROVED-CLOSE.