关于 remotion-video
remotion-video 是一项根据视频简报搭建 Remotion 项目的技能,涵盖多种画幅构图、动画场景、音频编排和可复用视觉组件,生成的项目可用 Remotion Studio 打开。
主要功能
- 01三种画幅构图
- 02基于 spring 的场景动画
- 03场景定时与交叉淡化
- 04按场景时间控制音量
- 05可复用场景与视觉组件
- 06适配移动画幅的尺寸
适用场景
- 01搭建产品演示视频项目
- 02制作桌面和移动端视频格式
- 03按时间编排视频场景
- 04添加动态文字和终端效果
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tushaarmehtaa/ tushar-skills --skill remotion-video安装后在 Claude Code 中输入/remotion-video确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/audio.mdcheatsheet.mdprimitives.md详细介绍
使用多格式合成、弹簧动画、节拍同步音频和可复用场景原语搭建 Remotion 视频项目。输出的项目可以立即运行 npx remotion studio。
阶段 1:了解需求
编写任何代码之前,先询问缺少的信息:
I'll scaffold a Remotion video project. Quick decisions:
1. Product name? (used for composition IDs and file names)
2. One-line pitch? (the core message of the video)
3. Scene ideas? (3-8 scenes — what story does each beat tell?)
4. Color vibe?
a) Dark + amber accent (#d97706) — warm, editorial
b) Dark + monochrome — clean, minimal
c) Custom — give me bg, text, and accent hex values
5. BPM of your music track? (default: 115)
6. Font? (default: system stack — or provide .woff2 files for Geist/custom)
如果用户已经在对话中描述了视频,请先提取答案,再提出问题。不要重复询问已有信息。
**用户跳过时的默认值:**25 秒、30fps、6 个场景、深色 + 琥珀色、115 BPM、系统字体栈。
阶段 2:搭建项目
创建以下精确文件树:
[name]-video/
├── package.json
├── tsconfig.json
├── src/
│ ├── index.ts
│ ├── Root.tsx
│ ├── [Name]Demo.tsx # orchestrator
│ └── [Name]Scenes.tsx # scenes + tokens + primitives
├── public/
│ ├── audio/ # user drops .mp3 here
│ └── fonts/ # .woff2 files if custom font
└── out/
package.json
{
"name": "[name]-video",
"type": "commonjs",
"dependencies": {
"@remotion/cli": "^4.0.421",
"@types/react": "^19.2.13",
"react": "^19.2.4",
"react-dom": "^19.2.4",
"remotion": "^4.0.421",
"typescript": "^5.9.3"
}
}
只有在加载本地字体文件时才添加 @remotion/fonts: "^4.0.434"。 否则不要添加。
必须设置 "type": "commonjs"。 ESM 会导致 Remotion 打包器出现问题。
tsconfig.json
{
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
"jsx": "react-jsx",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"]
}
src/index.ts
始终保持一致:
import { registerRoot } from "remotion";
import { RemotionRoot } from "./Root";
registerRoot(RemotionRoot);
阶段 3:合成(Root.tsx)
注册三个合成。三个合成都由同一个组件渲染,宽高比检测在组件内部进行。
import { Composition } from "remotion";
import { Demo } from "./[Name]Demo";
export const RemotionRoot = () => (
<>
<Composition id="[Name]Demo" component={Demo} durationInFrames={750} fps={30} width={1920} height={1080} />
<Composition id="[Name]DemoMobile" component={Demo} durationInFrames={750} fps={30} width={1080} height={1920} />
<Composition id="[Name]DemoMobileLandscape" component={Demo} durationInFrames={750} fps={30} width={1334} height={750} />
</>
);
30fps 下的 750 帧 = 25 秒。 如果用户指定了不同的时长,请相应调整。
切勿构建独立的移动端组件。 在组件内部检测格式:
const { width, height, fps } = useVideoConfig();
const isPhone = height > width;
const isMobileLandscape = width > height && width <= 1400;
const globalScale = isPhone ? 1.14 : isMobileLandscape ? 1.08 : 1;
使用 globalScale 缩放后的 <AbsoluteFill> 包裹整个场景区域。
如果要加载自定义字体,请在 Root.tsx 的模块级别、合成之前调用字体加载器。
阶段 4:场景架构(编排器)
编排器文件([Name]Demo.tsx)负责三件事:定义时间安排、连接音频和排列序列。
场景时间安排对象
const scenes = {
hook: { from: 0, dur: 90 },
xfade1: { from: 86, dur: 10 },
pain: { from: 90, dur: 120 },
xfade2: { from: 206, dur: 10 },
// ... continue for each scene
} as const;
规则:
- 交叉淡化与前一个场景重叠 4 帧(
from = prev scene end - 4) - 交叉淡化时长:10-16 帧
- 场景时长:60-195 帧(2-6.5 秒)。保持简短,不要让任何场景持续过久。
- TypeScript 必须通过
as const将值识别为字面量
序列布局
每个场景与交叉淡化配对,重复以下模式:
const frame = useCurrentFrame();
<Sequence from={scenes.hook.from} durationInFrames={scenes.hook.dur}>
<SceneHook frame={frame - scenes.hook.from} duration={scenes.hook.dur} />
</Sequence>
<Sequence from={scenes.xfade1.from} durationInFrames={scenes.xfade1.dur}>
<CrossfadeTransition frame={frame - scenes.xfade1.from} dur={scenes.xfade1.dur} />
</Sequence>
始终传入 frame - scenes.X.from,让每个场景从局部帧 0 开始。 场景绝不能引用全局帧。
音频
<Audio src={staticFile("audio/music.mp3")} volume={(f) => getMusicVolume(f)} />
使用 references/audio.md 中的 5 层系统构建 getMusicVolume。传入 scenes 对象和转场帧编号。
阶段 5:构建场景
将所有场景组件、设计令牌和原语放入 [Name]Scenes.tsx。
设计令牌
根据用户选择的颜色:
深色 + 琥珀色点缀:
export const colors = {
bg: "#000000", surface: "#080808", surfaceRaised: "#111111",
border: "#191919", borderHover: "#333333", muted: "#555555",
text: "#999999", heading: "#ffffff",
accent: "#d97706", accentDim: "rgba(217,119,6,0.19)",
accentGlow: "rgba(217,119,6,0.07)", accentBright: "rgba(217,119,6,0.35)",
};
深色 + 单色:
export const colors = {
bg: "#09090b", surface: "#18181b", border: "#27272a",
textPrimary: "#e4e4e7", textSecondary: "#c2c2cb",
textMuted: "#ababb5", textDim: "#9595a0", accent: "#e4e4e7",
};
必须包含的原语
从 references/primitives.md 复制:
- SceneWrap — 每个场景都必须使用。负责处理淡入/淡出,并防止 inputRange 非单调。
- SlamText — 逐词弹簧入场动画。用于标题。
- CrossfadeTransition — 场景之间的透明度峰值。必须设置
zIndex: 100。 - TypingEffect — 终端/输入模拟,带闪烁光标。
- GrainOverlay — SVG 噪声纹理(仅琥珀色风格)。
opacity: 0.035,zIndex: 50。 - StageLight + AmbientGlow — 漂移的径向渐变(仅琥珀色风格)。
场景手册
根据用户的需求,从此菜单中选择场景:
| 场景类型 | 时长 | 用途 |
|---|---|---|
| Hook | 2-4.5s | SlamText 标题 + 弹性副标题。吸引注意力。 |
| 痛点/问题 | 4-5s | 终端打字,展示旧方法。「New session」闪现后重置。 |
| 快速/解决方案 | 2-3s | 输入一条命令,显示结果,并以发光脉冲效果呈现「done.」。 |
| 加载/处理中 | 1.5-2s | 表情符号 + 抖动 + 进度条。营造期待感。 |
| 结果/卡片 | 4-6.5s | 项目从不同方向飞入。展示输出质量。 |
| 功能网格 | 2-3s | 2x3 或 3x2 网格,依次以弹簧效果进入。 |
| 反馈/聊天 | 3-4s | 聊天气泡:用户提问(向右滑入),AI 回复(向左滑入)。 |
| 滚动/轮播 | 5-6.5s | 项目通过进入/退出转场效果轮流出现在中心。 |
| 安装 | 3s | 标题 + 安装命令的打字动画 +「done.」。 |
| CTA | 3s | SlamText + 脉冲按钮 + URL。fadeOut: 0(无淡出,视频结束)。 |
场景中的常见模式:
- 每个文本元素都使用
spring()进入,绝不使用原始interpolate()实现运动 - 依次进入:每个项目延迟 3-6 帧
- 完成时的发光脉冲:
interpolate(Math.sin(frame * 0.1), [-1, 1], [0.03, 0.12]) - 轻微缩放漂移:
interpolate(frame, [0, duration], [1, 1.03])
响应式尺寸
每个尺寸常量都根据 isPhone 分支处理:
const fontSize = isPhone ? 148 : 88; // headlines
const subSize = isPhone ? 72 : 46; // subtext
const cmdSize = isPhone ? 72 : 48; // terminal commands
const panelW = isPhone ? 920 : 800; // UI panels
const borderRadius = isPhone ? 20 : 14; // card corners
手机端尺寸大约是桌面端的 1.4-2 倍,并非线性缩放。
完整的弹簧配置表、响应式数值和渲染命令,请参阅 references/cheatsheet.md。
第 6 阶段:注意事项
忽略以下事项会导致视频出现难以察觉的问题:
- 始终限制外推。 每次调用
interpolate()都需要{ extrapolateLeft: "clamp", extrapolateRight: "clamp" }。否则,数值会超出 0/1。 - 非单调 inputRange 导致崩溃。 如果 SceneWrap 中的
fadeOut=0,inputRange 会出现重复值。基础组件中的safeEnd = Math.max(duration - fadeOut, fadeIn + 1)守卫可修复此问题。 - 渲染时字体加载超时。 字体加载的
delayRender()可能在帧数 >700 时超时。请使用--timeout=60000。 - 交叉淡化时的 zIndex。 交叉淡化覆盖层必须设置
zIndex: 100,才能位于场景内容上方。 - 局部帧与全局帧。 始终向场景组件传递
frame - scenes.X.from。 - 在 scenes 对象上使用
as const。 这是让 TypeScript 将值视为字面量所必需的。 - 无需使用 remotion.config.ts。 CLI 默认设置即可正常工作。
- 在 package.json 中设置
type: "commonjs"。 此项为必需设置。ESM 会导致 Remotion 的打包器出错。 - SceneWrap 的背景颜色。 在 AbsoluteFill 上设置
backgroundColor: colors.bg。透明背景会在交叉淡化时露出前一个场景。 - 光标闪烁速率。 使用非对称阈值
[-1, -0.2, 0.2, 1] → [0, 0, 1, 1]的Math.sin(frame * 0.25)可实现逼真的 60% 可见率。
验证
[ ] npm install completes without errors
[ ] npx remotion studio opens and shows all 3 compositions
[ ] Desktop composition (1920x1080) renders without crashes
[ ] Mobile portrait composition (1080x1920) renders — text is readable
[ ] Mobile landscape composition (1334x750) renders
[ ] No interpolate() calls without extrapolation clamping
[ ] SceneWrap has the safeEnd/safeDur guard for fadeOut=0
[ ] Every scene component receives local frame (frame - scenes.X.from)
[ ] Crossfade overlays have zIndex: 100
[ ] Audio plays with volume changes across transitions
[ ] Full render completes: npx remotion render [Id] out/video.mp4 --timeout=60000