dolly: 用代码制作产品视频和动态图形
该视频是一个 Remotion 项目:React 组件逐帧渲染。此文件旁的 starter/ 文件夹包含两个可用的视频示例:Video(一个 41 秒的 Termary 启动视频剪辑,由真实录制素材构成)和 Promo(一个 25 秒的仅使用模板的动态图形剪辑)。两者均可在 8 种风格和 4 种格式下渲染。你需要将其转化为用户所需的视频,同时保留其成功要素。
规划 → 素材(录制或扫描用户的)→ 构建场景 → 审阅帧 → 渲染
你无法观看视频,因此需要通过渲染联系表并读取 PNG 来进行审阅。每次修改后都应执行此操作:大多数不良的动态效果都能在联系表中体现出来。
只读取工作所需的信息。 路径均相对于此技能文件夹:
| 何时 | 读取 |
|---|---|
| 你在 Mac 上录制产品(被观察者操作):应用程序、网站、iOS 模拟器 | references/record-mac.md |
| 用户需要录制:Windows、真实手机、你无法操作的设备或账户 | references/record-elsewhere.md |
| 用户提供他们录制的素材 | references/your-footage.md |
| 基于录制素材构建的场景:3D 工具包和摄像机运动 | references/camera.md |
| 非产品启动视频:活动、招聘、更新日志、数据故事等 | references/agendas.md |
| 选择组件:模板、文本、图形、绘图、背景、转场 | starter/src/library/CATALOG.md |
| 渲染出错,或你在编写新组件 | references/gotchas.md |
1. 开始
<此技能文件夹>/new.sh my-video # 检查 Node,复制 starter,安装所有依赖
cd my-video && npx remotion studio # 可选:用户可在 localhost:3000 上逐帧查看
如果 Node 缺失,new.sh 会使用 Homebrew 安装它,运行 npm install(同时生成音效),下载 Remotion 渲染所需的 headless Chrome,并提示 observee 是否已安装。在 Windows 上,请在 Git Bash 中运行(先执行 winget install OpenJS.NodeJS.LTS)。对于现有的 Remotion 4.0.320+ 项目,请复制 src/kit.tsx、src/look.tsx、src/parts.tsx、src/sequence.tsx、src/backdrop.tsx 和 src/library/。
| 文件 | 内容 |
|---|---|
src/brand.ts | 产品信息:名称、URL、Logo(位于 public/ 中)、强调色和警示色、风格、自定义字体(如有) |
src/look.tsx | 8 种风格和 4 种格式,以及每个部分都通过其读取的 useLook() |
src/Video.tsx、src/Promo.tsx | 视频:场景顺序及长度、声音提示 |
src/scenes/ | 基于 take 的场景。takes.ts 说明了内容在 take 中的位置 |
src/library/ | 组件库,每个项目一个文件夹;CATALOG.md 列出了它们及其属性 |
src/sequence.tsx、src/backdrop.tsx | Scenes 使用转场连接场景;Backdrop 绘制风格的页面 |
src/parts.tsx | 叠加在镜头上的内容:Caption、Tap、Callout、Speed、Pop |
src/kit.tsx | 3D 工具包和摄像机运动(references/camera.md) |
public/takes/ | 录制素材。将其替换为用户自己的素材 |
scripts/ | take.sh 录制 take,scan.mjs(npm run scan)读取录制素材,sfx.mjs 和 music.mjs 制作声音,voice.mjs 制作旁白,library.mjs 重建目录,check.mjs(npm run check)测量渲染,web.mjs(npm run web)制作上传副本 |
Remotion 对个人和不超过 3 人的公司免费;规模更大的公司需要公司许可证(remotion.pro)。如果适用,请告知用户一次。
2. 规划
首先阅读产品网站,然后与用户确定以下内容,仅询问你无法推断的信息:
-
播放位置:决定格式和时长。渲染他们需要的每种格式;以主要格式进行设计,并检查其余格式。
格式 组合 尺寸 适用场景 时长 landscape Video1920×1080 YouTube、X、LinkedIn、网站、演讲 启动视频 45–90 秒 vertical Vertical1080×1920 Reels、TikTok、YouTube Shorts、Stories 15–35 秒 square Square1080×1080 X、LinkedIn、Instagram 的信息流 15–45 秒 portrait Portrait1080×1350 Instagram 和 LinkedIn 的信息流 (4:5) 15–45 秒 信息流默认静音播放:文字承载故事,前 2 秒必须能独立吸引观众。
-
风格。以每种风格渲染一帧(
npm run styles,添加--props='{"frame":420,"format":"vertical"}'可指定其他帧或格式),展示给用户,并设置brand.style。根据品牌建议一种风格:深色开发者工具 → midnight 或 terminal,消费类应用 → soft 或 bold,高端或沉稳产品 → editorial 或 swiss,预告片 → cinema,创意或工艺型产品 → paper。风格 外观 editorial浅色纸张,衬线标题与斜体强调短语,硬切。沉稳且高端:示例 Termary 视频 midnight近乎黑色,强调色发光,紧凑无衬线,文字模糊进入,缩放转场 bold强调色作为页面,巨大粗体字,强调短语从色块中透出,弹性弹出,滑动 swiss米白色,黑色文字位于网格列上,强调色少量使用,方形卡片,硬擦除 soft强调色的柔和色调,圆角文字,强调短语位于药丸形状中,弹性弹出,圆形揭示 terminal全部等宽,标题带光标打字效果,扫描线,故障切换 cinema预告片风格:近乎黑色,大而安静的衬线,胶片颗粒,通过黑色缓慢淡入淡出 paper用代码绘图:浅薰衣草色页面上的纸质卡片,浅色衬线与粗体强调色,卡片翻转 -
观众应记住的一句话,产品中证明这一点的真实瞬间,以及结束卡的要求(URL、下载链接、候补名单)。
-
素材来源。具有界面的产品使用真实素材,这优于任何模拟:你可以录制、用户录制,或用户已有(上表说明了应读取的内容)。如果无法访问产品,或用于预告片或讲解视频,则从库中构建。
然后按顺序编写场景:痛点(吸引点,绝不用 Logo)、产品(在节拍点出现 Logo)、证明(真实瞬间,或功能、指标、前后对比)、要求(结束卡)。其他主题保持类似结构,但使用自己的中间部分(references/agendas.md)。屏幕上同时显示最多 7 个词,每个词停留 1 秒 + 0.3 秒。将概要放入 Video.tsx 顶部的注释中。
3. 素材
无论素材来自何种方式,使其可用的要素相同:停顿(每个操作前后保持 4–5 秒的状态:镜头由此裁剪)、真实产品(绝不使用演示模式的虚假结果,绝不使用私人数据),以及你从中读取的时间点。npm run scan 可读取任何录制素材:其停顿、变化和声音,并生成帧的联系表,从而让你能够基于无人向你描述过的素材进行规划。这些时间点就是镜头播放的 at 值。
4. 构建场景
场景是填充帧的组件。Video.tsx(或 Promo.tsx)中的 SCENES 按顺序列出场景及其时长;风格转场连接它们,场景可以指定自己的转场(例如 transition: 'iris',即进入该场景的转场)。在每次移动整个帧的转场(滑动、抽打、缩放)下播放一个 "whoosh" 音效。
库(src/library/)包含所有现成组件,每个组件一个文件夹:模板(完整场景)、文本效果、图形、绘图、旁白部分、背景和转场。在构建之前,请先阅读 src/library/CATALOG.md:每个项目的摘要、可直接使用的用法行及其属性。从库中导入(import {Stat, Statement} from './library')。每个项目通过 useLook() 读取风格,接受 start(从其场景开始起的起始帧)和 exit(如果可退出)。npm run gallery 渲染每个项目的示例,并用其代码标记(--props='{"only":"graphics","style":"bold","format":"vertical"}' 可缩小范围)。
模板是一个完整场景,因此可直接放入 SCENES:
{name: 'Features', seconds: 4.5, component: () => (
<Features title="Everything in" accent="one window." items={[{icon: Columns3, title: 'Split panes', text: '…'}]} />
)},
基于录制素材的场景会在 3D 空间中浮动窗口、面板或手机,并叠加 Caption,摄像机在其上方移动:请参阅 references/camera.md。
善用库。
Metric、Stat和Quote仅使用真实的数字和引文,并需获得许可。- 绘图会向品牌色靠拢:以获得工艺感和人性化效果,尤其适用于
paper风格。 - 旁白:
npm run voice -- script.txt name使用 Mac 或 Windows 内置语音(或使用录制的 WAV 文件)将脚本朗读到public/voice/name/和src/voice/name.ts中。Voiceover播放它,voiceTiming/voiceEnd使场景与其同步,Captions和Waveform跟随它。信息流默认静音:即使有旁白,仍需字幕。内置语音仅适用于草稿;对于已发布的视频,请录制真人语音或使用用户拥有权限的语音。 - 目录中称为 WebGL 着色器的转场仅作为强调使用:检查最终渲染中其前后的每一帧。
- 回馈视频中创造的内容。 其他视频可能使用的布局、控件或运动效果将成为项目库中的一个项目(一个包含组件、其示例
<name>.demo.tsx和item.json的文件夹,然后运行npm run library),并询问用户是否也将其添加到 dolly 自身的库中。
一个项目中多个品牌(客户变体,或每个产品一个视频):
使用 <LookProvider style="soft" brand={{name, url, logo, accent}}> 为内部所有内容设置品牌,并使用 useBrand() 读取品牌。
每种格式。 场景通过 useLook() 读取帧:look.safe(平台自带按钮覆盖的内边距:文本保持在内)、look.band(顶部的标题带)、look.aim(传递给 focusOn)、look.size(标题尺寸)、look.tall,以及用于选择布局的 byShape(look, {wide, tall, square})。
5. 品味
以下要素使视频在任何风格下都显得高端:
- 产品自身的外观。 其强调色、字体(
brand.fonts)、Logo、适合它的风格。 - 每个镜头都有标题,位于顶部的标题带中,强调短语以该风格的方式设置。
- 真实事物,紧密裁剪。 整个窗口、单个面板作为浮动卡片、Mac 旁边的手机。一个场景通常包含两到三个剪辑,字幕随剪辑变化。紧密裁剪到推近镜头所指向的内容。
- 显示输入操作。 在被点击处使用
Tap,在重要内容周围使用Callout或Spotlight,在模板上使用Cursor,在素材被加速时使用Speed控件。 - 每个转折点都有音效,其他则尽量少用。 在每个故事转折的时刻,在其变得可读的那一帧(而不是小节线之后)使用
public/sfx/ting.wav;点击时使用click.wav;仅在移动整个帧时使用whoosh.wav(视频在移动式转场(滑动、抽打、缩放、翻转)下播放一次,最多每 8 秒一次),每个视频大约两次。保持效果大约每 10 秒 5 个,让音乐承载其他剪辑:可以使用用户已获得许可的音轨,或运行npm run music -- <seconds>。 - 避免生成设计的常见问题: 渐变文本、紫色到蓝色渐变、深色背景上的青色、所有卡片相同、每个词都加效果、一个视频使用五种转场。一个想法使用一种效果,一个视频使用一种转场风格(可加一种强调转场),优先使用风格的默认设置。
运动规则。 对照它们检查每个镜头。
- 移动摄像机,而非对象。 每个镜头一条摄像机路径;纵深产生视差。
- 每镜头一个动作,并有理由:揭示、跟随或推近至重要内容。
- 平坦以便阅读。 当有文字需要阅读时,文字应面向摄像机并缓慢移动。
- 所有运动都使用缓动。 到达时使用
ease.out,离开时使用ease.in(更快),两个停顿之间使用ease.inOut。仅在风格需要弹性或用于 Logo 时使用弹跳效果。 - 永远不要完全静止。 每个镜头都应有缓慢的漂移(使用
useShot的第二个参数)。 - 停留足够长的时间供阅读,然后切换。如有疑问,停留更长时间并缩短下一场景。
- 在节拍上切换(120 BPM 时为 0.5 秒),并保持切换方向一致:场景离开的方向应和下一场景到达的方向相同。
- 克制。 产品是明星:每 10 秒最多一个炫耀性动作或效果。
优秀启动视频的关键数据(逐帧测量):画面在 0.1 秒内开始运动,第一个词在 0.4 秒内可读;产品在四分之一时间点前出现在屏幕上;大约每 0.7 秒发生一次变化,即使在长镜头内也是如此;正在阅读的文字每帧移动约 3 像素;关键主张处有一个 1–1.6 秒的设计性停顿,其他超过 0.8 秒的静止都不存在;最重大时刻出现在运行时间的 80% 左右,然后是一个约 2 秒的平静结束卡。
references/gotchas.md 包含陷阱:哪些因素会使 3D 变平,哪些因素会破坏逐帧渲染,捆绑的 ffmpeg 的限制。
6. 审阅
npx remotion still Sheet out/sheet.png # 视频,1 帧/秒
npx remotion still Sheet out/focus.png --props='{"scene":"NeedsYou","every":6}' # 单个场景,5 帧/秒
npx remotion still Sheet out/v.png --props='{"format":"vertical","guides":true}' # 其他格式,显示安全区域
npx remotion still Vertical out/f140.png --frame=140 # 单帧,全尺寸
npm run styles && npm run formats # 每种风格/格式的一帧
读取每张 PNG。检查:
- 前 2 秒在无声音和无上下文的情况下是否有意义;
- 所有可读内容是否正面面向摄像机并保持足够长的时间(连续几个几乎相同的单元格);
- 文本在所有格式下都位于虚线安全区域内,主体位于点线之间;
- 没有重要内容被帧边缘裁剪、被更近的层遮挡或被字幕覆盖;
- 没有帧是空白或镜像的(摄像机位于某物内部或后面);
- 相邻单元格…
…(已截断,准备翻译)