page-transition-animation
This skill should be used when the user asks to "animate page or route transitions", "add a page transition or crossfade between views", "animate route changes in Next.js App Router", "use the View Transitions API", "AnimatePresence exit doesn't fire on navigation", or "Framer Motion exit animation not working / exit animation before unmount in Next.js". Covers enter/exit page-transition animation with the View Transitions API and Framer Motion, for Next.js App Router and general SPA routing.
1实现原理 · 为什么它能做到
先讲清失败的结构性根因:App Router 导航会立刻换掉旧路由内容,而 AnimatePresence 只有在被移除的子元素仍挂载、且包裹层持续存在时才能跑 exit
The reason is structural — in the App Router, when navigating, Next.js unmounts the old route's content and mounts the new one almost immediately.
方案 A 等于 template.tsx(每次导航重挂载)加 pathname 作 key 的 AnimatePresence 加 FrozenRouter(快照 LayoutRouterContext 让旧树继续渲旧内容)
const frozen = useRef(context).current;
方案 B 等于原生 View Transitions API(::view-transition-old/new 动画加 document.startViewTransition 包裹 router.push),或用 next-view-transitions 库开箱接入
::view-transition-old(root) { animation: fade 0.25s both reverse; }
崩溃排查写成有序清单(7 条),覆盖包裹层位置、key、直接 motion 后代、mode="wait"、FrozenRouter、'use client'、单子元素
**Stable, changing key.** The animated child needs `key={pathname}` (or similar) so removal is detected.
验收降级为可独立复现的单文件:用两个 stub 页面加 ?view=/phase= 冻结过渡阶段,先把转场形状从 Next 工程里剥离出来验证
One file is the right tier for validating motion before wiring the router; don't stand up Next just to eyeball a fade.
2核心能力
3外部依赖
| Kind | Dependency / Endpoint |
|---|---|
| package | framer-motion(AnimatePresence 与 motion,配合 template.tsx 与 FrozenRouter) |
| package | next-view-transitions(把 View Transitions 接进 App Router 客户端导航) |
| api | Next.js 内部模块 LayoutRouterContext(next/dist/shared/lib/app-router-context.shared-runtime)与 usePathname |
| api | 浏览器原生 View Transitions API(document.startViewTransition、::view-transition-old/new、view-transition-name) |
| network | 交付页从 CDN 取 motion 与 React(产物期引用,不判级;正文未点名具体域) |
| cli | npx / Playwright(宿主侧截图工具)与仓库根 scripts/ 助手(seek-shot.sh、contact-sheet.sh 依赖 ffmpeg) |
4管控建议与判定依据
- 网络端点: 声明外部网络访问: 执行期零外发;交付页从 CDN 取 motion 与 React(产物期引用,正文未点名域)
- 本地工作目录: 文件读写与工件输出: 本 skill 目录零写盘;由 agent 在用户 Next 工程写 template.tsx、page-transition.tsx、frozen-
5第二遍独立确认
- [discrepancy] description 声称的覆盖范围(Next.js App Router 与 general SPA routing)与正文实际覆盖面是否相符 — frontmatter 写 ... for Next.js App Router and general SPA routing.,但正文主体(根因分析、方案 A 的三个文件、7 条排查清单)全部是 App Router 专属;general SPA 只在 View Transitions API 与交付用 stub HTML 两处被顺带覆盖,既无 React Router/Remix 等通用 SPA 路由的接线,也无对应排查清单。属描述略宽于实现(非虚假,但按 description 期望通用方案会落空)。
- [ok] FrozenRouter 依赖的 Next 内部 import 路径真实性 — SKILL.md 给出 import { LayoutRouterContext } from 'next/dist/shared/lib/app-router-context.shared-runtime'; 并在正文、notes、gotchas、references 四处重复提示 internal、跨版本可能变,references 还专列 FrozenRouter import note across versions 一节;即文档自己对该脆弱性做了标注,非隐瞒。
- [ok] View Transitions 验收的可行性(快照是瞬态) — 正文承认 snapshots are transient,并给出替代(截结束态或用 emulate slow animations),验收步骤不依赖捕捉瞬态帧;startViewTransition 的能力守卫在正文与完成前清单第 1 条都要求。
- [discrepancy] Packaged helper 的路径基准与语义 — SKILL.md 的 verify 段仍贴 scripts/seek-shot.sh anim.html 0 1.5 3(时间冻结、仓库根路径),但本 skill 的冻结参数是 ?view= 与 ?phase=(状态与相位),helper 不匹配;scripts/ 也在仓库根而非本 skill 目录。
6结论
083d4f27aaf44464…