Remotion 概覽
用 React 寫影片的框架,理解 Composition、Frame、interpolate 核心概念
Overview##
Remotion 是一個用 React 寫影片的框架。它把影片的每一幀視為一次 React render,讓你用元件、props、CSS 這些熟悉的工具來製作影片。
傳統影片製作與 Remotion 的差異:
| 面向 | 剪輯軟體 | Remotion |
|---|---|---|
| 介面 | 時間軸 GUI | React 程式碼 |
| 版本控制 | 專案檔難以 diff | Git 追蹤每一行變更 |
| 參數化 | 手動逐一修改 | Props 驅動,批次渲染 |
| AI 協作 | 無法自動化 | LLM 可直接生成程式碼 |
| 協作 | 匯出/匯入專案檔 | Pull Request + Code Review |
Note
Remotion 不是要取代 Premiere 或 After Effects。它更適合資料驅動、可重複、需要版本控制的影片場景,例如:產品 demo、社群短影片、個人化行銷影片。
Core Concept##
影片 = 純函數###
Remotion 最核心的設計哲學:
UI = f(frame)
每一幀都是一次獨立的 React render,元件的輸出完全由 frame number 決定。一支 30fps、10 秒的影片 = 300 次 render,每次都是純函數。
這帶來三個關鍵優勢:
- 確定性 — 給定同一個 frame number,永遠產生相同結果
- 可跳轉 — 直接預覽第 150 幀,不需要從頭播放
- 可並行 — 300 幀分給多個 CPU 同時渲染
import { useCurrentFrame, AbsoluteFill } from 'remotion';
export const MyVideo = () => {
const frame = useCurrentFrame(); // 0, 1, 2, ..., 299
return (
<AbsoluteFill style={{ justifyContent: 'center', alignItems: 'center' }}>
<h1>目前幀數:{frame}</h1>
</AbsoluteFill>
);
};
Warning
因為每幀必須是確定性的,Remotion 禁止使用 CSS animation、setTimeout、setInterval、requestAnimationFrame。這些都依賴真實時間,會破壞幀的獨立性。
Composition###
Composition 是影片的最小單位——一個 React 元件加上影片 metadata:
import { Composition } from 'remotion';
import { MyVideo } from './MyVideo';
export const RemotionRoot = () => {
return (
<Composition
id="MyVideo"
component={MyVideo}
durationInFrames={300} // 總幀數
fps={30} // 每秒幀數
width={1920} // 寬度(px)
height={1080} // 高度(px)
/>
);
};
| 屬性 | 說明 |
|---|---|
id | 唯一識別碼,渲染時指定用 |
component | 影片的 React 元件 |
durationInFrames | 總幀數(duration = frames / fps) |
fps | 每秒幀數 |
width / height | 影片尺寸(像素) |
一個專案可以有多個 Composition,全部在 src/Root.tsx 中註冊:
export const RemotionRoot = () => {
return (
<>
<Composition id="Intro" component={Intro} ... />
<Composition id="Outro" component={Outro} ... />
</>
);
};
Tip
useVideoConfig() 可以在元件內取得 Composition 的 metadata(fps、durationInFrames、width、height),避免硬編碼。
Animation##
interpolate###
interpolate 是一個數學映射函數——把一個數值範圍映射到另一個:
import { useCurrentFrame, interpolate } from 'remotion';
const frame = useCurrentFrame();
// frame 0~30 → opacity 0~1(線性)
const opacity = interpolate(frame, [0, 30], [0, 1]);
// frame 0~60 → x 位移 -100~0
const translateX = interpolate(frame, [0, 60], [-100, 0]);
interpolate 預設允許外推(extrapolation),超出範圍的值會繼續延伸。用 extrapolateRight: 'clamp' 限制在輸出範圍內:
const opacity = interpolate(frame, [0, 30], [0, 1], {
extrapolateRight: 'clamp', // frame > 30 時,opacity 維持 1
});
| 選項 | 說明 |
|---|---|
extrapolateLeft | 輸入低於範圍時的行為 |
extrapolateRight | 輸入超出範圍時的行為 |
'extend' | 繼續延伸(預設) |
'clamp' | 固定在邊界值 |
spring###
spring 模擬物理彈簧運動,產生自然的緩動效果:
import { useCurrentFrame, useVideoConfig, spring } from 'remotion';
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// 從 0 彈到 1,帶有自然的減速效果
const scale = spring({
frame,
fps,
config: {
damping: 200, // 阻尼,越大越不彈跳
},
});
spring 和 interpolate 可以組合使用:
// spring 產生 0→1 的彈簧曲線
const progress = spring({ frame, fps, config: { damping: 15 } });
// 用 interpolate 映射到實際的位移值
const translateY = interpolate(progress, [0, 1], [50, 0]);
const rotation = interpolate(progress, [0, 1], [0, 360]);
Tip
interpolate 是線性映射,spring 是物理模擬。兩者都是純函數——輸入 frame,輸出數值。它們不是動畫引擎,不控制時間軸。
GSAP vs Remotion###
如果你熟悉 GSAP,理解這個差異很重要:
| GSAP | Remotion | |
|---|---|---|
| 時間驅動 | 真實時間(ms) | 幀數(frame) |
| 狀態 | 內部 timeline,可變 | 無狀態,純計算 |
| 確定性 | 依賴 requestAnimationFrame | 給定 frame 永遠相同結果 |
| 適用場景 | 網頁互動動畫 | 影片輸出(MP4) |
// GSAP(命令式):「請在 1 秒內把它變不透明」
gsap.to(el, { opacity: 1, duration: 1 });
// Remotion(宣告式):「在第 N 幀時,透明度是多少?」
const opacity = interpolate(frame, [0, 30], [0, 1]);
Structure##
Sequence###
<Sequence> 控制子元件在哪個時間區段出現:
import { Sequence } from 'remotion';
export const MyVideo = () => {
return (
<>
<Sequence from={0} durationInFrames={60}>
<Title />
</Sequence>
<Sequence from={60} durationInFrames={60}>
<Content />
</Sequence>
<Sequence from={120} durationInFrames={30}>
<Outro />
</Sequence>
</>
);
};
關鍵特性:<Sequence> 內部的 useCurrentFrame() 會重置為 0。子元件不需要知道自己在全域時間軸的位置。
Series###
<Series> 是 <Sequence> 的語法糖——自動接續,不需要手算 from:
import { Series } from 'remotion';
export const MyVideo = () => {
return (
<Series>
<Series.Sequence durationInFrames={60}>
<Title />
</Series.Sequence>
<Series.Sequence durationInFrames={60}>
<Content />
</Series.Sequence>
<Series.Sequence durationInFrames={30}>
<Outro />
</Series.Sequence>
</Series>
);
};
改任何一段的 durationInFrames,後面的段落自動調整起始時間。
Tip
簡單的順序播放用 <Series>。需要重疊、交叉淡入等複雜排列時用 <Sequence>。
Rendering##
Remotion 的渲染流程:
graph LR
A[React 元件] --> B[逐幀截圖]
B --> C[PNG 序列]
C --> D[FFmpeg 編碼]
D --> E[MP4 / WebM]
三種渲染方式:
| 方式 | 說明 | 適用場景 |
|---|---|---|
| Remotion Studio | 瀏覽器預覽 + GUI 渲染 | 開發階段 |
| CLI | npx remotion render | 本地批次渲染 |
| Lambda | AWS Lambda 無伺服器渲染 | 大規模、平行化 |
# 預覽
npx remotion studio
# 渲染成 MP4
npx remotion render src/index.ts MyVideo out/video.mp4
# 指定 Composition ID
npx remotion render src/index.ts Intro out/intro.mp4
Note
渲染需要安裝 Chromium(Remotion 會自動下載)和 FFmpeg。npx remotion install 可以手動安裝必要的依賴。
Quiz##
Summary##
- Remotion 把影片視為純函數
UI = f(frame),每幀獨立、確定性、可並行 - Composition 定義影片的元件與 metadata(尺寸、fps、時長)
interpolate做線性數值映射,spring做物理彈簧模擬,兩者都是純函數- 禁止 CSS animation 和
setTimeout——動畫必須由 frame number 驅動 <Sequence>控制時間區段,內部 frame 自動重置;<Series>自動接續- 渲染流程:React render → 逐幀截圖 → FFmpeg 編碼為 MP4
留言 (0)
登入後即可留言