Communitygithub.com

MotionBrief — 动态图形视频生成工具

通过HTML或React制作动态图形与短视频:标题卡、Logo动画、动态文字、计数动画、数据揭示、下三分之一字幕、透明叠加层及功能集锦。将自然语言需求编译为验证过的需求简报并渲染;可将一份简报批量生成多个视频。

MotionBrief — 动态图形视频生成工具 是什么?

MotionBrief 是一个面向 AI 代理(如 Claude Code)的专业技能,用于生成动态图形(motion graphics)视频。它支持两条技术路线:HyperFrames(基于 HTML + GSAP,自动安装,Apache 2.0 许可)和 Remotion(基于 React + TypeScript,3人以下免费)。用户只需用自然语言描述需求(如“一个6秒的Logo动画”),该技能会自动将需求编译为结构化的 `brief.json` 简报,包含时长、分辨率、帧率、节奏点(beats)、文案、缓动效果及调色板。随后基于模板生成代码,进行校验(包括文案存在性、时间匹配、可见性等),最后渲染成视频。关键创新在于“简报即契约”——一切修改都基于编辑简报实现,无需重写代码,因为视频的每个段落(beat)的时间、内容、动效均由简报严格定义。这使得迭代成本极低,且可批量生成多个版本。该技能特别强调避免无声错误,例如 HyperFrames 中未注册时间线会导致静帧,而 `check-contract.mjs` 能捕获这类问题。

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/YahyaLendani/motionbrief-claude-skills/tree/main/skills/motionbrief

在你喜欢的 AI 中提问

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

文档

动态图形视频制作

通过编写一个逐帧渲染的网页来生成视频。 以下两条路径实现相同的效果;区别在于你编写的内容。

  • HyperFrames — 一个 HTML 文件,CSS 负责外观,一个暂停的 GSAP 时间线负责动效。node scripts/hf.mjs 运行锁定版本,并从提交的锁文件自动安装一次。Apache 2.0 许可。
  • Remotion — React 组件。useCurrentFrame() 返回当前帧索引,你自行计算。成熟、强类型,但仅限 3 人以内免费使用。

在编写组合代码之前,请加载对应的参考文档。框架规则不可猜测,且大多数失败是无声的:一个从未注册时间线的 HyperFrames 文件会渲染一个静帧,且没有任何错误提示。


轻量路径

用户用任意语言描述他们想要的内容。他们从不撰写简报、规格说明或节拍表——由 Claude 来编译。

/motion 一个为 Inkwell 制作的6秒 Logo 动画,要简洁有力

这就是全部输入。底层执行流程:

  1. 编译 请求,生成 brief.json — 时长、尺寸、帧率、带时间点的节奏点、逐字文案、缓动效果、调色板,以及一个 assumptions(假设)列表。每个空缺都从 references/brief.md 中的默认值表获取;所有字段都被定义,不留下任何未定义项,也不提出疑问。
  2. 展示 紧凑摘要(一个表格,约 12 行),并在同一轮交互中构建。无需批准环节。
  3. 基于模板构建、校验、渲染、查看帧画面。

后续迭代针对字段进行编辑,而非重新构建。“让它更有力”会修改 feel.ease 和两个持续时长;除非 kind 或 motion 发生变化,否则代码不会变动。

简报就是让这一切变得经济高效的关键产物。它存放在组合代码旁边,因此修订就是一个差异对比(diff),重新渲染也只需一条命令。


路径选择

信号路径
全新构建,未指定框架HyperFrames
有现成的 HTML/CSS/GSAP/Lottie 可复用HyperFrames
不需要 node_modules,不需要构建步骤HyperFrames
团队规模超过 3 人HyperFrames(许可要求)
用户指名 Remotion,或仓库是 React/TSRemotion
需要设计系统、图表库或复杂组件Remotion
移植现有的 Remotion 项目Remotion(移植成本往往高于收益)

当用户同时指定两者时,请使用 HyperFrames 构建,并用一句话说明 Remotion 移植版可按需提供。除非用户明确要求对比,否则对同一作品进行两次完整构建是浪费工作。


工作循环

1. 编译简报

在编写代码之前,将请求转换为 brief.json。模式定义、kind/motion 语法、默认值表以及迭代杠杆点都位于 references/brief.md 中。

node scripts/brief.mjs brief.json          # 校验并输出摘要表格
node scripts/brief.mjs brief.json --json   # 机器可读结果

向用户打印摘要,修复任何 ERROR,然后在同一轮交互中继续。警告是判断性问题——你接受的一个警告会被记录到 assumptions 中。

简报还包含节拍信息。选择 audio.bpm,使拍点网格能整分切点——在 bpm 下,一个拍时 = 60 / bpm 秒,每个 beats[].start 都应落在拍点上。120 BPM 每拍 0.5 秒,适合大多数短视频。如果 brief.mjs 报告 off_beat_grid,移动切点或更改速度;不要忽略它,因为这决定了作品是精准卡点还是感觉微妙地不对劲。

完成条件: brief.mjs 退出码为 0,每个拍点都有时间窗口、类型、动效和逐字文案,且没有切点偏离拍点网格。

2. 项目搭建

从本技能的模板开始,而不是从空白文件开始——它们针对两种契约都正确无误,并省去了两个容易出错的步骤(时间线注册、序列定时)。

# HyperFrames — 纯 HTML。固定版本的引擎会自动安装一次,需要网络
cp -R assets/hyperframes/. ./my-video/
node scripts/hf.mjs lint ./my-video

# Remotion — React 项目,需要一次性安装其固定版本依赖
cp -R assets/remotion/. ./my-video/
cd my-video && npm ci
# PowerShell
Copy-Item -Recurse -Force assets\hyperframes\* .\my-video\
Copy-Item -Recurse -Force assets\remotion\* .\my-video\

完成条件: node scripts/hf.mjs lint 通过,或 npx remotion compositions src/index.tsx 能列出组合 ID。

3. 构建各拍点

每个拍点一个文件。保持时间线扁平化——HyperFrames 使用绝对时间,Remotion 使用 <Sequence> 帧。当构建过程改变定时时更新拍点表,然后重新检查总时长。

以其拍点 ID 命名每个场景,因为校验程序通过它来查找:HyperFrames 宿主元素上的 data-brief-beat="<id>",Remotion 中的 <Sequence name="<id>">。如果 Remotion Sequence 的定时是计算得出的,还需在其内部的一个元素上放置 data-brief-beat="<id>",以便测量时机。

完成条件: 拍点表中的每个拍点在代码中都存在,组合总时长与拍点表匹配,且没有 TODO、存根(stub)或占位符文案。

4. 验证动效

静帧会欺骗你对时机的判断。先查看帧画面,再查看渲染输出。

node scripts/check-contract.mjs --dir ./my-video --preflight   # 静态检查,无需安装
node scripts/check-contract.mjs --dir ./my-video --runtime     # 同时在浏览器中检查

node scripts/hf.mjs check ./my-video                # 布局、动效、对比度
node scripts/hf.mjs snapshot ./my-video --review    # 输出拍点帧和衔接帧的 PNG 图片
node scripts/hf.mjs keyframes ./my-video --selector "#card" --shot motion.png

npx remotion still src/index.tsx LaunchCard out/f.png --frame=45
npx remotion studio src/index.tsx              # 以 1 倍速度观看

check-contract.mjs 无需安装任何东西即可捕获静默失败:未注册的时间线、不匹配的 window.__timelines 键、未暂停的时间线、缺少的时长、组合中的 Math.random()、未钳位的 interpolate。它是一次预检,不能替代真正的 linter。

当 brief.json 位于项目中(或通过 --brief 指向一个文件)时,它还会将构建结果与简报进行比较。每个需求都会标记为 verified(已验证)、failed(失败)或 unverified(未验证)。 unverified 不是通过状态,并且会阻止渲染。

代码状态含义
brief_format_mismatchfailed宽度、高度、帧率或时长与 format 不符
brief_scene_count, brief_scene_unmappedfailed某个拍点没有声明其 ID 的场景,或者某个场景没有对应的拍点。位置本身不代表身份
brief_timing_mismatchfailed某个场景的开始或结束时间与简报不符,误差超过一帧
brief_copy_missingfailed该文案行不在场景中。注释和未使用的变量不计入
brief_copy_wrong_scenefailed该文案行仅出现在另一个场景中
copy_not_visiblefailed运行时:在 DOM 中但被隐藏、透明、移出屏幕、裁剪、模糊或遮挡
copy_hold_shortfailed运行时:可读时长少于 beats[].hold
first_frame_emptyfailed运行时:visibleAtStart 已设置,但该拍点的内容没有任何渲染
first_frame_unverifiedunverified运行时:第一帧上只有图形,或者该拍点没有文案。请查看帧画面
brief_timing_unverified, brief_format_unverifiedunverified源代码计算得出的值。运行时可以最终确定
brief_copy_dynamic, brief_copy_unverifiedunverified文案是否显示是一个运行时问题。除非经过运行时检查,否则 Remotion 的文案始终显示为此状态

匹配忽略大小写和空白,并统一弯曲引号。其他标点有重要意义,"12,480" 匹配一个最终停在 12480 的计数动画。当需求仍为 unverified 时,明确说明哪些需求,并尝试使其可测量再进行接受。接受一个需求意味着要指名道姓,使用 --allow-unverified "beat.lines.copy[0].visible",并向用户报告。永远不要接受通配符模式,并且 failed 状态根本无法被接受。请阅读 references/validation.md 了解确切的规则和限制。

在代码中修复偏差,或者有意修改简报并重新运行 brief.mjs——绝不允许两者不一致。

检查帧画面——所有检查都可能在一个有缺陷的影片上通过

一个通过的契约检查只表明时机和文案匹配,以及文本可读。它没有说明调色板、缓动、转场或影片本身是否有效。本技能的模板自身曾通过了 lint、布局、动效、对比度和工艺检查,但同时每个拍点都切到黑屏,且计数动画在数字显示的一瞬间就退出了。只有查看帧画面才发现了这个问题。捕获它们:

# HyperFrames:拍点帧,每个切点前后 5 帧的序列,以及手机尺寸预览图
node scripts/motion-render.mjs --brief ./my-video/brief.json --snapshot --no-render

# Remotion:对于每个切点 c(以帧为单位),抓取 c-6、c、c+6,以及每个拍点的中间帧
# (模板的切点在 75、210 和 270 帧)
node scripts/motion-render.mjs --dir ./my-video --no-render \
  --stills 37,69,75,81,142,204,210,216,240,264,270,276,315

然后查看图片并回答每个问题。修复代码,重新捕获,再次查看:

  • 切点是否出现黑屏? 一个切点周围出现多于一帧的空帧,意味着前一个拍点过早结束,下一个拍点是从无到有淡入。移动前一个拍点的退出动画,使其正好在切点结束(start = beat duration − exit duration)。
  • 高潮部分是否有足够停留时间? 计数动画的最终数字,或一行文案的最后一个词,在离开前应至少在屏幕上停留一个拍点的时间(60 / bpm 秒)。在数字落定的瞬间就退出意味着用户根本来不及阅读。
  • 在手机上是否可读? 检查 review-phone.jpg,或者设想一下帧在 360 像素宽下的效果。在 1080p 下,大约 40 像素以下的标签和标语通常无法看清。
  • 是否使用了简报指定的字体? 如果回退到 Segoe UI 或 Arial,说明字体从未加载成功,另一台机器将渲染出不同的影片。--runtime 会通过 font_fallback 发出警告,并且报告会记录实际绘制的字体。Remotion 需要 @fontsource/*(模板的选择)或 @remotion/fonts 来加载本地字体文件。
  • 是否使用了简报指定的转场? feel.transition 体现在每个切点周围的帧中,而不是一个到黑色的渐变。

完成条件: 你已经查看了所有拍点帧和每个衔接帧序列,回答了上述每一个问题,并且“发布检查清单”下的每一项都满足。

5. 渲染

node scripts/motion-render.mjs --brief ./my-video/brief.json
node scripts/motion-render.mjs --brief ./my-video/brief.json --batch rows.json --no-audio

该封装脚本从简报中读取路径、格式、帧率和 slug(标识符),并在简报、静态检查、工具、资源或运行时检查要求停止时,在花费任何渲染时间之前停止。失败时退出码为 1,存在未验证需求时退出码为 3。--no-checks 会跳过验证并在报告中记录。然后它会执行 lint、渲染、使用 ffprobe 测量文件,并写入 <out>.report.json。

当 audio.policy 为 generated(无论哪种路径),它会使用 music.mjs 合成背景音乐(bed),仅渲染无声音的视频,然后通过一次 ffmpeg 调用将两者混合——这样组合代码就永远不依赖于引擎的音频混合器。然后它会测量文件是否包含音频流,以及是否为静音。

对于透明视频:使用 --format webm 或 --format mov——H.264 无法携带 Alpha 通道。--no-audio 会跳过背景音乐,生成一个没有音频流的文件。GIF 无法携带音频,因此如果简报中包含背景音乐,除非你传递 --no-audio,否则会拒绝渲染为 GIF。

使用 --batch 时,一份简报加一个行数据文件会生成 N 个视频:HyperFrames 原生渲染每一行,Remotion 则为每一行生成一个 props 文件。批处理模式下只有视频,如果简报中包含背景音乐,除非你传递 --no-audio,否则会被拒绝。

完成条件: 输出文件存在,报告显示 rendered,其 notVerified 列表为空或者你已告知用户列表中的内容,并且文件的第一帧和最后一帧都是有意设计的。


无声失败的契约检查

HyperFrames — 四项,全部必需:

  1. 根元素必须包含 data-composition-id、data-width、data-height、data-duration、data-start="0"。
  2. 每个时间元素必须包含 id + data-start + data-duration。
  3. GSAP 时间线必须使用 { paused: true } 构建。
  4. window.__timelines[<data-composition-id>] = tl — 键名必须相同。在添加完所有补间动画之后执行。如果遗漏此项,你将得到一个静帧,无任何错误。

Remotion — 三项:

  1. 在入口文件中调用 registerRoot(),在根组件中使用 <Composition>。
  2. interpolate(..., { extrapolateLeft: "clamp", extrapolateRight: "clamp" }) — 每次都要钳位两端。
  3. 组合中不能使用 Math.random() 或 Date.now()。请使用 random(seed)。

决定作品是否显得廉价的关键四原则

这些是最常出问题的地方。完整集合及代码示例请参阅 references/motion-craft.md。

  1. 只移动活动的部分。 已就位的元素保持静止。空闲时“呼吸”式的缩放看起来像机器生成的。
  2. 重叠,不要排队。 交错约 15–30% 的元素自身时长。下一个元素在上一个元素还在收尾时就开始。
  3. 文字不要有弹跳效果。 过冲(overshoot)适用于有质量的物体——卡片、翻板、角色。文本、数字和 UI 标签使用 power3.out / expo.out,绝不产生过冲。
  4. 单个动效传达单一意图。 y + opacity 表示“正在出现”。增加旋转和缩放后,文字在飞行过程中将无法阅读。

另外:一个转场应当是一个退出,而不是一个淡出后再接一个淡入。后者渲染出来会是一个中间变暗的跳切。


发布检查清单

  • brief.json 已验证:定时节拍,第一帧有意设计,结尾停留 ≥ 2 秒。
  • check-contract.mjs --runtime 输出 verified,或未验证的 ID 已按名称接受并向用户报告。
  • 文案、数字、链接和 URL 与要求完全一致——没有假文(lorem),没有占位符。
  • 时间线已使用组合 ID 注册(HyperFrames),或 npx remotion compositions 能列出组合(Remotion)。
  • Lint/检查无报错。
  • <out>.report.json 显示 rendered,并包含预期的尺寸、帧率、时长和音频信息。
  • 帧画面已检查:每个拍点、每个衔接帧、手机宽度——切点处无黑屏,

…

[翻译截断]

相关技能