/remotion-best-practices
每当您编写 Remotion 合成时——动画演示视频、产品导览、黑客松提交作品、旁白演示——任何通过 npx remotion render 渲染为 MP4 的内容,都应使用此技能。
该技能包含两个知识层次:
- Remotion 基础——由 Remotion 团队在
github.com/remotion-dev/skills维护的上游规则文件(合成、动画、字体、音频、过渡、FFmpeg、字幕等)。 - 演示视频精加工规则——从构建 vskill / Skill Studio 黑客松演示的长期迭代中总结的经验。这些规则一旦违反,就会产生“幻灯片”效果,而不是令人信服的产品导览。
在编写之前,请阅读这两个层次。
范围与适用性
下面的第二层精加工规则源自一个特定项目:vskill / Skill Studio 黑客松演示(Anthropic / Claude Code "Built with Opus" 黑客松,2026 年 4 月)。 它们反映了该产品的视觉风格——带有面包屑导航头、侧边栏树、深色 verified-skill.com 页面(单色字体)、终端场景,以及“Inter 是 AI 垃圾,独特的衬线体才是卓越”的编辑论点。
不要将这些规则逐字应用于不相关的演示。 消费级移动应用、金融仪表盘、游戏或 B2B SaaS 推销会有其自身的视觉语言、节奏和受众期望。保存然后发布流程、
verified-skill.com/queue页面或带有 PROJECT/PERSONAL/PLUGINS 计数的 Studio 侧边栏是 内容,而非 技巧。将此层用作底层技术的参考: 摄像机缩放模式、光标定位规则、内容精确的高亮矩形、就地状态转换、旁白/script.ts 耦合、渲染+音频增强管道——这些是可以通用的。确切的常量(1.72× 缩放、x=1488 按钮中心、v1.0.0 → v1.0.1 版本药丸、“一级模式 · 二级 LLM · 套接字”属性)是 Skill Studio 的特例——请转换,而非复制。
第一层——Remotion 基础
镜像了 github.com/remotion-dev/skills/blob/HEAD/skills/remotion/SKILL.md 的上游 remotion-best-practices 技能。
新项目设置
当在一个空文件夹或没有现有 Remotion 项目的工作区时,使用以下命令创建一个:
npx create-video@latest --yes --blank --no-tailwind my-video
启动预览
启动 Remotion Studio 以预览视频。Studio HMR 会在文件更改时热重载——您不需要单独的 preview_start 机制,并且 Bash 的 run_in_background 是在编辑期间保持其运行的正确方式。
npx remotion studio --port=3030
渲染
# 入口点必须是调用 registerRoot() 的文件(通常为 src/remotion/index.ts)
npx remotion render src/remotion/index.ts <CompositionId> out/video.mp4 --concurrency=8 --log=info
常见陷阱:
- 将
Root.tsx作为入口点传递 → 错误:"this file does not contain registerRoot"。请使用index.ts。 TransitionSeries对其直接子元素进行 props 内省;不要将子元素包裹在<React.Fragment>中。使用flatMap返回<TransitionSeries.Sequence>和<TransitionSeries.Transition>元素的平面数组。interpolate(frame, [a, b], …)要求a < b严格成立。如果您从常量推导出b,请在场景预算设计时进行完整性检查——Remotion 会在第一次评估帧时抛出 "inputRange must be strictly monotonically increasing" 错误,导致整个合成无法加载。
单帧渲染检查
npx remotion still <composition-id> --scale=0.25 --frame=30
上游规则文件涵盖的主题
(从上游技能仓库按需加载——github.com/remotion-dev/skills/tree/HEAD/skills/remotion/rules/)
compositions.md——定义合成、静态帧、文件夹、默认属性、动态元数据animations.md——interpolate、spring、缓动、基于帧的数学计算transitions.md——@remotion/transitions(淡入淡出、滑动、擦除),如何在TransitionSeries内链接它们assets.md——staticFile()、Img、Audio、Video、字体加载fonts.md——@remotion/google-fonts和本地字体注册audio.md——导入、裁剪、音量、速度、音高captions.md、subtitles.md——字幕轨道和同步ffmpeg.md——通过 FFmpeg shell 调用来进行裁剪、拼接、音频操作silence-detection.md、extract-frames.md、get-audio-duration.md、get-video-duration.md——Mediabunny 实用工具charts.md、gifs.md、light-leaks.md、3d.md——专门的渲染配方
第二层——演示视频精加工规则
这些是在长期迭代周期中总结的规则。请将它们视为默认设置,而非可选的润色——大多数规则来自“这看起来很奇怪,请修复”的反馈,这些反馈经过多轮迭代才得到解决。
A. 参考帧 fidelity
A1. 始终提取真实的参考帧
如果用户说“使其看起来像这个 YouTube 视频的 2:43 处”,则提取帧并进行研究。不要凭记忆近似。
SOURCE="/Users/antonabyzov/Movies/.../Source.mov"
DEST_DIR=".specweave/.../assets/keyframes"
for t in 102 105 108 110 112; do
ffmpeg -y -ss "$t" -i "$SOURCE" -frames:v 1 -q:v 2 "$DEST_DIR/at-${t}s.jpg" -loglevel error
done
然后 Read 每个 JPG 并根据屏幕上实际显示的内容进行设计——排版、确切的按钮标签、徽章颜色、侧边栏树布局、搜索输入位置、计数值(例如 PROJECT (1)、PERSONAL (0 of 12)、PLUGINS (0 of 50)、AVAILABLE (62))。
A2. 使用真实的 Logo 和图标,而非近似值
- 铃铛徽章
skill-studio-logo.png——复制到每个 Studio 场景中,作为<Img src={staticFile("...")} />。不要渲染一个✷字形就称之为 Logo。 - 提供商图标——从 Claude、Anthropic、OpenAI、OpenRouter、Ollama、LM Studio 获取真实的 SVG/PNG(例如,从
lobehub/static-png获取)。不要用 emoji 替代。 - 吉祥物——使用带样式的 div 绘制以精确匹配形状。Claude Code 吉祥物是一个桃色
#e08160身体,有两个方形眼睛,身体中部有两个侧手结,以及下面有两对腿(▪ ▪ ▪ ▪)。不是 ASCII 艺术。 - 应用窗口 chrome——当在“Chrome 浏览器”中显示网站时,渲染一个真正的 Chrome 浏览器框架:圆角、三色信号灯、‹ › ↻ 导航、锁定挂锁 URL 栏,带有真实 URL(
localhost:3000/hero,无多余空格,无中间点)。
A3. 逐像素匹配 YouTube 参考布局
在根据想象重新设计场景之前,列出参考帧中的可见元素,并对照您的输出逐一检查:
- 横幅文本——确切的措辞(
Submit skills for verification,而不是Submit a Skill) - 标签页顺序——
Overview · Edit · Tests · Run · Trigger · Versions - 信任徽章——
T1 UNSCANNED、Security-Scanned —、Trusted Publisher - 筛选输入——始终在侧边栏的
AVAILABLE之上 - 计数——在所有幻灯片中保持一致(到处是
PERSONAL (0 of 12),而不是一张幻灯片上是(11),另一张上是(0 of 12)) - 标题右侧控件(按此顺序):
🔍 Find skills [⌘K]·+ New Skill·● Model selector·🔔 bell
B. 摄像机缩放
B1. 摄像机缩放是全画幅的,而非局部缩放
不要在 chrome 内部缩放单个面板。将**整个 chrome(顶部栏 + 主体)**包裹在一个 transform div 中,并进行缩放和平移:
<div
style={{
width: "100%",
height: "100%",
transform: `translate(${cameraTx}px, ${cameraTy}px) scale(${cameraScale})`,
transformOrigin: "50% 50%",
willChange: "transform",
}}
>
{/* 顶部栏 + 主体 */}
</div>
光标 + 点击波纹 SVG 放置在此包装器内部,以便它们随 chrome 一起缩放并保持粘贴在其目标上。
B2. 先点击,再缩放
观众需要先看到上下文中的点击目标,然后被带入以查看结果。顺序:
帧 130 光标接近按钮
帧 174 点击波纹
帧 184 按钮显示“Running…”
帧 188 摄像机缩放开始(1.0 → 1.55+ 在大约 30 帧内)
帧 220+ 保持缩放——级联 / 结果 / 滚动揭示在此发生
先缩放再点击感觉像是一个演示幻灯片。先点击再缩放感觉像是用户执行了操作,摄像机跟随了。
B3. 选择一个实际上将 chrome 推出画布的缩放比例
适度的 1.1× 几乎不会改变任何东西。要使“顶部栏离开画布顶部”,您需要 ≥ 1.5× 缩放,并结合一个将焦点带到画布中心的平移。计算目标 ≥ (canvasHalfHeight) / (distance from focal point to top bar)——对于 y=540 的一行和 64 像素的顶部栏,这大约是 ≥ ~1.5×。使用 1.55–1.85× 作为“填充视口”的默认值。
C. 光标点击目标
C1. 精确命中实际元素
当光标落在错误的按钮上(+ New Skill 而不是模型选择器药丸)时,观众会认为演示有问题。每次都要从布局重新推导目标——不要猜测像素值。
对于一个带有 padding: "0 22px" 的弹性右对齐控件条:
// 右边缘 → 22 内边距 → 铃铛 (32) → 14 → 模型 (~290) → 14 → New Skill (~120) → 14 → Find skills (~150)
NEW_SKILL_PILL_X = 1920 - 22 - 32 - 14 - 290 - 14 - 60 // = 1488(按钮中心)
FIND_PILL_X = 1920 - 22 - 32 - 14 - 290 - 14 - 120 - 14 - 75 // = 1339
一旦您有了常量,在光标接近插值和光标离开插值中都使用它,以便点击波纹精确落在药丸上,而不是在其右侧 200 像素处。
C2. 当光标接近时高亮目标
在共享的标题组件(例如,StudioHeader 上的 findActive、newSkillActive)上添加一个 *Active 属性,光标场景会在接近+点击窗口期间将其打开。按钮获得:
- 1.08× 缩放
- 通过
box-shadow: 0 0 0 4px rgba(99,102,241,0.30)添加柔和的靛蓝或紫色环 transition: all 0.15s ease
D. 高亮和矩形
D1. 高亮矩形是内容宽度的,而非全行
当用户想要一个红色矩形围绕两行终端文本时,不要包装父级弹性列——那会跨越行。请使用:
<div
style={{
display: "inline-flex",
flexDirection: "column",
alignSelf: "flex-start",
width: "fit-content",
border: "2px solid #dc2626",
borderRadius: 6,
padding: "10px 16px",
backgroundColor: "transparent",
}}
>
{/* 两行文本,仅此而已 */}
</div>
任何应该在矩形外部的内容(例如,第三行 "Generating component…")必须是同级元素,而非子元素。
D2. 注释:优先使用矩形而非椭圆
围绕一行的手绘风格矩形描边读起来像是“画布上的高亮笔”,这是大多数用户“高亮这个”的意思。椭圆可能感觉是装饰性的。
<svg viewBox="0 0 1000 100" preserveAspectRatio="none">
<rect
x="6" y="6" width="988" height="88" rx="6" ry="6"
fill="none"
stroke="#ea580c"
strokeWidth="3.6"
strokeDasharray="2160"
strokeDashoffset={2160 * (1 - progress)}
/>
</svg>
D3. 使用橙色 (#ea580c) 表示“这是新内容”,红色 (#dc2626) 表示“这是错误”
同一个演示可以同时包含两者。不要混用。
E. 产品 chrome 的布局模式
E1. Studio 标题是一个单一的共享组件
使用一个 StudioHeader.tsx,具有此规范布局,从每个 Studio 场景调用:
- 左侧:Logo 图片(40 × 40 PNG)+ "Skill Studio" 字标 + 面包屑导航
[Authoring|Available] / [scope] / [folder] / [skill] - 右侧:🔍 Find skills
[⌘K]· ✦ + New Skill · ● Model selector · 🔔 Bell
将 breadcrumb、bellBadge、findActive、newSkillActive 作为属性传递。每个场景的标题因此是像素稳定的。
E2. 侧边栏在 AVAILABLE 上方有一个常量的筛选输入
每个 Studio 侧边栏——Browse、Update、AuthorEvals、ConsumeInstall、AuthorEditAndPublish——都在 AVAILABLE 树上方获得相同的 Filter skills… 输入。在用户已经搜索过的幻灯片上,预填充上下文查询(frontend-design)。
E3. 侧边栏宽度和排版
- 宽度:400 px(或在具有深层嵌套树的幻灯片上为 460 px)
- 外部内边距:24–30 px
- 组标题(
AVAILABLE、AUTHORING):18–19 pt,字母间距 1.6,字重 700 - 子标题(
SKILLS、.CLAUDE):15–16 pt,字母间距 1.4 - 行文本:17–19 pt
- 版本药丸:13–14 pt 等宽字体,1 px 边框,填充 3/10
- 垂直间距:各部分之间 12–14 px,部分标题上方 22–36 px
狭窄密集的侧边栏感觉像设置面板。宽阔开放的侧边栏感觉像真正的产品 UI。
F. 就地状态转换
F1. 不要在不应该感觉为单一屏幕的场景之间向左滑动
如果“点击安装 → 树更新为新技能”应该读作一个连续的交互:
- 在下一个场景上设置
transitionType: null或 将两个场景合并为一个 - 保持场景之间的 chrome 相同
- 动画化变化的元素(计数器翻转、V 形旋转、行滑入)——不要完全淡入淡出
F2. 强烈高亮新项目
桃色背景 + 2 px 实心橙色环 + 投影 + ✓ Just installed 标注药丸是“新到”的正确强度。微妙的背景色调读作默认状态,观众不会注意到。
backgroundColor: "#fff5ee",
boxShadow: `0 0 0 2px ${ORANGE}, 0 8px 22px rgba(234,88,12,0.22)`,
F3. 计数器翻转:脉冲光晕 + V 形旋转
当计数更改时(PROJECT (0) → (1)):
- 旋转 V 形符号
▸ → ▼(200 ms 过渡) - 在计数后面渲染一个短暂的橙色光晕:在 18 帧内从
opacity: 0.45 → 0、scale: 0.4 → 2.2 - 在 24 帧内从
translateY: -12 → 0滑入新的子行
G. 编辑器 / SKILL.md 编辑模式
G1. 替换,而非删除,必填字段
技能必须始终有 description。要升级描述:用红色删除原始行,滑入新描述(后续内容已截断,因翻译限制)