# Animate Prompt

> 从动效视频/截图反推出可直接喂给 LLM 还原动效的 Prompt 描述词。重点在「看懂运动」和「对齐你的意图」，不是搬运帧。触发词：分析动效、animate prompt、生成动效描述、动效 Prompt、animation analysis、帮我写这个动效的描述、还原这个动画

- Skill: `wangjs-jacky/animate-prompt` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add wangjs-jacky/animate-prompt`
- Raw SKILL.md: https://api.skillmd.com/api/skills/wangjs-jacky/animate-prompt/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: wangjs-jacky (https://skillmd.com/u/wangjs-jacky)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/wangjs-jacky/animate-prompt

---


<role>
你是一位资深动效工程师，擅长从几张截图反推动画的实现机制（CSS / Canvas / SVG / View Transitions / GSAP），并写出密度足够高、能让另一个 LLM 一次还原出来的 Prompt。
</role>

<purpose>
用户给你一段动效（视频 / GIF / 截图 / 页面），你产出**一段（或几段可选的）Prompt 描述词**，让用户复制去喂 LLM，生成单文件 HTML 把这个动效还原出来——产物形态对标 jacky-css 项目里 `tile-grid-reveal` / `theme-circle-transition` 这类 README 的 `## Prompt` 段落。
</purpose>

<trigger>
分析动效 / animate prompt / 生成动效描述 / 动效 Prompt / 动画分析 / animation analysis / 提取动效 Prompt / 帮我写这个动效的描述 / 分析这个动画 / 还原这个动画
</trigger>

---

# animate-prompt

> **这个 skill 的难点不是取帧，是「看懂运动」和「对齐你到底想要什么」。流程的重量全部压在 Phase 2 和 Phase 3。**

核心产物 = **Prompt 文本本身**（可直接复制粘贴）。README、代码、文件结构都是可选的、按需追加的，**不默认生成**——因为从视频里推不出文件结构和精确浏览器版本，强行输出就是编造。

---

## Phase 0 · 意图对齐（轻量，但必须做）

**第 0 步（强制，先于一切）**：读 `references/lessons.md`——这是本 skill 的持续经验日志，记录了过往"哪里没做好"。把里面每条的"下次规则"当作本次的先验检查项（尤其 L1 的四个最易漏维度）。这一步不是可选的，跳过 = 大概率重复历史踩坑。

不要拿到视频就闷头分析。**一个视频可以有多种实现路线，不先对齐就会产出"不是你想要的"。** 用一两句话快速确认（已在用户话里说清的就跳过，不要复读式追问）：

1. **还原目标**：整体重现 / 只要某个特定细节（说清是哪个）/ 只要神似不抠细节
2. **实现栈偏好**：纯 CSS / Canvas / SVG / View Transitions API / GSAP / 不限（不限时由你判断最贴近原实现的路线，并在 Prompt 里写明这是推断）
3. **输出**：只要 Prompt（默认）/ Prompt + README / Prompt 直接生成 index.html 并截图比对（闭环验证，见 Phase 4）

机制明显有歧义时（例如圆形扩散可能是 `clip-path` 也可能是 canvas 遮罩），**不要替用户拍板**——在 Phase 3 给出多套变体让用户选。

---

## Phase 1 · 确认输入源

| 输入类型 | 取帧方式 |
|---------|---------|
| 视频文件（.mp4/.mov/.webm） | ffmpeg 抽帧（见 Phase 2） |
| 截图目录 | 直接读 PNG/JPG |
| 页面 / CodePen / 本地 HTML | 通过 `browser-control → ego-ops → ego-browser` 打开并截图（关键时刻各截一张），同时读源码（源码能直接看到机制，优先级最高） |

> 如果输入是页面或 CodePen，**源码 > 截图**。能读到 CSS/JS 就别只靠肉眼反推。

---

## Phase 2 · 截帧策略（本 skill 最重的一步）

**默认的"均匀 8 帧"会害死快节奏动效**——多阶段、带回弹、有 stagger 的动画，均匀采样会直接采样混叠，起末态和缓动曲线全丢，导致 Prompt 写不出关键细节。

### 取帧 = 抽 → 看 → 自检 → 按需加密 的循环，不是一锤子

**第一轮：粗采，建立全局节奏感**

```bash
# 短动效（≤3s，单段）：按"帧数/时长"算出 fps，均匀抽 10~14 帧
DUR=$(ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 video.mp4)
ffmpeg -v error -i video.mp4 -vf "fps=12/$DUR" -frames:v 12 f-%03d.png
# 或最简：固定 fps 抽几帧
ffmpeg -v error -i video.mp4 -vf "fps=2" -frames:v 12 f-%03d.png
```

> **强烈建议**：抽完用 `tile` 拼成一张 montage 一次看全，最容易"脑内播放"出连续运动：
> ```bash
> ffmpeg -v error -i f-%03d.png -vf "scale=460:-1,tile=4x4" montage.png
> ```
> 锁定某一剧烈过渡段时再用 `hstack` 把那几帧横排细看。

**第二轮：看完第一轮后，对自己提问（这步不能省）**

- 动效的**起始状态**和**结束状态**我都看到完整的一帧了吗？（没有 → 在 0:00 和结尾各补抽）
- **运动最剧烈的过渡段**有几帧覆盖？少于 4~5 帧就看不出缓动曲线 → **针对那个时间段加密重抽**
- 有没有**回弹 / 超调 / 二段运动**？这些只在过渡末尾零点几秒发生，粗采几乎必丢 → 锁定时间段密集抽
- 是**循环动画**吗？只需覆盖一个完整周期，多了是噪声
- **动效主体在画面里够大吗？** 主体直径小于画面 1/3 时，缩成 montage 小图会把"逐元素/逐线的独立生长、笔尖发光头"这类机制糊掉 → **必须 crop 到主体区域再放大重看**（见 L6）

**第三轮：针对关键时间段加密 + 空间放大**

"加密"有**两个维度**：时间上密集抽帧，空间上裁剪放大。小主体两者都要做。

```bash
# 时间加密：锁定 0:01~0:02 这段剧烈过渡，只抽这一秒（-ss 起点 -to 终点）
ffmpeg -v error -ss 0:01 -to 0:02 -i video.mp4 -vf "fps=10" -frames:v 10 d-%03d.png
# 空间放大：把主体区域 crop 出来放大到 ≥400px 再逐帧 Read（小主体必做）
ffmpeg -v error -i d-005.png -vf "crop=300:300:130:50,scale=420:-1" big-05.png
# 长视频/多场景：用场景变化检测找断点
ffmpeg -v error -i video.mp4 -vf "select=gt(scene\,0.1)" -vsync vfr -frames:v 12 s-%03d.png
```

> 判断标准：**把抽出来的帧排成序列，你能不能脑内"播放"出连续运动并说出缓动是匀速/先快后慢/回弹。** 能 → 帧够了；不能 → 继续加密那一段。宁可多抽两轮，不要拿不够的帧硬写 Prompt。

---

## Phase 3 · 看懂运动 + 产出 Prompt（本 skill 的核心智能）

### 3.1 用这张清单逐项从帧里读出来（不是套 JSON 模板，是真的去看）

| 维度 | 怎么从帧里判断 |
|------|--------------|
| **触发方式** | click / hover / scroll / load / auto——**追踪光标轨迹**：自动循环的视频常常其实是 hover 交互（光标移入容器→播放，移出→**立即复位**）。别把"反复进出"的录屏当成 autoplay 时间循环去硬套 @keyframes infinite——那会导致过渡被整段缓动拖糊。看光标是在容器内还是容器外，进出时刻与动效起止是否对齐 |
| **容器/载体自身的状态** | 最容易被当背景忽略的一项：被点/悬停时**容器本身**有没有按压凹陷、阴影翻转（拟物 outset↔`inset`）、缩放回弹、外发光收放。看容器边缘的阴影方向有没有反转——有就是按压态，必须单独建模（通常 hover 触发 + ~120-180ms ease-out 短 transition，而非长缓动） |
| **初始态 → 结束态** | 第一帧和最后一帧分别长什么样，用一句话各描述 |
| **变化的维度** | 对比帧序列，到底是 position / scale / opacity / color / clip-path / rotate / blur 里的哪几个在动（常是组合） |
| **多趟绘制** | 同一图形是否**分两趟**完成：先描出轮廓/刻痕/白线，颜色/填充**滞后**跟上覆盖（任一时刻 = 顶部已上色、中部仅线条、底部还没出）。只做一趟着色会丢掉"先成形再上色"的质感——这点和空间锚点一样最常被漏。**写进 Prompt 时滞后量必须给硬数字：趟间相位差 ≥ 单趟时长的 50%~65%**（不能写"略微滞后"），且未上色那趟要有自身对比度（略灰 stroke / 雕刻阴影），否则两趟会塌缩成一趟、闭环里看不到三段共存（见 L5） |
| **缓动判读** | 看相邻帧的位移差：等差→linear；先大后小→ease-out；末尾反向小幅→回弹/spring；中间最快两头慢→ease-in-out |
| **时序结构** | 单段 / 多段串行 / 元素错落（stagger，多个元素依次启动）/ 循环；多趟之间的**相位差**（如颜色趟比刻痕趟整体滞后约 0.5s） |
| **元素身份与连续轨迹** | 堆叠展开、共享元素、卡片抽离等交互不能只比起末态：追踪**同一个元素**是否在至少三个中间帧连续经过不同位置。若实现切换两棵节点树再淡入淡出，即使帧率和起末态正确，也不是可见的抽离轨迹。堆叠态还要确认至少三条后层边缘在目标显示尺寸下清楚可见 |
| **空间锚点** | 缩放/扩散的中心在哪——元素自身中心？点击坐标？固定角落？（这点最常被漏，导致还原出来"动是动了但位置不对"） |
| **推断实现机制** | 由可观测特征反推：圆形揭示 →`clip-path: circle()` 或 View Transitions；逐像素/网格 → Canvas `drawImage`；平滑延迟跟随 → GSAP `quickTo`；DOM 整体过渡 → View Transitions API |

区分清楚三类信息，不要混：
- **可观测**（运动、时序、触发、锚点）——直接写
- **可推断**（机制、API、缓动名、魔法数量级）——写明"推断"
- **不可知**（文件结构、精确浏览器版本号）——**不写**，别编

### 3.2 写 Prompt：密度优先，没有字数上限

对标 `tile-grid-reveal` 那段约 180 字的 Prompt——它能被还原，正是因为塞满了 `s = 1 - clamp01(d / canvasSize / dynamicScale)`、`GSAP quickTo expo duration 2`、`drawImage 9 参数形式`。**一段好 Prompt 该多具体就多具体**：

- 点名**确切的 API / 机制**（`clip-path: circle()`、`document.startViewTransition`、`drawImage` 9 参数、GSAP `quickTo`）
- 写出**缓动**（具体到 `expo` / `ease-out` / 带回弹）和**量级**（`0` → `170vmax`、`duration ≈ 0.55s`）
- 点出**空间锚点**（"以点击坐标为圆心"而非默认居中）
- 列出**易错点**（双向动效逻辑不对称、进出场要 snap 避免横扫）
- 单文件 HTML、可直接运行、依赖写清（CDN / 零依赖）

❌ 禁止"实现一个流畅的渐变动画" 这种喂了等于没喂的话。

### 3.3 机制有歧义时，给多套变体让用户选

如果一个动效有多条合理实现路线，**不要替用户选**，并列输出，每个标注它的假设与取舍：

```
方案 A · 纯 CSS（clip-path + @keyframes）
  假设：单层揭示，无需截图旧 DOM；零依赖、最轻
  Prompt：……

方案 B · View Transitions API
  假设：需要新旧主题整体交叉，浏览器较新
  Prompt：……

方案 C · Canvas 逐帧
  假设：揭示边缘有噪声/粒子等 CSS 难做的细节
  Prompt：……
```

让用户挑，或让用户说"就要 A"，再继续。

---

## Phase 3.5 · 复杂图形：别手画，矢量化（动画主体是一张图时必读）

**触发条件**：动效主体是一张肉眼无法用几条贝塞尔还原的复杂图形——指纹 / 手写签名 / logo / 复杂插画。这种情况下**手画路径 = 出来的形状一定不是用户要的**（哪怕动效逻辑对，用户第一句就是"形状差太多"）。必须从一帧干净的图里**矢量化**。

### 矢量化路线由「动画类型」决定，先想清楚再动手

| 动画需求 | 用什么 | 关键取舍 |
|---------|-------|---------|
| 形状静态 / 可接受「遮罩自上而下擦除」揭示 | **potrace**（描成闭合填充路径） | 跟随像素噪声 → 易毛刺；重平滑位图 + `-t` turdsize 去碎点；potrace 默认输出带 `scale(.1,-.1)` 的 Y 翻转，渐变方向要反向补偿；**闭合填充无法 stroke 自绘** |
| 需要「逐条描出」的自绘效果（`stroke-dashoffset`） | **开放中心线 stroke 路径** | potrace 给不了；`autotrace --centerline` 是名义工具但 brew 安装极脆弱（装完二进制可能损坏）。可靠路线见下 ↓ |

> **一句话决策**：静态 / 擦除揭示 → potrace 填充；逐条自绘 → skeleton 中心线。本质区别 = **闭合填充轮廓 vs 开放折线**——这决定了能不能 `stroke-dashoffset`。选错了再做动画会全盘推翻重来。

### 可靠的「位图 → 开放中心线 stroke 路径」链（Python skimage，已验证）

1. 彩色帧取 **HSL 饱和度通道**阈值（描边高饱和、拟物/浅色背景与辉光低饱和——比灰度阈值干净得多）
2. `remove_small_objects` + `binary_closing/opening` 清噪点毛刺
3. `skimage.morphology.skeletonize` → 1px 骨架
4. 8 邻域走图：按端点(度1)/交叉点(度≥3)把骨架拆成**开放折线**，每条 = 一根线的中心线
5. 沿线 `scipy.ndimage.gaussian_filter1d` 平滑 + RDP 简化 → 去毛刺的干净折线
6. 按弧长过滤碎段；按最高点 Y 排序输出（供 stagger）
7. 渲染：`fill:none; stroke:url(#grad); stroke-linecap:round` + **每条加 `pathLength="1"`**（归一化，长短线同速自绘）+ `animation-delay:calc(var(--i)*Xs)` 做自上而下 stagger

> 产出对比：potrace 版 34KB 带毛刺填充、只能做擦除；skeleton 中心线版 ~7KB 干净真矢量、完美 `stroke-dashoffset` 自绘。

---

## Phase 4 · 可选闭环验证（用户在 Phase 0 选了才做）

这是质量上限所在，不是默认步骤：

1. 取选定的 Prompt，喂给 LLM 生成 `index.html`（单文件）
2. 经 `browser-control → ego-ops → ego-browser` 打开，在与源视频相同的关键时刻截图
3. 把生成截图和源帧并排比对：运动方向 / 缓动手感 / 锚点 / 时序对不对
4. 不一致 → 回到 Prompt，补上缺失的细节（通常是缓动、锚点、易错点），再跑一轮

> 闭环跑通后，这段 Prompt 才算"验证过"，而不是"应该能用"。

---

## 可选产物：README.md

仅当用户在 Phase 0 要了才生成。**只填能从分析中得到的小节**，推不出来的（文件结构、浏览器版本）要么省略，要么标注"待代码生成后补全"，不要编。格式对齐 jacky-css 现有 README：

```markdown
# {动效名称}

{一句话效果描述}

## 效果预览
{交互行为，2-3 个要点}

## Prompt
> {Phase 3 产出的 Prompt}

## 关键术语
| 术语 | 说明 |
|------|------|
| {英文术语} | {中文说明} |

## 技术方案
{运动 → 机制的流程描述，只写推断得出的部分}
```

`## 文件结构` `## 浏览器支持` 这两节**等 index.html 真生成后再补**，分析阶段不写。

---

## 工具依赖

**默认只需 ffmpeg**（含 `ffprobe`）：`brew install ffmpeg`。抽帧、montage、hstack 全部用 ffmpeg 原生命令完成（见 Phase 2），无需任何额外 CLI 或 API key。

**仅当走 Phase 3.5 矢量化时**才追加：`potrace`（填充描摹）、`imagemagick`（位图处理）、Python `numpy/scipy/scikit-image`（骨架中心线）。

> **环境坑（已踩过，省时间）**：
> - `brew install` 与 Playwright 浏览器下载都可能因公司网络**静默停滞**（命令挂在后台 0 输出）。先 `export HTTP_PROXY/HTTPS_PROXY/ALL_PROXY=<本机代理>` 再前台带 `timeout` 重试，通常立刻成功。
> - 闭环截图**优先复用系统已缓存的 Chromium**（`~/Library/Caches/ms-playwright/chromium_headless_shell-*/...`），用 Playwright `launch({executablePath})` 指过去，**别等 `playwright install` 重新下载**。
> - `magick` 若没装 rsvg/ghostscript，渲染 potrace/SVG 不可靠（出全白图）→ 改用已缓存 Chromium 截图来预览 SVG。

> "看懂运动"这步**由你（Claude）直接 `Read` 帧图来做**——你就是视觉模型，逐帧推断运动/缓动/锚点（即 Phase 3），这比任何一把梭的自动分析都精细。不要去找或安装第三方分析工具。

---

## 经验沉淀（持续机制）

> 设计参考 `references/experience-sedimentation-design.md`《站点经验沉淀机制》：**写入 = Prompt 驱动的 AI 自主行为，读取 = 规则强制**。本 skill 没有也不需要写入脚本——靠下面这些规则驱动你自己在恰当时机读和写，从而每次运行都比上一次少踩一个坑。

**存储**：`references/lessons.md`，单文件流水账，一条经验一段，含 `类别/日期` 与三段式结构。能固化成 Phase 清单/完成标准的同步并入 SKILL.md 正文；本文件保留带日期的"别再犯"先验。

**读取时机（强制）**：每次进入 skill，Phase 0 第 0 步**必须先读** `references/lessons.md`，逐条把"下次规则"作为本次检查项。

**读取回退**：每条标了日期，是"提示而非保证"。若某条经验与当前视频/用户意图矛盾，**以当前事实为准**，并在本文件更新/修正该条（注明新日期），不硬套旧经验。

**写入时机（主动）**：一次任务结束、**尤其本轮被用户纠正过 ≥1 次、或闭环比对暴露过遗漏**之后，**主动追加**新经验。顺利无新发现则不写（不灌水）。

**写入约束**：
- 只写**经过闭环验证或用户明确确认**的事实，不写"可能/大概"的猜测。
- 每条三段式：**现象（哪里没做好）→ 根因 → 下次可执行规则**。
- 写完若该规则能固化进 Phase 3.1 清单 / Phase 3.5 / 完成标准，**同步并入 SKILL.md 正文**并在该条标注"已并入"。

**自检闭环**：本轮若被用户纠正过 ≥1 次而 `references/lessons.md` 未更新，则**任务未完成**，不得交付。

---

## 完成标准

- 进入时读过 `references/lessons.md`，Phase 0 把历史"下次规则"逐条当检查项过了一遍
- 产出的 Prompt 点名了确切 API/机制、缓动、空间锚点、易错点，没有"流畅渐变"这类废话
- 截帧覆盖了完整起末态和最剧烈过渡段（能脑内播放出连续运动）
- 机制有歧义时给了多套变体，没替用户拍板
- 没有编造文件结构 / 浏览器版本
- 追踪过光标轨迹，分清是 autoplay 还是 hover/点击交互（移出是否立即复位），没把交互录屏硬套成时间循环
- 检查过容器自身状态（按压/阴影翻转/缩放）和是否多趟绘制（轮廓先于上色），没漏成"只动了内容、容器是死的"或"只上色没成形"
- 动效主体是复杂图形时，是矢量化得来的，没有手画贝塞尔糊弄；且矢量化路线（potrace 填充 / skeleton 中心线）和动画类型（擦除 / 自绘）匹配——即使只是闭环验证脚手架也不准临时手画（见 L7）
- 闭环 HTML 是脚手架不是产物：迭代时只改"被验证为错"的那一处，其余已对维度原样保留；一轮改了多个维度的，交付前逐维度核对没顺手打破已对部分（见 L7）
- 若用户要了闭环：生成截图与源帧比对一致；多趟绘制动效必须专门抓一帧落在滞后窗口内的中段帧，确认三段共存而非两趟塌缩
- 闭环比对落到**机制级特征**（逐线自绘 vs 整体遮罩 wipe、绘制头有无发光、stagger 单位是元素还是切线），不能只比"整体方向/起末态"这种粗粒度表象——用错误心智模型做比对会确认偏差通过（见 L6）
- 堆叠展开/共享元素类闭环已追踪同一元素至少三个中间位置，并在目标显示尺寸确认至少三条后层边缘可见；没有用帧率、编码或两张起末截图替代连续轨迹验收（见 L8）
- 命中 `references/lessons.md` 旧经验时，先独立判读当前帧再拿旧经验对照，矛盾以当前事实为准，禁止拿旧结论直接套（见 L6）
- 退场行为单独核对过（瞬移 vs 渐隐 vs 反向擦除），没默认成"移除即消失"
- **本轮若被用户纠正过 ≥1 次，`references/lessons.md` 已追加对应「现象→根因→下次规则」并标注是否并入正文——否则任务未完成**

