关于 remotion-video
remotion-video 是使用 React 以代码生成 MP4、GIF 和 WebM 的视频制作技能,面向模板化和数据驱动的动态图形。其动画由帧决定,可精确预览、复现并在 CI 中渲染。
主要功能
- 01按帧驱动的确定性动画
- 02Sequence 与 Series 时间线编排
- 03带类型校验的参数化属性
- 04音频与节拍同步
- 05浏览器预览及命令行渲染
适用场景
- 01批量生成个性化社交视频
- 02制作可版本管理的动态图形
- 03在 CI 中渲染 MP4 或 GIF
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ iart-ai/ motion-design-skills --skill remotion-video安装后在 Claude Code 中输入/remotion-video确认已加载。
附带文件README.mdreferences/api-and-patterns.md
详细介绍
Remotion(程序化视频)
在 React 中构建真正的 MP4/GIF/WebM 视频。每一帧都是 useCurrentFrame() 的纯函数,因此输出具有确定性、可拖动浏览、可比较差异,并可在 CI 中渲染。这是 After Effects 的代码优先替代方案,适用于模板化和数据驱动的动态图形。
适用场景
- 通过代码渲染 MP4/GIF/WebM(社交媒体短片、标题卡、解说视频)。
- 模板化/数据驱动的视频:一个合成,基于 props 生成多个输出(按用户、记录或 CSV/DB 的每一行生成)。
- 必须进行版本管理、代码审查,并且无需 GUI 即可在 CI 中渲染的动态图形。
- 程序化音频同步、基于数据制作动画图表,或将着色器/Three.js 嵌入视频。
核心技巧
基于帧的动画
动画由当前帧推导而来,而不是通过 setState 或 requestAnimationFrame 实现。interpolate 将输入范围映射到输出范围;spring 可生成符合物理规律的自然运动。
import {useCurrentFrame, useVideoConfig, interpolate, spring} from 'remotion';
export const Title = () => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
// Fade in over frames 0-30, then stay (clamp prevents over/undershoot).
const opacity = interpolate(frame, [0, 30], [0, 1], {
extrapolateLeft: 'clamp',
extrapolateRight: 'clamp',
});
// Spring entrance; divide by spring duration is unnecessary — drive transforms directly.
const scale = spring({frame, fps, config: {damping: 200, mass: 1, stiffness: 100}});
return <h1 style={{opacity, transform: `scale(${scale})`}}>Hello</h1>;
};
除非需要有意产生超出范围的效果,否则请始终对 interpolate 进行钳制——默认情况下,它会在范围之外线性外推,导致不透明度大于 1 或出现负值。
调度:Sequence 和 Series
<Sequence> 会偏移时间:在序列的 from 位置,子元素看到的 frame 会重置为 0。使用它将片段放置到时间轴上。<Series> 可连续排列各个片段,无需手动计算偏移量。
import {Sequence, Series, AbsoluteFill} from 'remotion';
export const Timeline = () => (
<AbsoluteFill style={{backgroundColor: 'black'}}>
<Sequence from={0} durationInFrames={60}><Intro /></Sequence>
<Sequence from={60} durationInFrames={90}><Body /></Sequence>
{/* Series auto-sequences; offset overlaps the previous segment for crossfades */}
<Series>
<Series.Sequence durationInFrames={60}><ShotA /></Series.Sequence>
<Series.Sequence durationInFrames={60} offset={-15}><ShotB /></Series.Sequence>
</Series>
</AbsoluteFill>
);
合成注册 + 参数化 props
<Composition> 声明 id、尺寸、fps、时长和 defaultProps。zod schema 可确保 props 类型安全,并可在 Studio 侧边栏中编辑。
import {Composition} from 'remotion';
import {z} from 'zod';
export const schema = z.object({
title: z.string(),
accent: z.string(),
fps: z.number().default(30),
});
export const Root = () => (
<Composition
id="Promo"
component={Promo}
durationInFrames={150}
fps={30}
width={1080}
height={1920}
schema={schema}
defaultProps={{title: 'Launch', accent: '#5b8cff', fps: 30}}
/>
);
如需让时长依赖数据,可在 Composition 上使用 calculateMetadata,根据 props 计算 durationInFrames(例如行数 × 每行帧数),并在渲染前完成计算。
音频与节拍同步
import {Audio, staticFile, useCurrentFrame, useVideoConfig} from 'remotion';
const BEATS_SEC = [0.5, 1.0, 1.5, 2.0]; // detected offline
export const Music = ({children}) => {
const frame = useCurrentFrame();
const {fps} = useVideoConfig();
const t = frame / fps;
const onBeat = BEATS_SEC.some((b) => Math.abs(t - b) < 1 / fps);
return (
<>
<Audio src={staticFile('track.mp3')} />
<div style={{transform: `scale(${onBeat ? 1.06 : 1})`}}>{children}</div>
</>
);
};
请离线检测节拍(例如使用 web-audio-beat-detector 或 aubio),并将时间戳写入 props——切勿在渲染时分析音频,因为无头渲染没有实时音频时钟。
渲染
在基于浏览器的 Studio 中预览;通过 CLI 或程序化 API 进行无头渲染。
npx remotion studio # interactive preview
npx remotion render Promo out/promo.mp4 \
--props='{"title":"Launch","accent":"#f43"}' # pass parametric props
npx remotion render Promo out.gif --codec=gif # GIF output
对于批处理/数据驱动的流水线,可在 Node 中使用 @remotion/renderer 渲染(打包一次,渲染多次)——参见参考文件。
交付与验证(渲染静帧 → MP4)
打包的辅助工具(
scripts/):使用scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png将静帧拼成图集,然后使用scripts/probe-mp4.sh out.mp4 [WxH] [fps]验证编码结果。参见scripts/README.md。
Remotion 从设计上就是逐帧确定性的——每一帧都是 useCurrentFrame() 的纯函数,因此无需寻帧工具,就能在无头模式下渲染任意指定帧(相当于 Web 场景中 ?t=N 的重型版本)。当输出必须是 MP4/GIF、必须包含精确的数字或文本,或者需要根据数据批量生成时,使用此方案;对于轻量级 Web 动画,则交付独立 HTML。
输出约定:
- 一个已注册合成的 Remotion 项目(
<Composition>+ zodschema+defaultProps),所有动画均由帧驱动(不使用计时器 /Date.now()/Math.random())。 - 交付物 = 渲染好的
out/*.mp4(以及项目,以便用户使用新的 props/数据重新渲染)。 - 时长取决于数据?在
calculateMetadata中计算,不要手动填写。
验证循环——渲染静帧 → 检查 → 编码。 先渲染单帧(成本低,无需视频编码),检查无误后再完整编码视频。
# 1. Frame-exact stills at start / mid / end (PNG, headless, fast)
npx remotion still Promo out/f-start.png --frame=0
npx remotion still Promo out/f-mid.png --frame=75
npx remotion still Promo out/f-end.png --frame=149 # last frame = durationInFrames - 1
# render with the SAME props you'll ship, not just defaultProps:
# npx remotion still Promo out/f-mid.png --frame=75 --props='{"title":"Launch"}'
# 2. Inspect each PNG — fidelity (matches brief; numbers/text correct) AND
# artifacts (text overflow, off-canvas, clipped safe-area, missing font, wrong data binding).
# 3. Only after the stills check out, encode the video:
npx remotion render Promo out/promo.mp4 --props='{"title":"Launch"}'
- 使用
npx remotion compositions查看每个合成的durationInFrames/fps,并确定最后一帧。 - 数据驱动 / 批量生成:先通过静帧验证一组有代表性的 props,再批量渲染所有行——一次发现布局问题,避免重复出错。
- 免费生成 README 演示 GIF:
npx remotion render Promo out/demo.gif --codec=gif会生成首屏展示片段(方向 D)。
完成前:
npx remotion still在第 0 帧、中间帧和最后一帧均可干净渲染——没有错误,也没有缺失资源或字体。- 所有已检查帧中的数字/文本均准确,且位于安全区域内。
- 仅使用帧驱动——不使用
Date.now()/Math.random()/ 计时器(确保在 CI 中保持确定性)。 - Props 使用 zod 类型定义;实际交付的 props 渲染正确(不能只验证
defaultProps)。 - 完整 MP4 已编码并可播放;(可选)为 README 渲染 GIF。
快速参考
| 需求 | 用法 |
|---|---|
| 将时间映射为数值 | interpolate(frame, [a,b], [x,y], {extrapolateRight:'clamp'}) |
| 自然缓动 | spring({frame, fps, config}) |
| 在 t 时刻放置片段 | <Sequence from durationInFrames> |
| 连续播放镜头 | <Series> |
| 音频 | <Audio src={staticFile(...)} /> |
| 帧 ↔ 秒 | frame / fps |
| 循环一个数值 | frame % period,然后插值 |
| 可编辑 props | 在 <Composition> 上定义 zod schema |
| CI 渲染 | npx remotion render 或 @remotion/renderer |
注意事项
- 绝不使用
Math.random()、Date.now()或动画计时器——它们会破坏确定性。使用 Remotion 的random(seed)实现稳定的逐帧随机性。 - 通过
staticFile()加载字体和资源,并使用delayRender/continueRender等待加载完成,否则字体可能会在渲染过程中途突然出现。 interpolate默认会进行外推——请限制范围。<Sequence>内的useCurrentFrame使用局部帧号(从 0 开始);绝对时间请使用useVideoConfig().durationInFrames。
参考文件
references/api-and-patterns.md—interpolate选项和Easing、spring 配置示例、Sequence/Series 排程、<Audio>与节拍同步、使用 zod +calculateMetadata设置参数化defaultProps、CLI 标志、通过@remotion/renderer以编程方式批量渲染,以及嵌入 GLSL 着色器 / Three.js(@remotion/three)。