mcpField
R
remotion-video

remotion-video

github.com/tushaarmehtaa创意与媒体1242 次安装2 周前更新
代码仓库

关于 remotion-video

remotion-video 是一项根据视频简报搭建 Remotion 项目的技能,涵盖多种画幅构图、动画场景、音频编排和可复用视觉组件,生成的项目可用 Remotion Studio 打开。

主要功能

  1. 01三种画幅构图
  2. 02基于 spring 的场景动画
  3. 03场景定时与交叉淡化
  4. 04按场景时间控制音量
  5. 05可复用场景与视觉组件
  6. 06适配移动画幅的尺寸

适用场景

  1. 01搭建产品演示视频项目
  2. 02制作桌面和移动端视频格式
  3. 03按时间编排视频场景
  4. 04添加动态文字和终端效果

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tushaarmehtaa/tushar-skills --skill remotion-video

安装后在 Claude Code 中输入/remotion-video确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
audio.md
cheatsheet.md
primitives.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 复制:

  1. SceneWrap — 每个场景都必须使用。负责处理淡入/淡出,并防止 inputRange 非单调。
  2. SlamText — 逐词弹簧入场动画。用于标题。
  3. CrossfadeTransition — 场景之间的透明度峰值。必须设置 zIndex: 100。
  4. TypingEffect — 终端/输入模拟,带闪烁光标。
  5. GrainOverlay — SVG 噪声纹理(仅琥珀色风格)。opacity: 0.035,zIndex: 50。
  6. StageLight + AmbientGlow — 漂移的径向渐变(仅琥珀色风格)。
场景手册

根据用户的需求,从此菜单中选择场景:

场景类型时长用途
Hook2-4.5sSlamText 标题 + 弹性副标题。吸引注意力。
痛点/问题4-5s终端打字,展示旧方法。「New session」闪现后重置。
快速/解决方案2-3s输入一条命令,显示结果,并以发光脉冲效果呈现「done.」。
加载/处理中1.5-2s表情符号 + 抖动 + 进度条。营造期待感。
结果/卡片4-6.5s项目从不同方向飞入。展示输出质量。
功能网格2-3s2x3 或 3x2 网格,依次以弹簧效果进入。
反馈/聊天3-4s聊天气泡:用户提问(向右滑入),AI 回复(向左滑入)。
滚动/轮播5-6.5s项目通过进入/退出转场效果轮流出现在中心。
安装3s标题 + 安装命令的打字动画 +「done.」。
CTA3sSlamText + 脉冲按钮 + 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 阶段:注意事项

忽略以下事项会导致视频出现难以察觉的问题:

  1. 始终限制外推。 每次调用 interpolate() 都需要 { extrapolateLeft: "clamp", extrapolateRight: "clamp" }。否则,数值会超出 0/1。
  2. 非单调 inputRange 导致崩溃。 如果 SceneWrap 中的 fadeOut=0,inputRange 会出现重复值。基础组件中的 safeEnd = Math.max(duration - fadeOut, fadeIn + 1) 守卫可修复此问题。
  3. 渲染时字体加载超时。 字体加载的 delayRender() 可能在帧数 >700 时超时。请使用 --timeout=60000。
  4. 交叉淡化时的 zIndex。 交叉淡化覆盖层必须设置 zIndex: 100,才能位于场景内容上方。
  5. 局部帧与全局帧。 始终向场景组件传递 frame - scenes.X.from。
  6. 在 scenes 对象上使用 as const。 这是让 TypeScript 将值视为字面量所必需的。
  7. 无需使用 remotion.config.ts。 CLI 默认设置即可正常工作。
  8. 在 package.json 中设置 type: "commonjs"。 此项为必需设置。ESM 会导致 Remotion 的打包器出错。
  9. SceneWrap 的背景颜色。 在 AbsoluteFill 上设置 backgroundColor: colors.bg。透明背景会在交叉淡化时露出前一个场景。
  10. 光标闪烁速率。 使用非对称阈值 [-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

评论

支持 Markdown