首页 / 全部技能 / 设计 / page-transition-animation
设计 · iart-ai/web-animation-skills

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.

L3 联网 · 声明域名与密钥范围V1 已固定联网读写文件Dual-pass Audit
Author iart-aiGitHub iart-ai/web-animation-skills ↗Stars 28License MIT(仓库根 LICENSE 为 MIT License, Copyright (c) 2026 iart.ai;.claude-plugin/plugin.json 的 license 字段同为 MIT)Commit b6dba3eb75
管控等级描述 skill 的能力与建议配套的管控措施,不代表质量或安全认证,也不表示可用或不可用。是否使用由用户和管理者决定。不同 agent 宿主对权限的约束各不相同,请勿假定宿主一定会提供安全兜底。第三方 skill 版权归原作者,使用风险由使用者自行承担。

1实现原理 · 为什么它能做到

先讲清失败的结构性根因:App Router 导航会立刻换掉旧路由内容,而 AnimatePresence 只有在被移除的子元素仍挂载、且包裹层持续存在时才能跑 exit

skills/page-transition-animation/SKILL.md
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.
把三个必要条件写死:包裹层常驻、child key 随路由变化、退出期间旧子树仍需渲染旧内容。

方案 A 等于 template.tsx(每次导航重挂载)加 pathname 作 key 的 AnimatePresence 加 FrozenRouter(快照 LayoutRouterContext 让旧树继续渲旧内容)

skills/page-transition-animation/SKILL.md
const frozen = useRef(context).current;
给出三个文件的完整代码(template.tsx、page-transition.tsx、frozen-router.tsx)与各参数作用(mode="wait"、initial={false})。

方案 B 等于原生 View Transitions API(::view-transition-old/new 动画加 document.startViewTransition 包裹 router.push),或用 next-view-transitions 库开箱接入

skills/page-transition-animation/SKILL.md
::view-transition-old(root) { animation: fade 0.25s both reverse; }
明确选型:简单淡入或形变走 View Transitions,需要细粒度编排与可打断退场走 Framer Motion;并强制 startViewTransition 能力守卫。

崩溃排查写成有序清单(7 条),覆盖包裹层位置、key、直接 motion 后代、mode="wait"、FrozenRouter、'use client'、单子元素

skills/page-transition-animation/SKILL.md
**Stable, changing key.** The animated child needs `key={pathname}` (or similar) so removal is detected.
把 exit 不触发这一现象拆成可逐条排除的清单,而不是散落的技巧。

验收降级为可独立复现的单文件:用两个 stub 页面加 ?view=/phase= 冻结过渡阶段,先把转场形状从 Next 工程里剥离出来验证

skills/page-transition-animation/SKILL.md
One file is the right tier for validating motion before wiring the router; don't stand up Next just to eyeball a fade.
点明 View Transitions 的快照是瞬态,截图应取结束态(或借助慢速动画模拟)。

2核心能力

01App Router 逐路由入场(template.tsx 每次导航重挂载)
02路由退场动画(pathname 作 key 的 AnimatePresence 加 FrozenRouter 防内容闪替)
03原生 View Transitions 接入(CSS 伪元素加 startViewTransition 守卫包装 router.push)
04next-view-transitions 的一处接入(layout 包 ViewTransitions,并改用其 Link)
05AnimatePresence 不触发的 7 条排查清单
06方向性滑动、交叉淡入、共享元素与 loading.tsx 过渡等变体
07过渡阶段冻结 harness(?view=b 与 ?phase=exit)
08零 build 交付(先用单 HTML 两个 stub 页面验证转场,不必为看一眼淡入而搭 Next)
09可访问性判据:reduced-motion 下把滑动位移降级为短交叉淡入

3外部依赖

KindDependency / Endpoint
packageframer-motion(AnimatePresence 与 motion,配合 template.tsx 与 FrozenRouter)
packagenext-view-transitions(把 View Transitions 接进 App Router 客户端导航)
apiNext.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(产物期引用,不判级;正文未点名具体域)
clinpx / Playwright(宿主侧截图工具)与仓库根 scripts/ 助手(seek-shot.sh、contact-sheet.sh 依赖 ffmpeg)

4管控建议与判定依据

建议配套管控措施
面向 Agent
声明可访问域名与密钥范围
面向管理者
密钥最小权限,保留请求日志
判定依据(文件路径与关键语句摘要)
  • 网络端点: 声明外部网络访问: 执行期零外发;交付页从 CDN 取 motion 与 React(产物期引用,正文未点名域)
  • 本地工作目录: 文件读写与工件输出: 本 skill 目录零写盘;由 agent 在用户 Next 工程写 template.tsx、page-transition.tsx、frozen-
审计说明: 。判级只依据 skill 自身目录(skills/page-transition-animation/ = SKILL.md + 0 字节 README.md + references/full-examples.md,find 全量核对):零脚本、零凭证、零写盘、执行期零外发(token 扫描 fetch(/XMLHttpRequest/curl/wget/child_process/process.env/API_KEY|TOKEN|SECRET/.env/eval( 零命中)。正文点名的 CDN(motion 与 React,未点名域)出现在输出契约里,属产物期引用,按批4 口径不判级;对 Next 内部模块的 import 属工程依赖(由用户工程安装),非本 skill 外发。

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结论

  • 把最常见的 exit 不触发写成结构性根因与三个必需条件,而不是零散技巧
  • 两个方案都落到可抄代码(三个 tsx 文件、CSS 伪元素加守卫包装),并给选型判据
  • 对照料足:references 给完整目录布局、方向性变体、共享元素、loading.tsx 与决策表
  • 对自身脆弱点诚实:Next 内部 import 路径在多处被显式标记为版本敏感
  • 适合: 适合:① Next.js App Router 项目要做页面与路由进出场(尤其 exit 一直不触发、旧页瞬间消失的现场);② 需要判断该用 Framer Motion 还是 View Transitions 的团队;③ 需要共享元素(view-transition-name)或方向性滑动转场;④ 想先把转场曲线在单文件里验证、再回工程接线。
    不适合: 不适合:① 非 Next 的通用 SPA 路由(description 提及但正文无具体接线,需自行补);② 只需要页面内元素微交互(走 micro-interaction);③ 不接受依赖框架内部私有路径的项目(FrozenRouter 方案有升级风险,应改用 View Transitions);④ 需要浏览器全覆盖的无守卫实现(View Transitions 支持面不齐,必须带 fallback)。
    Install Agent-Ready
    ① Verified Mirror 2026-09-28
    Option A · Direct DownloadDownload page-transition-animation.tar.gz
    sha256: 083d4f27aaf44464…
    Option B · Copy Guide for Agent
    install.json
    agent 读 JSON 指南后会自动从本站下载安装,无需更多说明。
    ② Upstream GitHub
    GitHub Repo ↗
    Pinned to commit b6dba3eb75.