Communitygithub.com

视频解说生成器

通过编写 HTML/SVG/CSS 动画场景,使用 GSAP 制作动画,并借助无头 Chromium 和 ffmpeg 逐帧渲染,创建信息型解说视频(MP4)。适用于用户要求制作解说视频、动画演示、动态图形短片或导出为视频的动画图表。

视频解说生成器 是什么?

该技能将专业动态设计师的工作流程转化为代码:每个场景是一个独立的 JS 模块,构建 DOM/SVG 元素并在暂停的 GSAP 时间线上添加补间动画。渲染器逐帧移动时间线(`t = frame / fps`),截取每一帧,然后通过 ffmpeg 合成视频。输出是确定性的——相同项目始终渲染相同帧。支持分镜设计(`video.json`)、场景编写(`scenes/<id>.js`)、可选的语音旁白(通过 OpenRouter MCP 生成)、完整检查(lint)以及带联系表的预览渲染(contact-sheet)。平台为 CLI(Node.js),适用于 DeepAI、Claude Code、Cursor 等支持 shell 命令的 AI Agent。开发者需要理解 GSAP、面向时间线的动画概念,并且系统上已安装 ffmpeg 和 Playwright。

兼容平台~Claude Code~Codex CLI~Cursor✓Gemini CLI
npx skills add https://github.com/lleadbet/video-explainer-skill/tree/HEAD

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

视频解说生成器 是做什么的?

你像动态设计师一样制作视频,但使用的是代码:每个场景是一个小型 JS 模块,构建 DOM/SVG 元素,并在暂停的 GSAP 时间线上添加补间动画。渲染器逐帧播放该时间线(t = frame / fps),截取每一帧,并将帧序列传递给 ffmpeg。输出具有确定性:相同项目总是渲染出相同的帧。

SKILL_DIR 指本技能的基础目录(包含此文件的文件夹)。

设置(每台机器一次)

cd SKILL_DIR/scripts && npm install && npx playwright install chromium

你还需要将 ffmpeg 添加到 PATH。如果缺少依赖,每个脚本都会打印此命令。

工作流程

  1. 先设计分镜。 商定主题、受众、目标时长以及是否需要旁白,然后在 video.json 中编写场景列表。每个场景包含 narration(旁白内容)和 visual(屏幕显示内容)。阅读 reference/storyboard.md。在分镜自行合理之前,不要编写场景代码。
  2. 创建项目骨架: node SKILL_DIR/scripts/new.mjs <project-dir> --title "...",然后编辑 video.json,并在 scenes/<id>.js 中为每个场景编写一个模块。参考 reference/animation-patterns.md 获取模式,参考 reference/design.md 获取布局、排版和颜色。如果有旁白,将场景时长设置为 "auto",并使用 cue('短语') 来同步动画。两个完整的配音视频示例:examples/kubernetes-overview/(ElevenLabs)和 examples/how-dns-works/(Gemini)。
  3. 旁白(如果需要): 遵循 reference/voiceover.md。简言之:在 video.json 中添加 "voice" 块,运行 node SKILL_DIR/scripts/narration.mjs status <project-dir>,对每个列出的场景调用一次 OpenRouter MCP 工具 generate-speech(使用它打印的确切参数),并使用 narration.mjs add 注册每个保存的文件。在检查(步骤 4)之前完成此操作,因为真实的音频会改变场景时长和 cue() 的时间。
  4. 检查: node SKILL_DIR/scripts/lint.mjs <project-dir>。它会在 Chromium 中加载每个场景,并报告加载错误、动画时长超过场景、在 tl 外部创建的动画、超出 frame 的元素、被裁剪的文本以及超出场景时长的旁白。修复每一个警告,除非是故意的。
  5. 预览: node SKILL_DIR/scripts/render.mjs <project-dir> --contact-sheet,然后查看 PNG(<project-dir>/out/contact-sheet.png)。检查层次结构、重叠、可读性、空白帧、时间。如需细节,渲染特定时刻:--stills 12.5,30。反复修改直到视觉正确,然后在最后一次编辑后再进行一次联系表渲染。
  6. 渲染: node SKILL_DIR/scripts/render.mjs <project-dir> → <project-dir>/out/video.mp4。旁白片段会自动混入。将路径、时长和场景列表提供给用户。他们可以使用 node SKILL_DIR/scripts/serve.mjs <project-dir> 进行交互式预览(拖拽进度条、播放/暂停、旁白播放、c 切换字幕、m 静音)。

有用的渲染标志:--out file.mp4,--from 10 --to 20(部分渲染),--scale 0.5(快速草稿),--workers N,--crf 18,--audio track.mp3(使用自定义音轨代替旁白),--no-voice(静音),--audio-codec aac(默认是 MP3,也可以在 VS Code 中播放)。

项目结构

my-video/
  video.json          # 标题、宽度、高度、帧率、种子、过渡、主题、场景[]
  scenes/<id>.js      # 每个场景一个模块
  assets/             # 图片/SVG,引用为 '/assets/x.svg'
  audio/              # 旁白片段 + manifest.json(来自 narration.mjs;保留它们,因为付费生成)
  style.css           # 可选,如果存在则自动加载
  out/                # 渲染输出(contact-sheet.png, stills/, video.mp4)

video.json 场景字段:id(必需,也是默认文件名 scenes/<id>.js),duration(秒,或 "auto":匹配旁白音频时长,或在音频存在前基于阅读速度估算,且永远不会短于动画时长),narration,visual,可选的 file,以及可选的 transition("fade",默认,或 "cut")。顶层 "voice" 块在 reference/voiceover.md 中描述。

场景契约

import { h, reveal, pop } from '/__runtime/helpers.js';

export default function ({ el, tl, gsap, theme, width, height, random, onFrame, cue, voice }) {
  const title = h('div', { class: 'h1' }, 'Hello');
  el.append(h('div', { class: 'center' }, title));
  reveal(tl, title, { at: 0.3 });                       // tl 时间 0 = 本场景开始
  tl.to(title, { color: 'var(--accent)', duration: 0.5 }, cue('the key idea'));  // 当说出该短语时
}
  • el:此场景的容器。它覆盖完整的 1920×1080 舞台,并会自动显示和隐藏。
  • tl:此场景的时间线。所有动画必须位于 tl 上(或添加到 tl 的其他时间线上)。切勿直接使用 gsap.to(...)、CSS animation/transition、setTimeout、setInterval、requestAnimationFrame、<video> 或任何依赖挂钟时间的内容。渲染器仅移动时间线播放头,因此其他任何内容在 MP4 中都会冻结或不同步。
  • cue(phrase, offset = -0.15) 返回场景中说出 phrase(不区分大小写,必须出现在本场景的旁白中)时的场景时间。一旦音频存在,它会与片段测量的停顿对齐,因此从句开头的短语会落在口语单词上。如果未找到该短语则抛出异常。对所有需要与旁白同步的 at 使用它。voice 提供本场景语音的 { start, duration, end, estimated }(例如,保持循环效果运行直到 voice.end)。
  • 对于逐帧绘制(画布、程序化运动),使用 onFrame((sceneTime) => draw(sceneTime))。该函数在场景可见的每一帧被调用。
  • 覆盖层(可选): 在 video.json 中设置 "overlay": "scenes/_overlay.js" 会在整个视频的每个场景上方绘制一个模块,用于显示时间码、进度条、徽标或帧边框。它接收 { el, tl, onFrame, scenes, duration, ... },其中 onFrame((t) => ...) 接收全局时间,scenes 列出每个场景的 start/end。
  • random() 按场景播种,Math.random 也被播种,因此随机布局是可重现的。
  • 该函数可以是 async(例如,用于 fetch('/assets/data.json'))。字体在场景运行前加载,因此测量文本是可行的。
  • 主题颜色为 CSS 变量:var(--bg) --surface --surface2 --fg --muted --accent --accent2 --accent3 --accent4 --danger,外加 --font 和 --mono。在 video.json → "theme": { "accent": "#ff3366" } 中覆盖它们。
  • GSAP 插件已全局注册:DrawSVG, MotionPath, MorphSVG, SplitText, Text, ScrambleText, CustomEase。

质量标准

  • 每个场景一个想法。屏幕上至少每 2-3 秒应有内容移动或变化,并且每个动画应与它所说明的旁白行同步(使用 cue();旁白语速约 2.5 字/秒)。
  • 文字要大:在 1920×1080 舞台上,正文 ≥ 40px,标签 ≥ 26px。保持在安全区域内(.safe,边距 96/128px)。
  • 逐步构建图表,而不是直接展示完整的图表。
  • 在每个场景结束、淡出前,留下短暂的停顿,以便最终状态能被看清。

旁白

音频来自 OpenRouter MCP 服务器(generate-speech);本技能仅负责规划与录制。如果这些工具不可用,告知用户旁白需要连接 OpenRouter MCP 服务器,并在此时无旁白渲染。reference/voiceover.md 包含完整流程、模型与语音选择以及成本。

相关技能