Remotion 运动图形 — 基于帧的 2D 视频创作 是做什么的?
Remotion 将 React 渲染为视频。每一帧都是帧索引的纯函数,因此输出是确定性的、可比较的且可审查的。对于以文本和数据驱动的视频,它是默认的最佳选择;同时,它也是将带有排版、字幕和转场的 Blender 或 Manim 渲染片段组装起来的最佳“合成器”。
阅读 references/REMOTION-PLAYBOOK.md 了解约定,以及 references/REMOTION-RECIPES.md 获取可直接复制的组件。请查阅官方文档和已安装的 CLI 以获取当前 API:https://www.remotion.dev/docs/
1. 设置
node --version # 需要 18+,推荐 20/22 LTS
npx create-video@latest my-video # 选择空白模板
cd my-video
npx skills add remotion-dev/skills # 官方 Remotion 代理技能(推荐)
npm run dev # Remotion Studio 运行在 http://localhost:3000
渲染:
npx remotion render <entry> <CompositionId> out/video.mp4 --codec=h264
npx remotion render <entry> <CompositionId> out/preview.mp4 --scale=0.5
npx remotion render <entry> <CompositionId> out/frames --sequence --image-format=png
具体标志因版本而异;请使用 npx remotion render --help 确认。
许可:Remotion 是 源代码可用,但非 OSI 开源。根据其当前条款,个人和符合条件的小型组织可免费使用;大型或商业/自动化用途可能需要付费许可。在承诺交付成果之前,请查阅 https://www.remotion.dev/docs/license/pricing 了解用户的实际使用情况。不要将其描述为“MIT”或“任何公司都免费”。
2. 项目结构
适应启动器而不是与之对抗:
src/
Root.tsx # 注册合成
compositions/
MainVideo.tsx # 场景排序
scenes/
Intro.tsx Feature.tsx Outro.tsx
components/
AnimatedTitle.tsx Background.tsx Grid.tsx Caption.tsx Transition.tsx
animations/
easing.ts timing.ts reveal.ts
data/
content.ts # 文案和数字,与布局分离
styles/
tokens.ts # 调色板、字体比例、间距
public/
audio/ fonts/ images/ video/
规则:
- 每个场景一个文件;
MainVideo仅负责排序。 - 文案和数据存放在
data/中,切勿内联在五个场景中。 - 设计标记在
styles/tokens.ts中;不要到处使用魔术十六进制值。 - 可复用的基础组件在
components/中,切勿在每个场景中重复。 public/下的所有内容使用staticFile("...")。
3. 确定性(硬性规则)
所有视觉状态均源自当前帧:
import { useCurrentFrame, useVideoConfig, interpolate, spring } from "remotion";
const frame = useCurrentFrame();
const { fps, durationInFrames, width, height } = useVideoConfig();
禁止作为动画驱动:Date.now()、setTimeout、setInterval、requestAnimationFrame、CSS keyframes、未初始化的 Math.random()、在渲染之间变化的异步数据。
需要变化时的种子随机数:
export const rand = (seed: number) => {
const x = Math.sin(seed * 12.9898) * 43758.5453;
return x - Math.floor(x);
};
异步资源必须在帧渲染之前解析。正确使用 delayRender/continueRender,始终在 catch 中继续渲染,或者在帧外部预加载资源(推荐)。
4. 时间控制
durationInFrames是显式的。在 30 FPS 下,10 秒 = 300 帧,索引 0–299。- 转换一次:
const s = (n: number) => Math.round(n * fps)。 - 场景边界来自累积时间线,而不是每个场景的舍入。
- 使用
<Sequence from={start} durationInFrames={len}>;检查是否有内容超出合成范围。 - 确保交叠是有意的;一帧的间隙会导致可见的闪烁。
- 当持续时间或尺寸来自 props 时,使用
calculateMetadata。
5. 动画技巧
| 运动类型 | 原始方法 |
|---|---|
| 进入/稳定 | spring 或带 Easing.out(Easing.cubic) 的 interpolate |
| 退出 | Easing.in(Easing.cubic) |
| 对称移动 | Easing.inOut(Easing.cubic) |
| 机械/连续运动 | Easing.linear |
| 数字/颜色/旋转 | 带有钳位外推的 interpolate |
| 交错 | 每个元素偏移 from(30–80 毫秒) |
const enter = spring({ frame, fps, config: { damping: 18, stiffness: 120, mass: 0.8 } });
const opacity = interpolate(frame, [0, 12], [0, 1], {
extrapolateLeft: "clamp", extrapolateRight: "clamp",
});
不要对所有内容都使用 spring。不要对所有属性都进行动画处理。优先使用变换和透明度(GPU 友好)而不是布局属性。确保短标题至少停留 0.8–1.2 秒,正文内容则需要更长时间。
6. 排版与设计
- 设置字体比例(例如,在 1080p 下使用 96/64/40/28/20 px)并始终如一地使用。
- 从
public/fonts使用@remotion/fonts或启动器中记录的加载字体,并在渲染前等待就绪。避免依赖系统字体。 - 检查行长(≈45–75 个字符)、行高(显示字体 1.1–1.4)和字距。
- 保留 5–8% 的安全边距;检查垂直/社交媒体格式的平台 UI 覆盖层。
- 对于波斯语/阿拉伯语:正确设置
dir="rtl",使用支持字形的字体,验证混合数字/URL,并检查渲染的帧——无头 Chrome 对文本的塑形方式与某些设计工具不同。 - 逐字符验证最终文案。视频中的错别字是发布错误。
7. 合成与转场
- 每个节拍一个焦点;引导视线,而不是动画整个屏幕。
- 使用转场词汇:剪切、6–10 帧交叉淡入淡出、蒙版擦除、缩放、模糊过渡。有目的地复用。
- 优先在节拍上剪切,而不是溶解一切。
- 对于长视频,首先构建一个时间线图(秒 → 帧 → 场景)并将其编码在一个文件中。
8. 音频与字幕
import { Audio, staticFile } from "remotion";
<Audio src={staticFile("audio/music.mp3")} volume={0.6} />
- 仅导入到声音应该开始的序列中。
- 使用
interpolate在volume上进行淡入/淡出;避免出现爆音。 - 在语音旁白下压低音乐音量;确保对话清晰可懂。
- 字幕:对于社交媒体,使用
<Caption>烧录,或为平台导出.srt格式。尊重安全区域和阅读速度(约 15–20 字符/秒)。 - 务必在编码后的文件上验证混音,而不仅仅是在预览中。
9. 性能
- 在内存受限的机器上降低并发度:
--concurrency=4。 - 避免巨大的模糊效果、滤镜链、巨大的 SVG 和成千上万的 DOM 节点;对于密集图形,使用 Canvas。
- 缓存静态背景(
<Freeze>或预渲染的图像)。 - 优化图像(正确尺寸,支持 WebP/AVIF 时使用)并修剪视频素材。
- 使用
--scale=0.5渲染预览,并首先测试短帧范围。
10. 批量与数据驱动视频
- 定义 props schema 并在渲染前验证。
- 将数据保存在 JSON/CSV 中;将布局保留在组件中。
- 文本适配:最大行数、回退字体大小、截断规则、溢出测试。
- 对每个变体,使用相同的合成但不同的
--props进行渲染。 - 编写一个清单并验证每个输出的持续时间和非空大小。
npx remotion render src/index.ts Main out/acme.mp4 --props='{"brand":"Acme","tagline":"Build faster"}'
11. 与 Blender 混合使用
- 以 与 Remotion 合成相同的 FPS、分辨率和帧数 渲染 Blender 片段。
- 除非项目定义了偏移,否则将 Blender 帧 1 映射到 Remotion 帧索引 0。
- 对于透明度,导出 PNG 序列或 ProRes 4444,并在棋盘格背景上验证 alpha 通道;MP4 没有 alpha 通道。
- 匹配色彩管线:使用与浏览器输出相同的传递/视图转换假设来编码 Blender 片段,然后检查合成结果。
- 使用
<OffthreadVideo>(而不是<Video>)将片段放置在<Sequence>内部,并根据帧映射设置startFrom/帧偏移。
12. 交付前验证
npx remotion compositions src/index.ts # 列出 ID 和尺寸
ffprobe -v error -show_entries format=duration,size \
-show_entries stream=codec_name,width,height,r_frame_rate,pix_fmt,channels \
-of json out/video.mp4
然后检查第 0 帧、每个场景边界、每个转场、每个文本密集的帧以及最后一帧。检查是否有裁剪的文本、缺失的字体、黑帧和音频漂移。请参阅 video-composition 了解编码/规范化方法,以及 motion-studio/references/QUALITY-CHECKLIST.md 了解完整的检查清单。
13. 常见失败模式
- 未找到合成 → 入口文件或 ID 错误;运行
npx remotion compositions。 - 空白渲染但预览正常 → 资源路径在 Studio 中解析但在无头环境中无法解析;使用
staticFile,检查public/大小写。 - 字体回退为 Times → 渲染前未加载字体;等待就绪。
- 不同渲染之间的输出不同 → 墙钟时间或未初始化随机数。
- OOM 或极慢 → 降低
--concurrency,减少模糊/缩放,拆分渲染。 - 音频不同步 → 错误的
startFrom,FPS 不匹配,或可变帧率源。