AgentStack
SKILL verified MIT Self-run

Animation Explainer

skill-agentbuff-animation-explainer-animation-explainer · by AgentBuff

把一个技术概念/流程/系统转化为"剧场式"动画 HTML — 多场景 + 自动播放 + 章节导航 + 旁白与真实代码。适用于网络协议、底层原理、算法、架构原理等"看不见但需要看见"的主题。单文件 HTML,无构建步骤。

No reviews yet
0 installs
15 views
0.0% view→install

Install

$ agentstack add skill-agentbuff-animation-explainer-animation-explainer

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Animation Explainer? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Animation Explainer · 知识动画化技能

这个技能是什么

输入一个主题("打开浏览器到屏幕上像素的全过程"、"一个 SQL 查询是怎么被执行的"、"TLS 1.3 握手"、"V8 是怎么编译 JS 的"),输出一份单文件 HTML 动画演示,能在任意浏览器打开播放。

参考实现:examples/browser-request/index.html任何新主题都从复制这个文件开始,而不是从零写。

它不是什么

  • ❌ 不是幻灯片:每节有 SVG 动画,元素会移动、闪烁、依次出现
  • ❌ 不是单页长滚动信息图:内容被切成离散场景,自动按节奏播放
  • ❌ 不是 PPT 截图导出工具:纯 HTML+SVG+CSS+原生 JS,没有打包步骤
  • ❌ 不是通用 explainer 框架:只解决一类问题 — 多场景剧场式技术解说

核心结构(必须遵守)

文件

  • 单一 index.html,所有 CSS/JS/SVG 内联。零外部依赖(除了 Google Fonts,可选)。
  • 复制 examples/browser-request/index.html 改,不要从空文件开始

页面骨架(grid)

┌─────────────────────────────────────────────┐
│ 顶栏: brand + chips + 进度条 + N/总数        │  ← 章节导航
├─────────────────────────────────────────────┤
│  舞台 (SVG 全屏)        │  旁白面板          │
│  ─ 当前场景的动画区     │  - 节号 + 大标题   │  ← 主体(1.55 : 1)
│  ─ 角落计时             │  - 正文(带高亮)  │
│                         │  - 代码块(真实)  │
├─────────────────────────────────────────────┤
│ 控件: ◀ 上一节  ⏸/▶  下一节 ▶  ↻  + 章节名 │  ← 控件
└─────────────────────────────────────────────┘

DOM 约定

  • 每个场景一个 `,**只有 .active` 那个显示**
  • 每个旁白一个 ``,配对切换
  • JS 用 CHAPTERS 数组驱动一切,每项必须有 { id, title, duration, narration }
  • narration = 中文口播稿(必填,详见"口播旁白系统"那节)
  • duration = TTS 开时是进度条参考;TTS 关时是切换间隔
  • 切换 = 切 .active + 调用 runScene(N) + 触发口播

必备控件

  • 上一节 / 下一节 / 播放暂停 / 重播本节 / 🔊 旁白开关
  • 键盘: ← → / Space / R / M(静音切换)
  • 章节 chip 可点击直接跳转
  • 顶部进度条 + N/总数标签
  • 角落 SCENE 编号 + mm:ss / mm:ss 计时
  • 自动推进由口播结束驱动,不是固定 setTimeout(详见"口播旁白系统"那节)

工作流(每次接到任务执行这 6 步,可选第 7 步导出 MP4)

步骤 1 · 拆主题为场景

约束:3–8 个场景。少于 3 节没必要做动画;多于 8 节注意力分散。

每个场景 = "一个核心概念 + 一个能动的视觉隐喻"。先在脑子里过一遍,写出来:

场景 1 · [标题]
  核心概念: [一句话能讲完的那个点]
  视觉隐喻: [打字机 / 飞行的包 / 流水线 / 树 / 时序图 / ...]
  真实数据: [命令输出 / 报文 / 日志 / 耗时数字]
  时长: [6000~9000ms]

好的隐喻是排他的。"DNS 是电话簿" ✅ 一眼就懂;"DNS 是分布式服务" ❌ 太泛。

步骤 2 · 选择视觉模式(按场景类型)

复用 demo 里已有的 5 种基础模式,不要每节都发明新的:

| 类型 | 用途 | demo 里在哪 | | ------------------ | ----------------------------- | -------------------- | | 实物 mockup | 起点/终点、用户看得见的东西 | scene 1(浏览器壳) | | 节点 + 飞包 | 多方协调、网络拓扑、消息流转 | scene 2(DNS 递归) | | 时序图 | 两端协议、握手、状态转移 | scene 3/4/5/7(TCP/TLS/HTTP) | | 流水线 + 日志 | 内部处理、阶段流转、副作用 | scene 6(服务器内部)| | 结构树 / 合并 | 数据结构、编译、解析 | scene 8(DOM/CSSOM) |

需要新隐喻时,先问"能不能用以上 5 种里的 1 种讲清楚"。

步骤 3 · 写真实数据,不要编

旁白里的代码块是教学价值最高的部分。所有命令、报文、日志、时间都要真实

  • 命令: 真的运行 digcurl -vtcpdump 输出
  • 报文: 用 HTTP/1.1 真实格式(动词 路径 协议\r\n + Header\r\n + ...)
  • 时间: 用合理的 RTT/TTFB 范围(不要写 0ms 或 999ms)
  • 日志: 抄真实框架的输出格式(Rails / Nginx / Postgres 各有特征)

虚构的报文/日志读者一眼就知道是 AI 编的,整个 demo 的可信度崩塌。

步骤 4 · 写动画函数(每场景一个)

每个 scene N() 函数干两件事:

  1. 重置元素到初始状态(resetEl('id1','id2')
  2. 按时间序列调用 showEl(id, delayMs) 或自己写 RAF 动画

复杂运动(飞行)用 RAF + cosine easing:

const start = performance.now(); const dur = 2400;
function step(ts){
  const p = Math.min(1, (ts - start) / dur);
  const ease = 0.5 - Math.cos(p * Math.PI) / 2;  // ease-in-out
  el.setAttribute('transform', `translate(${x0 + dx * ease}, ${y0})`);
  if (p 

脚本会自动从 HTML 抠出 narration 字段,生成 audio/scene-N.mp3(默认云希男声)。重新打开 demo,HTML 会自动检测并使用 mp3 旁白;没生成 mp3 会回退到浏览器原生 Web Speech API。

第一次跑前要装依赖:npm install

步骤 6 · 自检(反 AI Slop 清单)

提交前逐项核对:

  • [ ] 没有"作为一个 AI 助手" / "希望对你有帮助"这类废话
  • [ ] 没有 emoji 泛滥(一节最多 1 个,且作为视觉锚点而不是装饰)
  • [ ] 代码块的命令是真的能跑的
  • [ ] 时间数字是合理范围(不是占位的 100ms / 1000ms)
  • [ ] 没有用 `` 堆出"动画"(必须是真的会动)
  • [ ] 每个场景结束时画面"稳",给读者读完代码的时间
  • [ ] 暗色背景不刺眼(不要纯黑 #000,用 #060912 这种)
  • [ ] 字体用 Inter + JetBrains Mono,不要 system-ui 凑合
  • [ ] 浏览器打开后能键盘 ← → / Space / M 操作
  • [ ] 主题专业术语都准确("三次握手"不写成"三次连接")
  • [ ] .codeblk 的 CSS 有 white-space: pre; tab-size: 2;(否则代码挤一行)
  • [ ] CHAPTERS 每项都有 narration 字段,没漏节
  • [ ] 口播稿是真口语(不会读出"等" "之" "乃"这种书面字)
  • [ ] audio/scene-N.mp3 已生成
  • [ ] 切换章节是按口播结束驱动,不是 setTimeout(duration) 硬切
  • [ ] 控件区有 🔊 按钮 + M 键绑定

步骤 7 · 人工审核 + 导出 MP4(可选)

前 6 步走完、在浏览器里看过完整 demo、觉得满意后,再导出 MP4。这一步是人工 in-the-loop:不审核就导出会浪费几分钟跑 Playwright,最终发现某节口播错字或动画卡顿,还得重跑。

node scripts/export-video.mjs examples/
# 或:npm run video:

输出 /video.mp4(1280×800 30fps,5MB / 2 分钟左右)。可以直接发微信、抖音、B 站、知乎。

第一次跑前要装浏览器:npx playwright install chromium(约 200MB,只装一次)。

实现细节见下方"视频导出"那节。


设计系统(颜色 / 字体 / 间距)

颜色(5 个语义槽,按需选)

| Token | 值 | 语义 | | ----------- | -------- | ---------------------------- | | --cyan | #22d3ee | 客户端 / 主线 / "去"的方向 | | --violet | #a78bfa | 服务端 / 系统 / "回"的方向 | | --lime | #a3e635 | 代码字符串 / 成功 | | --amber | #fbbf24 | 状态码数字 / 中间步骤 | | --rose | #fb7185 | Paint / 警告 / 危险 | | --emerald | #34d399 | 最终成功 / 200 OK |

一个场景里最多用 3 种主色,其他降到 --text-dim / --muted

字体(已在 demo `` 引入)

  • Inter — UI 正文
  • Inter Tight — 大标题(h2)
  • JetBrains Mono — 所有代码、日志、抓包、技术标签

间距 / 圆角

  • 控件按钮: padding: 7px 13px, border-radius: 8px
  • 大卡片: border-radius: 16px(var(--radius-lg))
  • 中卡片: border-radius: 10px
  • 网格背景: 48×48px 极淡,营造"工程感"

代码块(重要)

旁白里的 .codeblk 必须white-space: pre; tab-size: 2; —— 否则 HTML 默认把所有空白(含换行)折叠成单个空格,整段代码会挤成一行。模板已带上,从模板出发就 OK;从老 demo 复制要确认这条 CSS 在。

.codeblk{
  /* ...其它... */
  white-space: pre;        /* ← 必须 */
  tab-size: 2;             /* ← 缩进对齐 */
  -moz-tab-size: 2;
  overflow: auto;          /* 长行水平滚动 */
  max-height: 240px;       /* 限高度,超出垂直滚动 */
}

SVG `` 元素由 y 坐标硬定位,行间距建议 font-size × 1.45(如 11px 字号配 16px 行距、12px 字号配 18px 行距)。


口播旁白系统(每个 demo 默认带上)

为什么:动画 + 真人口播 = 真正的科普视频体验。只看不听,单场景的注意力撑不住 20 秒。

CHAPTERS 数据结构

const CHAPTERS = [
  { id:1, title:"...", duration:11000,
    narration:"一切从一行字开始。打开一个 vue 文件……" },
  // ...
];

口播稿写法(决定听感,比语音引擎本身更重要)

| 要求 | ✅ 好 | ❌ 差 | | -------------------------- | ------------------------------------------------- | ----------------------------------------------------- | | 3–5 句,每句 ≤ 25 字 | "TCP 是可靠的传输协议。在发数据前要先建立连接。" | "TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。" | | 口语化,不照搬旁白 | "reactive 不复制对象,而是用 Proxy 把它包起来" | "reactive 函数返回的并非原对象的副本,乃是一个 Proxy 实例" | | 避免符号污染朗读节奏 | "把模板、脚本、样式三段塞在一起" | "把模板(template)、脚本(script)、样式(style)塞在一起" | | 专业术语不翻译 | "Proxy 拦截器"、"render 函数" | "代理拦截器"、"渲染函数"(TTS 读中文易出错) | | 时长 10–20s(云希默认语速)| — | — |

双轨实现:MP3 优先 → Web Speech 兜底

打开 demo
  ├─ 探测 audio/scene-1.mp3 能否加载(1.5s 超时)
  ├─ 能加载 → 用 mp3(edge-tts 预生成的云希等 Neural voice,质量好)
  └─ 不能加载 → 回退 Web Speech API(系统自带 voice,质量一般但零依赖)

带来的好处:

  • 删掉 audio/ 目录,demo 仍可用(用系统 voice)
  • 改了 narration 文案,重跑生成脚本即可
  • 本地 file:// 双击也能工作(Audio 元素支持同目录文件)

MP3 生成(edge-tts,免费)

# 一次性安装
npm install

# 给某个 demo 生成 mp3(默认 voice:云希男声,rate +5%)
node scripts/generate-audio.mjs examples/

# 换 voice
node scripts/generate-audio.mjs examples/ --voice=zh-CN-XiaoxiaoNeural

# 调语速
node scripts/generate-audio.mjs examples/ --rate=+10%

中文 Neural voice 推荐:

| voice | 性别 | 风格 | 用途 | | ---------------------- | ---- | -------- | ------------------- | | YunxiNeural(云希)| 男 | 年轻清爽 | 技术解说默认 | | YunyangNeural(云扬) | 男 | 新闻播报 | 历史 / 综述 | | YunjianNeural(云健) | 男 | 浑厚 | 长篇教学 | | XiaoxiaoNeural(晓晓) | 女 | 温柔标准 | 通用 | | XiaoyiNeural(晓伊) | 女 | 活泼年轻 | 趣味科普 |

脚本逻辑:用正则从 demo 的 index.html 抠出 CHAPTERS 数组里的 narration: "..." 字符串,逐节生成 audio/scene-N.mp3

自动推进:必须按口播结束驱动

错误做法(早期 demo 的 bug):

// ❌ 用固定 duration 切下一节 — 口播没说完就被打断
setTimeout(() => goTo(i+1), CHAPTERS[i].duration);

正确做法

const ADVANCE_BUFFER_MS = 1200;   // 口播结束后停留多久再切下一节
const SAFETY_MAX_MS     = 60000;  // 兜底:若口播 onEnd 没触发,最长 60s 强制推进

function startCurrentScene(){
  state.sceneStart = performance.now();
  const text = CHAPTERS[state.index].narration;
  if (state.ttsEnabled && text) {
    scheduleAdvance(SAFETY_MAX_MS);                // 兜底
    speak(text, state.index, () => {               // ← 真正的推进信号
      if (state.playing) scheduleAdvance(ADVANCE_BUFFER_MS);
    });
  } else {
    scheduleAdvance(CHAPTERS[state.index].duration); // 静音回退到 duration
  }
}

speak() 接收 onEnd 回调,挂在 audio.onended / utterance.onend / onerror 上 —— 失败也触发推进,不会卡死。

三个关键防坑细节

1. stopSpeak() 主动停止时,要先卸掉 onended 监听器

function stopSpeak(){
  if (currentAudio) {
    currentAudio.onended = null;   // ← 关键
    currentAudio.onerror = null;
    currentAudio.pause();
    currentAudio.currentTime = 0;
    currentAudio = null;
  }
  if ('speechSynthesis' in window) speechSynthesis.cancel();
}

否则 pause() 之后浏览器仍可能触发 ended,被误判为"自然结束"导致莫名切页。

2. 初始化用 state.playing = true; goTo(0),不是 goTo(0); play()

// ✅
state.playing = true;
updatePlayBtn();
goTo(0);

后者会在 goTo 里 speak 一次(无 onEnd),play 里再 speak 一次(带 onEnd)—— 第一个 mp3 刚开播就被第二次调用打断。

3. Audio 引用要锁住,回调里判等

const a = new Audio(`audio/scene-${idx+1}.mp3`);
currentAudio = a;
a.onended = () => {
  if (currentAudio === a) currentAudio = null;  // ← 防旧实例污染
  onEnd && onEnd();
};

防止用户连按下一节时,上一个 audio 的延迟 ended 事件污染新场景的状态。

Web Speech 兜底实现

function webSpeak(text, onEnd){
  if (!('speechSynthesis' in window)) { onEnd && onEnd(); return; }
  speechSynthesis.cancel();
  const u = new SpeechSynthesisUtterance(text);
  u.lang = 'zh-CN'; u.rate = 1.05;
  if (cnVoice) u.voice = cnVoice;
  u.onend   = () => { onEnd && onEnd(); };
  u.onerror = () => { onEnd && onEnd(); };  // 失败也推进
  speechSynthesis.speak(u);
}

cnVoice 在页面初始化时挑选,优先级:Premium/Enhanced/Neural 中文 > 任意中文 > null。


视频导出(MP4)

适用:human-in-the-loop 工作流 —— 浏览器里审核通过后,一键导出可分发的视频文件。

命令

# 一次性安装(第一次跑前)
npm install
npx playwright install chromium

# 导出某个 demo
node scripts/export-video.mjs examples/
# 或:npm run video:

# 自定义分辨率 / 帧率
node scripts/export-video.mjs examples/ --width=1920 --height=1080 --fps=60

默认输出 /video.mp4:1280×800 30fps,H.264 + AAC,约 5MB / 2 分钟。

实现原理

Playwright headless Chromium 加载 HTML
   ↓
recordVideo 录制 WebM(无音轨 — Playwright 的限制)
   ↓
ffmpeg 把每节 mp3 串起来 + 节间 1.2s 静音(对齐 ADVANCE_BUFFER_MS)
                            + 头部 1s pre-roll(对齐 autoplay 启动延迟)
   ↓
ffmpeg mux WebM + 音轨 → MP4(H.264 + AAC + pix_fmt yuv420p + faststart)

pix_fmt yuv420p 是 QuickTime / 微信 / 抖音兼容性的必备;faststart 让 mp4 头部前置,浏览器边下边播。

同步约束(必须理解)

画面切换由 HTML 内的 audio.onended 驱动;音轨是脚本按 mp3 真实时长 + ADVANCE_BUFFER 预先拼好的。两者用同样的时间常数(1.2s),所以大体同步

轻微漂移可能出现(一般 ` 即可

要分发的 mp4 单独上传(飞书 / 微信文件 / B 站 / 抖音)。


输出位置约定

examples/
  /
    index.html             # 主文件(单文件 HTML,含所有 CSS/JS/SVG)
    audio/                 # TTS 旁白(edge-tts 生成,跟 demo 一起提交)
      scene-1.mp3
      scene-2.mp3
      ...
      scene-N.mp3
    video.mp4              # 可选 · 导出的视频(不入 git,本地按需生成)

例如:examples/sql-query-execution/index.htmlexamples/git-merge/index.html

  • audio/ 可选 —— 删掉后 HTML 会自动回退到浏览器原生 Web Speech API,质量差但能听
  • video.mp4 可选 —— 是导出产物,只在要分发时本地生成

常见任务的拆解参考

收到主题时,可以先比对一下是否属于以下类型:

| 主题类型 | 场景拆解模式 | | ------------------ | ---------------------------------------------------- | | 网络协议 | 起因 → 寻址 → 连接 → 加密 → 请求 → 响应 → 解析 | | 编译/解释器 | 源码 → 词法 → 语法 → AST → 优化 → 字节码 → 执行 | | 前端框架原理 | SFC → 编译 → 响应式(reactive/track/trigger)→ VNode → Diff → Patch | | 数据库查询 | SQL → 解析 → 优化器 → 执行计划 → 索引扫描 → 聚合 | | 构建工具 | 入口 → 依赖图 → 编译 → 打包 → Tree shaking → 输出 | | 操作系统 | 用户态调用 → 系统调用 → 内核处理 → 硬件 → 返回 | | 加密算法 | 明文 → 分组 → 轮函数 → 密钥扩展 → 密文 → 解密验证 | | 分布式协议 | 提议 → 投票 → 多数派 → 提交 → 通知 → 状态同步 |


与花叔 Design / 前端设计技能的关系

  • 这个 skill 专注于教学性技术动画,更窄、更程式化
  • 视觉品味遵循 frontend-design / huashu-design 的反 AI slop 原则
  • 不要为每个 demo 重新设计颜色/字体;用本 skill 的 design token

维护规范

  • 每完成一个新主题的 demo,把它的章节拆解写进上面的"常见任务"表
  • 发现新的视觉模式(不在已有 5 种里)且复用过 2 次以上,沉淀到 templates/
  • demo 文件之间不共享代码(保持单文件可分发的属性),但共享模式
  • 提交前必跑 node scripts/generate-audio.mjs examples/ 生成 mp3,让 demo 默认带高质量口播
  • 改了某节 narration 后重跑生成脚本(脚本会整体覆盖 audio/ 目录,单节增量没必要)
  • audio/ 目录建议跟着 demo 一起提交 — 约 100KB/节,8 节 `
  • 输出位置约定下增加 audio/scene-N.mp3 子结构

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.