Remotion 影片創作者
使用 Remotion (React 元件) 製作可程式化的影片。此技能封裝了 Skill Stack 的視覺風格以及從建立解說內容中學到的經驗。
目的
建立 10-60 秒的短影音內容,以獨特的 Risograph 風格美學來解釋 Skill Stack 的概念。影片即程式碼,因此它們是版本控制、可重現且可無限編輯的。
何時使用此技能
- 建立 Skill Stack 概念的解說影片
- 製作動態社交媒體內容 (直式 9:16、方形 1:1、橫式 16:9)
- 視覺化技術工作流程或漸進式揭示
- 任何需要精確時間與排版的影片
不適用於:
- 現場影像編輯 (請使用傳統影片工具)
- 複雜的 3D 圖形 (Remotion 專注於 2D)
- 快速的單次圖形製作 (請使用 Figma 或 Canva)
專案設定
快速開始
# 建立新的 Remotion 專案
npx create-video@latest my-video
# 安裝依賴
cd my-video && npm install
# 加入 Google Fonts
npm install @remotion/google-fonts
# 啟動 studio
npm run start # 開啟 http://localhost:3000
檔案結構
my-video/
├── src/
│ ├── Root.tsx # Composition 定義
│ ├── Main.tsx # 主要影片元件
│ └── components/ # 可重複使用的元素
├── package.json
├── remotion.config.ts
└── out/ # 渲染後的影片
Composition 設定 (Root.tsx)
務必為每支影片建立多種長寬比:
import { Composition, Folder } from "remotion";
import { MyVideo } from "./MyVideo";
export const RemotionRoot = () => (
<>
<Folder name="MyVideo">
<Composition
id="MyVideo-Vertical"
component={MyVideo}
durationInFrames={600} // 20 秒,30fps
fps={30}
width={1080}
height={1920} // 9:16
/>
<Composition
id="MyVideo-Square"
component={MyVideo}
durationInFrames={600}
fps={30}
width={1080}
height={1080} // 1:1
/>
<Composition
id="MyVideo-Landscape"
component={MyVideo}
durationInFrames={600}
fps={30}
width={1920}
height={1080} // 16:9
/>
</Folder>
</>
);
視覺風格:Skill Stack Risograph
色盤
const C = {
paper: "#FAF8F5", // 暖灰白背景
coral: "#D4694A", // 強調色、行動呼籲、亮點
teal: "#1E4D4D", // 標題、選取狀態
ink: "#1C1C1C", // 內文
muted: "#666666", // 次要文字
dimmed: "#AAAAAA", // 第三層、停用
white: "#FFFFFF", // 卡片、容器
};
字體
import { loadFont as loadInter } from "@remotion/google-fonts/Inter";
import { loadFont as loadPlayfair } from "@remotion/google-fonts/PlayfairDisplay";
import { loadFont as loadJetBrains } from "@remotion/google-fonts/JetBrainsMono";
// 內文、UI 標籤
const { fontFamily: inter } = loadInter("normal", {
weights: ["400", "500", "600"],
subsets: ["latin"],
});
// 標題、引文、情感化文字
const { fontFamily: playfair } = loadPlayfair("normal", {
weights: ["400", "500", "600", "700"],
subsets: ["latin"],
});
// 程式碼、技術內容、技能名稱
const { fontFamily: mono } = loadJetBrains("normal", {
weights: ["400", "500"],
subsets: ["latin"],
});
字型大小指南
影片中可讀的最小尺寸:
| 元素 | 方形 (1080) | 直式 (1080w) | 橫式 (1920w) |
|---|---|---|---|
| 標題 | 64-84px | 64-84px | 72-96px |
| 技能名稱 | 36-40px | 36-40px | 40-48px |
| 內文 | 28-32px | 28-32px | 32-36px |
| 標籤 | 24-28px | 24-28px | 28-32px |
| 註解 | 22-24px | 22-24px | 24-28px |
關鍵經驗: 永遠比你認為的還大。影片會壓縮細節。
顆粒紋理疊加
const GrainOverlay: React.FC = () => {
const frame = useCurrentFrame();
return (
<AbsoluteFill
style={{
pointerEvents: "none",
opacity: 0.04,
mixBlendMode: "multiply",
}}
>
<svg width="100%" height="100%">
<defs>
<filter id="grain">
<feTurbulence
type="fractalNoise"
baseFrequency="0.8"
numOctaves="4"
seed={Math.floor(frame / 4)} // 顆粒動畫
/>
</filter>
</defs>
<rect width="100%" height="100%" filter="url(#grain)" />
</svg>
</AbsoluteFill>
);
};
動畫模式
核心工具
import {
useCurrentFrame,
useVideoConfig,
AbsoluteFill,
interpolate,
spring,
Sequence,
} from "remotion";
淡入/淡出
const fadeIn = interpolate(frame, [0, 30], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
const fadeOut = interpolate(frame, [150, 180], [1, 0], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// 結合以產生場景透明度
<div style={{ opacity: fadeIn * fadeOut }}>
彈簧動畫
const { fps } = useVideoConfig();
// 平滑進場
const entrance = spring({
frame: frame - 20, // 延遲 20 幀
fps,
config: { damping: 100 }, // 平滑,無彈跳
});
// 彈性選取
const selectPulse = spring({
frame: frame - 15,
fps,
config: { damping: 12, stiffness: 100 }, // 有彈性
});
// 套用至 transform
<div style={{
opacity: interpolate(entrance, [0, 1], [0, 1]),
transform: `translateY(${interpolate(entrance, [0, 1], [20, 0])}px)`,
}}>
打字機效果
const ScenePrompt: React.FC<{ frame: number }> = ({ frame }) => {
const text = "您的提示文字在此";
const charsToShow = Math.floor(frame / 2); // 30fps 下每秒 15 字元
const visibleText = text.slice(0, charsToShow);
const isTyping = charsToShow < text.length;
const cursorBlink = Math.floor(frame / 18) % 2 === 0;
return (
<div>
"{visibleText}
{(isTyping || cursorBlink) && (
<span style={{
backgroundColor: C.coral,
marginLeft: 4,
opacity: cursorBlink ? 1 : 0,
}}>
{"\u00A0"}
</span>
)}
{!isTyping && '"'}
</div>
);
};
列表逐步顯示動畫
const ITEMS = ["item-1", "item-2", "item-3"];
{ITEMS.map((item, i) => {
const delay = i * 25; // 每個項目間隔 25 幀
const s = spring({
frame: Math.max(0, frame - delay - 20),
fps,
config: { damping: 100 },
});
return (
<div
key={item}
style={{
opacity: interpolate(s, [0, 1], [0, 1]),
transform: `translateY(${interpolate(s, [0, 1], [20, 0])}px)`,
}}
>
{item}
</div>
);
})}
場景時間指南
時間計算
- 30 fps = 每秒 30 幀
- 10 秒 = 300 幀
- 20 秒 = 600 幀
節奏經驗談
太快是頭號錯誤。 觀眾需要時間來:
- 注意到場景變化
- 閱讀文字
- 理解含義
- 為下個變化做準備
最短場景持續時間:
| 場景類型 | 最短 | 舒適 |
|---|---|---|
| 打字機文字 | 3-4 秒 | 5-6 秒 |
| 列表出現 | 4-5 秒 | 6-8 秒 |
| 選取/強調 | 3-4 秒 | 5 秒 |
| 技術圖表 | 4-5 秒 | 6-8 秒 |
| 重點/行動呼籲 | 2-3 秒 | 3-4 秒 |
場景重疊模式
場景之間應交叉淡出,而非硬切:
// 20 秒影片 (600 幀) 的場景時間
{frame < 200 && <ScenePrompt frame={frame} />}
{frame >= 160 && frame < 340 && <SceneScan frame={frame - 160} />}
{frame >= 300 && frame < 460 && <SceneSelect frame={frame - 300} />}
{frame >= 420 && frame < 560 && <SceneLoad frame={frame - 420} />}
{frame >= 520 && <ScenePunchline frame={frame - 520} />}
40 幀的重疊 (1.3 秒) 在結合淡入/淡出 interpolate 時,可創造流暢的交叉淡出效果。
工作流程
階段 1:分鏡
在撰寫程式碼前,先定義:
- 核心訊息 - 觀眾應該學到的一件事是什麼?
- 場景分解 - 4-6 個場景,每個場景一個想法
- 總時長 - 社群媒體 10-20 秒,解說影片 30-60 秒
- 文字內容 - 每個場景的確切字詞
階段 2:骨架
- 建立帶有適當時間長度的 Composition
- 用佔位內容建立場景元件
- 設定基本時間 (場景範圍)
- 測試所有場景都能正常顯示
階段 3:樣式
- 套用色盤和字型
- 加入顆粒紋理疊加
- 確保字型大小可讀
- 在手機 (直式) 和桌上電腦 (橫式) 上測試
階段 4:動畫
- 為每個場景加入淡入/淡出
- 為進場加入彈簧動畫
- 微調時間 - 幾乎總是需要放慢
- 多次測試完整播放
階段 5:渲染
# 渲染特定 Composition
npx remotion render MyVideo-Square out/square.mp4
# 渲染所有格式
npx remotion render MyVideo-Vertical out/vertical.mp4
npx remotion render MyVideo-Square out/square.mp4
npx remotion render MyVideo-Landscape out/landscape.mp4
常見錯誤
❌ 置中問題
問題: 內容出現在左上角。
修正: 使用 AbsoluteFill 搭配 flexbox,而非 position: absolute。
// ✅ 正確
<AbsoluteFill style={{
justifyContent: "center",
alignItems: "center",
}}>
// ❌ 錯誤
<div style={{ position: "absolute", left: "50%", top: "50%" }}>
❌ 字型太小
問題: 在 studio 中可讀,在手機上難以辨識。
修正: 內文至少 28px,標題至少 64px。
❌ 太快
問題: 文字在消失前來不及閱讀。
修正: 將初始時間估計加倍。每個場景至少需要 4-8 秒。
❌ 硬切
問題: 場景間的轉換突兀。
修正: 使用淡入/淡出讓場景重疊 30-50 幀。
❌ 無長寬比支援
問題: 影片在不同平台上看起來不對。
修正: 一開始就建立所有三種 Composition (直式、方形、橫式)。
字幕整合
Remotion 支援原生字幕。依成本分為三種選項:
選項 1:原生 Whisper (推薦 - 免費)
npm install @remotion/captions @remotion/install-whisper-cpp
npx @remotion/install-whisper-cpp --model large-v3-turbo
import { transcribe } from "@remotion/captions";
const result = await transcribe({
inputPath: "/path/to/audio.mp3",
model: "large-v3-turbo",
language: "en",
});
// result.captions = [{ text: "Hello", startTime: 0, endTime: 0.5 }, ...]
選項 2:ZapCap API ($0.10/分鐘)
適用於批次處理,無需本機模型設定。
選項 3:Submagic API ($0.69/分鐘)
提供預設樣式的「病毒式」字幕模板,但較昂貴。
完整工作流程詳情: 請見 references/caption-workflow.md
社群資源
Discord
Remotion Discord - 超過 6,000 名成員。活躍的 #help 和 #showcase 頻道。創作者 (Jonny Burger) 會親自回覆。
值得學習的關鍵模板
| 模板 | 用途 | 連結 |
|---|---|---|
| TikTok | 直式社群影片 | remotion-dev/template-tiktok |
| Audiogram | Podcast 片段 | remotion-dev/template-audiogram |
| GitHub Unwrapped | 數據驅動影片 | remotion-dev/github-unwrapped |
| claude-remotion-kickstart | AI 輔助工作流程 | 社群專用的 Claude + Remotion 起手式 |
必要套件
# 字幕
npm install @remotion/captions @remotion/install-whisper-cpp
# 圖形
npm install @remotion/skia # 2D 向量圖形
npm install @remotion/three # 3D 使用 Three.js
npm install @remotion/lottie # Lottie 動畫
# 渲染
npm install @remotion/lambda # AWS 無伺服器渲染
npm install @remotion/player # 嵌入網頁應用
完整資源列表: 請見 references/community-resources.md
捆綁資源
references/what-is-a-skill.tsx- 來自「什麼是技能」影片的完整範例元件references/caption-workflow.md- 完整的字幕整合指南 (Whisper、ZapCap、Submagic)references/community-resources.md- 模板、套件、學習路徑
相關技能
- video-caption-creation - 為渲染後的影片加入字幕和主題標籤
- youtube-scriptwriting - 用於較長的解說影片腳本
- social-content-creation - 將影片概念重複用於靜態貼文
版本歷史
-
v1.1 (2026-01-22):字幕與社群整合
- 透過
@remotion/captions加入原生 Whisper 字幕工作流程 - 加入字幕樣式預設 (簡約、粗體、卡拉 OK、品牌)
- 加入社群資源 (Discord、模板、套件)
- 新的參考檔案:
caption-workflow.md、community-resources.md - 成本比較:Whisper (免費) vs ZapCap ($0.10/分鐘) vs Submagic ($0.69/分鐘)
- 透過
-
v1.0 (2026-01-21):初始技能建立
- Risograph 視覺風格
- 動畫模式 (spring、interpolate、打字機)
- 時間指南 (從「太快」的迭代中學到)
- 場景重疊模式
影片即程式碼。進行版本控制、反覆迭代,並建立一個可重複使用的元件庫。