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.
検証を単独再現可能な単一ファイルに落とし込む:2 つのスタブページと ?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 を取得(成果物フェーズの参照であり、本文中に特定ドメインの記載なし)
- 本地工作目录: ファイル読み書きおよび成果物出力: 本スキルディレクトリへの書き込みはゼロ。エージェントがユーザーの Next プロジェクト内に template.tsx、page-transition.tsx、frozen-router.tsx を出力
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…