Remotion 視覺製作技能
基於製作 SureCart 4.2 啟動影片的真實實戰經驗建構。 作者:Chandresh Vaghanani
開始之前 — 2 個必問問題(不可妥協)
在撰寫任何程式碼之前,先問這 2 個問題。用一條訊息,兩個問題的方式提問,保持輕鬆。即使使用者說「直接開始」或「現在就做」,也不能跳過。這 10 秒鐘可以避免數小時的返工。
開始之前 — 兩個問題:
1. 深色還是淺色背景?(或提供您的網站/截圖,我會從中提取)
2. 您有產品截圖或 Mockup 嗎?(完全可選 — 沒有我也能製作)
就這樣。除非使用者主動提供更多資訊,否則不要再問其他問題。
如何處理回答:
- 如果他們提供了 Mockup/截圖 — 提取背景色、強調色、字體風格、UI 文案。直接使用。
- 如果他們提供了網站 URL — 抓取該網站,提取相同資訊。不要猜測。
- 如果他們只回答深色/淺色 — 直接使用下方的「無資訊時回退預設值」。
- 如果他們跳過兩個問題 — 直接使用下方的「無資訊時回退預設值」。不要再次詢問。
其他素材(Logo、音樂、額外顏色)— 若使用者提供則接受,但永遠不要因為這些素材而卡住進度。
無資訊時回退預設值
當沒有品牌資訊時,AI 的本能是縮小字體並增加內距。這個本能對影片來說是錯的。請應用以下設定:
當未提供 Mockup、截圖或網站時,這些設定會自動啟用。即使沒有品牌資訊,也能確保專業的結果。
佈局
- 每個場景的
AbsoluteFill都使用justifyContent: "center"+alignItems: "center"— 沒有例外 marginTop: -50將內容稍微拉至真正中心點的上方- Mockup/卡片寬度:1200px(使用上限 — 填滿畫面)
- 容器內距:最大 40px — 絕不超過
- 內容必須佔據 1080px 高度的至少 75%。如果沒有,請增加字型大小或減少間距。
字型大小(回退 — 使用範圍的上限)
| 元素 | 回退大小 |
|---|---|
| 主要標題 | 140px |
| 副標題 | 56px |
| 主體 / 描述文字 | 36px |
| 標籤 / 膠囊按鈕 | 22px |
| 卡片內容文字 | 28px |
顏色(回退調色盤 — 安全且專業)
- 背景:
#0a0a0f(接近黑色,中性) - 強調色:
#6366f1(靛藍色 — 可讀性高、現代、非產品特定) - 文字:
#ffffff - 淡化文字:
rgba(255,255,255,0.55) - 卡片背景:
rgba(255,255,255,0.06)
這些僅僅是起點。一旦使用者分享品牌顏色,就完全取代它們。
沒有品牌資訊時「不要」做的事
- 不要使用螢光/賽博龐克顏色 — 那是個人審美,不是品牌風格
- 不要使用
paddingTop: 120然後稱之為「置中」— 那是向上對齊,底部會有空白 - 不要因為標題
fontSize: 32「看起來很乾淨」就選用它 — 它在影片中是無法辨識的
規則 #1 — 畫布不是網站
這是 AI 生成的 Remotion 影片中最常見的錯誤。
Remotion 畫布是 1920×1080px。設計要填滿它 — 而不是像網頁一樣。
⚠️ 這些是最小值。將主體文字設為
fontSize: 18是一個 BUG,而不是風格選擇。 低於最小列的值意味著文字在 1080p 螢幕上無法閱讀。 將這些數字視為型別錯誤 — 在繼續之前必須修正。
| 元素 | 最小值(硬性下限) | 建議範圍 |
|---|---|---|
| 主要標題 | 80px | 100–160px |
| 副標題 | 40px | 48–72px |
| 主體 / 描述文字 | 28px | 32–40px |
| 標籤 / 膠囊按鈕 / 徽章 | 18px | 20–24px |
| 卡片內容文字 | 22px | 24–32px |
規則:
- 內容感覺必須填滿整個螢幕
- Mockup 卡片:
width: 1100–1200px,置中 - 容器內距:最大 48px — 不要像網頁那樣設為 80–120px
- 如果文字感覺「大到不舒服」— 那可能正好適合影片
規則 #2 — 所有動畫「必須」使用 useCurrentFrame()
// 正確
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 20], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
// 禁止 — 無法正確渲染
// CSS: transition: opacity 1s ease
// Tailwind: animate-fade-in
// CSS @keyframes
除非你明確需要無邊界值,否則每個 interpolate() 呼叫都必須包含 extrapolateLeft: "clamp" 和 extrapolateRight: "clamp"。忘記這點會導致值溢出範圍並產生微妙的錯誤。
規則 #3 — 確定性
// 禁止 — 每次渲染傳遞的值都不同
const x = Math.random() * 100;
// 正確 — 每次、每幀的值都相同
import { random } from "remotion";
const x = random("particle-x-1") * 100; // 字串種子 = 確定性
規則 #4 — 素材
import { staticFile } from "remotion";
import { Img } from "remotion"; // 不要使用原生 <img>
import { Audio } from "@remotion/media";
// 對於 public/ 資料夾中的任何素材,務必使用 staticFile()
<Audio src={staticFile("bg-music.mp3")} />
<Img src={staticFile("logo.png")} /> // <Img> 確保素材在影格渲染前載入
// 遠端 URL 不需要 staticFile(),但需要 CORS
規則 #5 — 流暢的預覽播放
在 <Sequence> 元件上新增 premountFor={30},以便重量級元件在它們的時間點前預先載入 30 幀:
<Sequence from={90} durationInFrames={120} premountFor={30}>
<HeavyScene />
</Sequence>
緩動函式食譜
import { Easing } from "remotion";
// 清晰的 UI 入場(強烈的 easing-out,無超調)— 大多數進入動畫
Easing.bezier(0.16, 1, 0.3, 1)
// 緩慢的編輯淡出(平衡的 ease-in-out)— 氛圍轉場
Easing.bezier(0.45, 0, 0.55, 1)
// 俏皮超調 — 彈跳/有趣元素
Easing.bezier(0.34, 1.56, 0.64, 1)
// Spring — 無彈跳(Mockup 入場、卡片、UI)
spring({ frame, fps, config: { damping: 200 } })
// Spring — 快速,輕微彈跳(有力元素)
spring({ frame, fps, config: { damping: 20, stiffness: 200 } })
// Spring — 彈跳/俏皮
spring({ frame, fps, config: { damping: 8 } })
預佈局閘道 — 在撰寫任何場景佈局「之前」執行
這些不是建議。在撰寫任何場景的第一個 <div> 之前,請執行所有三個閘道。如果任何一個閘道失敗,請更改佈局 — 永遠不要用固定尺寸或額外內容來修補。
閘道 1 — 畫布填充(兩個軸向,強制)
寬度軸:
dead_side = (1920 − content_width) / 2
必須 ≤ 300px。如果 > 300px → 內容太窄。加寬它或更改佈局。
高度軸:
fill_h = content_height / 1080
必須 ≥ 0.80。如果 < 0.80 → 內容太短。更改佈局形狀。
⚠️ 如果高度檢查失敗,不要透過對卡片或容器設定固定高度來修正。 固定高度會在卡片內部產生一個空洞 — 空白空間只是移到元素內部,而不是被消除。唯一的真正解決方案是更改佈局形狀(閘道 2)。
真實失敗範例 — 3 個短功能卡片:
| 版本 | content_width | dead_side | content_height | fill_h | 結果 |
|---|---|---|---|---|---|
| v1:3 欄卡片 (365px) | 1151px | 384px | 416px | 38% | ❌ 兩個軸向都失敗 |
v2:強制 height: 720px | 1542px | 189px | 864px | 80% | ✅ 寬度,❌ 視覺(卡片內空洞) |
| v3:水平列 (1400px) | 1400px | 260px | 916px | 85% | ✅ 兩個軸向都通過 |
閘道 2 — 佈局選擇決策表
內容量決定佈局形狀。在撰寫程式碼之前,從此表中選擇佈局。
| 項目數 | 每個項目的內容 | 正確佈局 | 原因 |
|---|---|---|---|
| 3–5 個項目 | 圖示 + 名稱 + 1 行 | 水平列 (1400px 寬) | 短內容垂直堆疊 → 自然填滿高度 |
| 3 個項目 | 圖示 + 名稱 + 2–3 行 | 3 欄卡片 (最小 1100px 寬) | 內容足夠填滿卡片高度而不產生空洞 |
| 2 個項目 | 內容豐富 | 並排大卡片 或分割畫面 | |
| 1 個項目 | 任何內容 | 全螢幕主視覺 |
如果你內容的自然佈局在閘道 1 後任何一個軸向低於門檻值 — 那個佈局就是錯的。請選擇此表中的不同行。
永遠不要根據美學或預設直覺來選擇佈局。內容適配優先。美學其次。
閘道 3 — 內容密度限制
每個項目上限:圖示 + 名稱 + 1 短行。硬性停止。 沒有項目符號。沒有子區塊。沒有段落。沒有第二行描述。
觀眾每個場景大約有 5 秒鐘。他們閱讀 1 行。他們不會閱讀 4 個項目符號。
如果內容感覺空洞,你想加入更多東西來填滿空間 — 那是閘道 2 在告訴你佈局形狀錯了,而不是內容缺失。
用「尺寸」(更大的字型、更大的圖示、項目間更大的間距)來填補空白空間 — 永遠不要用更多內容。
通用場景規則
-
垂直對齊 —
justifyContent: "center"+marginTop: -40到-60(略高於真正中心點 = 現代、高級感。不是用內距向上對齊。)❌ 錯誤 — 向上對齊,底部留下空白空間:
<AbsoluteFill style={{ display: "flex", flexDirection: "column", paddingTop: 110 }}> <h1>Headline</h1> <p>Subtext</p> {/* 底部大片空白 */} </AbsoluteFill>✅ 正確 — 垂直置中,略高於中點:
<AbsoluteFill style={{ display: "flex", flexDirection: "column", justifyContent: "center", alignItems: "center", marginTop: -50 }}> <h1>Headline</h1> <p>Subtext</p> {/* 內容填滿畫面 — 沒有空白空間 */} </AbsoluteFill> -
畫布填充 — 在撰寫此場景之前執行預佈局閘道。 閘道 1 同時檢查寬度 (
dead_side ≤ 300px) 和高度 (fill_h ≥ 0.80)。閘道 2 從決策表中選擇佈局形狀。閘道 3 限制了每個項目的內容。所有三個閘道都位於上方的「預佈局閘道」部分 — 它們取代了此處舊的僅檢查寬度的規則。 -
標題 z-index — 始終在標題容器上設定
zIndex: 20,這樣 Mockup 就不會覆蓋到文字 -
標題溢出 — 始終在標題文字上設定
whiteSpace: "nowrap"(防止文字在 Mockup 後方換行) -
不要在 AbsoluteFill 上設定
overflow: hidden— 這會裁切游標和 SVG 元素。將其移除或將游標放在外部。 -
15 幀停留 — 每個場景在轉場觸發前,必須在結尾處有至少 15 幀完全可見的停留。永遠不要在離開場景的動畫仍在播放時開始轉場。
-
字型 — 全程使用一種統一字型。建議:透過
@remotion/google-fonts使用 Plus Jakarta Sans。最大可用字重:800(設定fontWeight: 900會渲染為 800)。 -
顏色 — 最多 2–3 種品牌顏色。一種深色背景,一種主要強調色,文字使用白色/淡化白色。所有場景保持一致。
字體層級
// 超級標題 / 標籤膠囊
{ fontSize: 20, letterSpacing: "4px", textTransform: "uppercase", fontWeight: 600 }
// 主要標題
{ fontSize: 112, fontWeight: 800 } // 範圍:100–160px
// 副文本 / 描述
{ fontSize: 36, opacity: 0.7 } // 範圍:32–40px
// 信任行 / 小徽章
{ fontSize: 26, opacity: 0.5 } // 範圍:24–28px
字型設定
import { loadFont } from "@remotion/google-fonts/PlusJakartaSans";
// 在頂層呼叫 — 必須在渲染前載入
const { fontFamily } = loadFont("normal", {
weights: ["400", "600", "800"],
subsets: ["latin"],
});
對於其他字型:透過 @remotion/google-fonts/FontName 安裝,或將 .woff2 放入 public/ 並使用 @remotion/fonts 的 loadFont。
場景結構模板
每個場景都遵循這個固定的圖層順序(從底層到頂層):
<AbsoluteFill style={{ background: brandBg }}