用 Claude Code + Remotion 做有高级感的动效视频:让每一帧都可审查
最近,「让 Claude Code 用 Remotion 写视频」成了很多人的新玩法:描述一下产品,几分钟后 Remotion Studio 里就有一条带标题、卡片、转场和数字滚动的宣传片。这段时间我主要用 Opus 5.5 驱动 Claude Code 做这件事,做过几条产品介绍和文章配套短片。
生成出来并不难,难的是让它看起来不像 AI 随手生成的:没有满屏渐变和到处回弹的弹簧,镜头有呼吸,信息一条一条交代清楚,转场不抢戏。
这篇文章把这套技术栈拆成三层:
- Remotion 的心智模型:为什么视频可以是一个 React 组件,以及它对写法的硬约束;
- 高级感从哪里来:先定一套动效 tokens 与场景结构,再让 Agent 往里填内容;
- 怎样与 Claude Code 协作:分镜先行、骨架先行、关键帧审查,最后才导出。
交互演示: 打开「视频是帧的函数」演示,拖动时间轴到任意一帧,切换缓动和错峰,看同一段画面的气质如何变化。
一、视频是帧的函数
Remotion 的核心可以用一句话概括:给定帧号,返回这一帧的画面。
你写的是普通的 React 组件,组件里通过 useCurrentFrame() 拿到当前帧,位置、透明度、缩放都由它算出来。渲染时,Remotion 用无头 Chromium 打开页面,逐帧设置帧号并截图,最后交给 FFmpeg 编码成视频。
这带来两个直接的约束:
- 时间不是墙上的时钟。 渲染一帧可能要 200ms,帧也可能被分到不同标签页里并行、乱序地渲染。CSS
transition、@keyframes、Tailwind 的animate-*,以及依赖requestAnimationFrame自己计时的动画库,在预览里看着还行,导出后就会跳帧、错位或干脆不动。 - 同一帧必须永远长一样。
Math.random()、Date.now()、还没加载完的字体和图片,都会让第 45 帧在两次渲染里不一致。
所以在 Remotion 里写动画,本质上是在写插值:把一段帧区间映射到一个数值。
interpolate() 默认不夹取:第 0.8 秒之后 progress 会继续涨到 1 以上,元素会一直往上飘。除非你有意利用外推,否则两侧都写上 clamp。
几块最常用的积木:
还有一条容易忽略的规则:<Sequence> 里的子组件,useCurrentFrame() 从 0 开始计数。 场景因此可以只关心自己的相对时间,既能单独开发,也能单独注册成一个 Composition 预览。
二、准备环境:项目、Skills 与 Studio
第四行安装的是 Remotion 官方维护的 Agent Skills(也可以用 npx remotion skills add)。它把上一节的约束写成了 Agent 能读懂的规则:所有动画由 useCurrentFrame() 驱动、CSS 动画与 Tailwind 动画类要改写、计时组件加 premountFor、用 @remotion/google-fonts 加载字体、多场景用 TransitionSeries 并扣减转场重叠的时长等。入口 /remotion-best-practices 会按任务路由到具体的子规则,/remotion-docs 则在动手前查当前版本的 API。
Skills 还约定了一个很好的默认行为:先打开 Studio 预览,不默认渲染视频。 Claude Code 桌面版自带浏览器面板,可以用 npx remotion studio --no-open 启动,再在面板里打开打印出来的地址,一边写一边看。
给项目补一份审美约定
官方 Skills 管的是「Remotion 怎么写才对」,不管「怎么写才好看」。审美上的约束需要自己写进项目的 CLAUDE.md:
这份文件的作用不是教 Agent 写代码,而是缩小它的选择空间。模型的默认审美是「把能加的效果都加上」,明确的禁止项比任何形容词都有效。
三、高级感从哪里来:先定动效系统
回头看那些「一眼 AI」的视频,问题通常不在技术,而在这几处:
- 每个元素都在动,没有主次,观众不知道该看哪里;
- 所有元素用同一个弹簧、在同一帧进场,画面像被一次性倒出来;
- 节奏匀速:每个镜头都是 3 秒,停留时间不随信息量变化;
- 转场抢戏:每次切换都换一种 slide、flip、wipe。
高级感几乎都来自约束:少量缓动、少量时长、明确的错峰和足够的停留。把它们写成 tokens,所有场景共用:
再加两个小函数,让场景里的入场、退场都读起来像一句话:
这里有一个取舍需要说明:官方 Skills 建议把 interpolate() 直接写在 style 里,这样能在 Studio 中可视化地拖动关键帧,改动会写回代码。收进 helper 之后,这部分可编辑性就没了。我的做法是:品牌片、系列视频用 tokens 保证一致;一次性的、需要在 Studio 里手调的镜头保持内联写法。
为什么是这几组数?
ease.out的前段很陡:元素在前 30% 的时间里走完大部分路程,剩下的时间慢慢落定。观众看到的是「已经到了,正在安顿」,而不是「还在路上」。- 错峰 3 帧(0.1 秒) 刚好能被感知为先后顺序,又不至于拖沓;一组超过 6 个元素时,可以把错峰压到 2 帧,或者分批进场。
- 退场比入场短,因为观众已经读完了,不需要再「欣赏」一次离开。
- 停留按字数算:短片最常见的问题是信息还没读完就切走了,
holdFor()把「够不够读」变成一个可计算的值。
在交互演示里把缓动切到「匀速」或「过度回弹」,再关掉错峰,就能直观感受到这几组数的差别。
四、场景结构:一个场景一个文件
主时间线只负责编排:每个场景一个 TransitionSeries.Sequence,场景之间统一用 15 帧的淡入淡出。
两点值得注意:
- 全片只用一种转场。 统一的淡入淡出几乎不会出错,观众的注意力留给内容;真正需要强调的一次切换,再单独换成
slide()或wipe()。 - 转场会让相邻场景重叠。 这条时间线的总时长是
75 + 150 + 75 − 15 − 15 = 270帧,不是 300 帧。忘记扣减时,最后一个镜头会被截断。
场景写成可以独立运行的组件之后,还可以把每个场景也注册成一个 Composition(官方 Skills 称之为 connected compositions),在 Studio 里单独预览、单独调时长,不用每次从头播放整条片子。
五、四个可复用的动效配方
下面四个组件覆盖了产品短片里最常见的画面:标题、镜头、数字、操作演示。它们都只依赖 frame,可以在任意场景里组合使用。
1. 标题:按词遮罩显现
- 每个词放进一个
overflow: hidden的外层,内层从 105% 处升上来。文字像从一条看不见的基线里被推出来,比「淡入 + 上移 40px」干净得多。 Intl.Segmenter能按词切分中文(「动效设计」会切成「动效」「设计」),比逐字显现更沉稳;英文则按空格切开。- 外层的
paddingBottom给 g、y 这类字母的下伸部分留出空间,否则会被遮罩切掉。
2. 镜头:给静态画面一点呼吸
画面完全静止时,视频会显得像幻灯片。整个镜头期间缓慢推近 3%–5% 就足够了;推到 10% 以上就成了「手机变焦」。镜头运动放在最外层,元素入场写在里层,两者互不干扰。
在 <Sequence> 里调用时,useVideoConfig() 返回的是这一段的时长,所以同一个 Camera 放进任何场景都会自动铺满该场景。
3. 数字:滚动到位
tabular-nums 让每个数字等宽,滚动时整串数字不会左右抖动。ease.out 让末尾几位慢下来,观众能看清它停在了哪里。
4. 光标:移动、按下、回弹
- 路径用
ease.inOut而不是线性插值:人移动鼠标时,起步和到位都会减速。 - 按下只占 2 帧,回弹 6 帧,比真实点击略夸张一点,在视频里才读得出来。
- 涟漪用
spring()的delay从点击那一帧开始,只出现一次。产品演示里最容易「廉价」的,就是循环不停的脉冲光圈。
六、和 Claude Code 协作:分镜先行,关键帧审查
有了约定、tokens 和配方,剩下的就是让 Agent 按顺序把片子做出来。我目前稳定下来的流程是这样的:
第一步:只要分镜,不要代码
得到的分镜表大致是这样:
分镜表是最便宜的修改点:在表里把第 2 镜从 4 秒改成 5 秒,只是改一个数字;等代码写完再改,就要连带调整一串帧偏移。它同时给了每个场景一份明确的验收标准,Agent 自查时有据可依。
第二步:骨架先行,再逐场景填充
确认分镜后,先让 Claude 写出 Root.tsx、Launch.tsx 和几个只有占位文字的空场景,在 Studio 里确认总时长和转场位置是对的,再一个场景一个场景地实现。每次只改一个场景,出问题时的范围也最小。
第三步:关键帧审查
Studio 适合看节奏,但「第 140 帧两张卡片叠在了一起」这类问题,靠盯着播放很容易漏掉。让 Claude 自己截取关键帧并读图检查:
每个场景取三帧:入场进行中、停留、退场前。然后让它对照分镜表和 CLAUDE.md 逐项检查:文字是否出了安全区、画面里是否只有一个主角、颜色有没有越界、是否出现了意外的半透明叠加。Claude Code 能直接读取 PNG,这一轮自查能拦下大部分低级问题,你只需要处理审美判断。
节奏问题看单帧是看不出来的。需要整体判断时,导出一版半分辨率的预览,按真实速度看一遍:
第四步:用动效语言给反馈
反馈越具体,迭代越快。比起「感觉不够高级」,下面这样的描述能直接落到代码上:
- 「标题入场有回弹,改成
ease.out,不要超调。」 - 「第 2 镜信息还没读完就切了,停留时间按
holdFor()重新算。」 - 「第 140 帧两张截图重叠,第二张推迟 6 帧进场。」
- 「数字和卡片同时在动,主角是数字,卡片先静止。」
指出帧号、指出 token、指出主角,这三件事比任何形容词都有效。
第五步:导出
需要竖版时,不必另做一条片子:用同一组场景组件注册一个 1080×1920 的 Composition,只调整布局参数。动效 tokens 和时间线完全复用。
七、常见坑
还有一点和代码无关:Remotion 不是 MIT 协议。 个人、非营利组织以及 3 人以内的营利公司可以免费使用;4 人及以上的公司需要购买公司授权。在团队里推广之前,先确认授权条款。
结语
Remotion 让视频变成了代码,Claude Code 让写代码变得便宜,但「好看」不会因此自动发生。
真正值得沉淀的,是那几十行 motion.ts、一份 CLAUDE.md 和一张分镜表。它们把你的审美写成了 Agent 可以遵守的约束:Agent 负责把每一帧写出来,你负责判断哪一帧值得被看见。
交付前的自查清单:
- 所有动画都由帧驱动,没有 CSS 动画,也没有未固定种子的随机数;
- 缓动、时长、弹簧只来自
motion.ts; - 每个镜头只有一个主角,停留时间够读完;
- 全片转场风格统一,总时长扣除了转场重叠;
- 每个场景截取三帧检查过安全区、颜色与层叠;
- 按真实速度完整看过一遍半分辨率预览。
参考资料
- Remotion 文档
- Remotion Agent Skills:安装方式与技能列表
- remotion-dev/skills:规则原文,
remotion-markup下的timing.md、transitions.md、sequencing.md值得通读 - Remotion License