產品示範影片
將靜態產品截圖或設計稿轉化為精緻的動畫示範——無需螢幕錄影、無抖動的實際游標、無 UI 版本偏差。為每個畫面加上外框,讓合成游標滑動到精確像素,產生點擊波紋,然後縮放到相關部分並加上功能說明。因為輸入是靜態的且動畫由程式碼驅動,每個值都是確定性的,當截圖更改時,會以完全相同的方式重新渲染。
何時使用
- 應用程式 / SaaS 示範、功能發布預告、入門引導 (15–90 秒)。
- 展示在只擁有截圖/設計稿的 UI 中的點擊路徑。
- 突出顯示密集儀表板中的一個焦點區域(縮放至區域 + 標註)。
為什麼截圖勝過螢幕錄影
| 螢幕錄影 | 截圖驅動(此技能) |
|---|---|
| 實際游標會漂移、過衝、抖動 | 游標沿著緩和路徑移動到精確目標 |
| 要修正一個步驟就需重新錄製整個片段 | 更換一個 PNG,重新渲染相同的程式碼 |
| 錄製過程中 UI 變更,滑鼠會亂找 | 每個畫面都是一個乾淨的最終狀態素材 |
| 難以在沒有像素化的情況下縮放 | 以 2 倍(DPR 2)匯出截圖 => 清晰的縮放 |
以便顯示尺寸兩倍的大小(視網膜 / deviceScaleFactor: 2)擷取輸入,這樣 2 倍縮放也能保持清晰。請參閱 references/screenshot-demo.md 以取得 Playwright 擷取腳本。
示範循環
每個示範都以相同的節奏重複,每個功能一次。停留足夠長的時間以便閱讀,有目的地移動,完成點擊,展現結果。
| 節拍 | 時間預算 | 任務 |
|---|---|---|
| 停留在畫面上 | 0.5–1 秒 | 讓觀看者在任何動作開始前先熟悉畫面 |
| 游標移動到目標 | 0.4–0.8 秒 | 緩和移動 (ease-in-out),非線性 |
| 點擊波紋 + 狀態變化 | 0.2–0.3 秒 | 觸覺回饋;畫面在同一幀做出反應 |
| 縮放到焦點區域 | 1–2 秒進入,停留 2–4 秒 | 2 倍是最佳點——足夠的細節,保留上下文 |
| 為功能加上說明 | 與縮放一起停留 | 一個好處短語,例如「一鍵匯出」 |
移動鏡頭或游標,但避免同時移動兩者——兩個同時進行的動作會分散注意力。
為截圖加框
原始截圖看起來像錯誤報告;加框後看起來則像產品。將每個畫面放入瀏覽器或設備外殼中,並搭配品牌背景。
// 瀏覽器外框 — 放入截圖,變成一個可信的視窗
const BrowserFrame = ({ url, children }) => (
<div style={{ borderRadius: 12, overflow: "hidden", background: "#1e1e22",
boxShadow: "0 40px 80px rgba(0,0,0,.35)" }}>
<div style={{ height: 40, display: "flex", alignItems: "center", gap: 8, padding: "0 14px" }}>
{["#ff5f57", "#febc2e", "#28c840"].map((c) => (
<span key={c} style={{ width: 12, height: 12, borderRadius: "50%", background: c }} />
))}
<div style={{ marginLeft: 12, flex: 1, height: 24, borderRadius: 6, background: "#2b2b30",
color: "#9aa", fontSize: 13, display: "flex", alignItems: "center", padding: "0 10px" }}>
{url}
</div>
</div>
<div style={{ background: "#fff" }}>{children}</div>
</div>
);
在網址列放一個真實的 URL(增加真實性),加上柔和陰影和漸層背景。對於手機,改用帶有瀏海和圓角的電話外框。將外框樣式保持在一個主題物件中,這樣每個畫面都能匹配。
動畫游標 + 點擊波紋(核心動作)
根據目前幀來驅動位置,絕不使用 CSS 過渡或真實時鐘——影片渲染器需要每個幀都是幀編號的純函數,否則游標會不同步並閃爍。
import { useCurrentFrame, interpolate, spring, useVideoConfig } from "remotion";
// 從 `from` 到 `to` 在 startFrame 和 startFrame+dur 之間進行緩和移動
const useCursor = (from, to, startFrame, dur) => {
const frame = useCurrentFrame();
const t = interpolate(frame, [startFrame, startFrame + dur], [0, 1],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: (x) => x * x * (3 - 2 * x) }); // smoothstep
return { x: from.x + (to.x - from.x) * t, y: from.y + (to.y - from.y) * t };
};
export const Cursor = ({ from, to, startFrame, dur, clickAt }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
const { x, y } = useCursor(from, to, startFrame, dur);
// 波紋只展開一次,在點擊幀時
const since = frame - clickAt;
const showRipple = since >= 0 && since < 18;
const r = spring({ frame: since, fps, config: { damping: 18 }, durationInFrames: 18 });
return (
<>
{showRipple && (
<div style={{ position: "absolute", left: x, top: y, transform: "translate(-50%,-50%)",
width: 12 + r * 60, height: 12 + r * 60, borderRadius: "50%",
border: "2px solid rgba(80,140,255,.9)", opacity: 1 - r }} />
)}
<svg width="28" height="28" viewBox="0 0 28 28"
style={{ position: "absolute", left: x, top: y, filter: "drop-shadow(0 2px 3px rgba(0,0,0,.4))" }}>
<path d="M3 2 L3 21 L9 15 L13 24 L16 23 L12 14 L20 14 Z" fill="#fff" stroke="#222" strokeWidth="1.4" />
</svg>
</>
);
};
游標使用 smoothstep,因此它會從靜止加速,並在到達目標時減速(線性游標看起來很機械化)。在相同的 clickAt 幀觸發波紋和畫面的狀態變化,使原因和結果一致。請參閱 references/screenshot-demo.md 以了解在多個畫面上連接多個點擊的完整組合。
縮放到一個區域(UI 的 Ken Burns 效果)
要縮放到一個焦點元素,請縮放畫面並將 transform-origin 設為該元素的中心,這樣縮放會收斂在該元素上,而不是畫面中心。
const ZoomToRegion = ({ target, scale = 2, startFrame, dur, children }) => {
const frame = useCurrentFrame();
const s = interpolate(frame, [startFrame, startFrame + dur], [1, scale],
{ extrapolateLeft: "clamp", extrapolateRight: "clamp", easing: (x) => 1 - Math.pow(1 - x, 3) }); // easeOutCubic
return (
<div style={{ transform: `scale(${s})`, transformOrigin: `${target.x}px ${target.y}px`,
willChange: "transform" }}>
{children}
</div>
);
};
將縮放限制在大約 2 倍(超過 3 倍會失去上下文並造成迷失)。保持縮放狀態 2–4 秒——足夠長的時間來閱讀細節——然後在移動到下一個畫面之前,以緩和方式縮小。將縮放與標註配對,切勿單獨使用。
標註說明與功能說明
在關鍵點進行註解,然後讓它消失。標註是一個標籤加上一個連接器(箭頭、圓圈或底線),指向焦點元素。
- 使用柔和的光環或變暗的背景來突出顯示元素 (
box-shadow: 0 0 0 9999px rgba(0,0,0,.45)可以打出一個聚光燈孔)。 - 每個節拍說明一個好處——簡短的名詞短語(「即時分析」),而不是一個句子。在縮放時進入,在下一個步驟之前退出。
- 將說明保持在下方三分之一處,並在字幕安全區域內,這樣它們才能在裁切為 9:16 時保留下來。
請參閱 references/annotation-and-transitions.md 以了解聚光燈遮罩、箭頭連接器和一個帶時間軸的說明軌道。
畫面到畫面轉場
在步驟之間,使用一種一致的語言來移動畫面。選擇一種並保持:
| 轉場 | 感覺 | 用途 |
|---|---|---|
| 推入 / 滑動 | 「下一步」的向前動態 | 線性逐步解說 |
| 交叉縮放 | 有動力感,像應用程式 | 跳入詳細檢視 |
| 交叉淡出 | 平靜,中性 | 切換上下文(設定 → 儀表板) |
| 在共享元素上匹配剪輯 | 無縫 | 同一張卡片跨畫面持續存在 |
在當前畫面的點擊動畫解析之前,保持顯示它,然後再進行轉場——永遠不要在移動中途剪輯。請參閱 references/annotation-and-transitions.md。
輸出檢查清單
- 輸入以 2 倍(DPR 2)擷取;縮放在 2 倍時保持清晰。
- 每個游標/縮放值都是
useCurrentFrame()的純函數——動畫狀態不使用 CSS 過渡。 - 游標沿緩和路徑移動 (smoothstep);波紋和狀態變化在同一點擊幀觸發。
- 每個畫面都有外框(瀏覽器/設備),帶有真實 URL 和一致的主題。
- 一次只做一個動作(鏡頭或游標);縮放 ≤ 2 倍,停留 2–4 秒。
- 每個節拍有一個好處說明,在字幕安全的下方三分之一處;轉場使用一種一致的語言。
交付與驗證(渲染靜態幀 → MP4)
打包的輔助工具 (
scripts/):使用scripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png將您的靜態幀拼貼,然後使用scripts/probe-mp4.sh out.mp4 [WxH] [fps]驗證編碼。請參閱scripts/README.md。
這是一個重量級任務:交付物是一個 MP4,而不是一個即時頁面。示範會引入用戶的素材——截圖/設計稿、可選標誌——因此驗證主要是在檢查正確的圖片是否確實加載並出現在畫面中。
輸出約定:
- 一個 Remotion 專案,註冊了組合 (
<Composition>+ zodschema+defaultProps);每個游標/縮放/轉場值都是useCurrentFrame()的純函數(無 CSS 過渡、計時器、Date.now())。 - 透過
staticFile()載入截圖,並使用delayRender/continueRender進行閘控,以便在幀渲染之前,2 倍 PNG(以及任何網路字型)已存在——否則畫面會在示範中空白彈出。 - 交付物 = 渲染後的
out/*.mp4加上專案(當截圖更改時重新渲染)。
驗證循環 — 渲染靜態幀 → 檢查 → 編碼。 先檢查便宜的 PNG,只有在它們正確後才製作影片。
# 使用您將實際使用的屬性(真實截圖路徑)來產生影格精確的靜態幀,而非使用 defaultProps
npx remotion still ProductDemo out/f-settle.png --frame=15 --props=demo.json # 畫面已加框,移動之前
npx remotion still ProductDemo out/f-click.png --frame=90 --props=demo.json # 游標在目標上 + 波紋
npx remotion still ProductDemo out/f-zoom.png --frame=150 --props=demo.json # 縮放到焦點區域 + 說明
# 結束幀 = durationInFrames - 1(npx remotion compositions 會讀取它)
檢查每個 PNG 的保真度(正確的截圖已載入;游標在精確像素上;點擊波紋和狀態變化在同一幀;說明文字正確)和瑕疵(圖片空白/未載入、畫面超出畫布、縮放像素化或超出畫面、說明超出字幕安全的下方三分之一區域、長寬比錯誤或有黑邊)。
# 僅在靜態幀乾淨後:
npx remotion render ProductDemo out/demo.mp4 --props=demo.json
npx remotion render ProductDemo out/demo.gif --props=demo.json --codec=gif # README 首畫面證明
批次處理(一個範本,多個產品): 當為每個產品重新設計示範外觀時,在批次渲染整個產品目錄之前,先透過靜態幀驗證一個代表性產品的屬性——一次捕捉空白圖片或超出畫布的錯誤,而不是 N 次。
在您完成之前:
- 靜態幀在停留/點擊/結束時渲染乾淨——無錯誤,截圖實際載入(非空白)。
- 游標落在精確目標上;波紋 + 狀態變化在同一幀;說明文字正確並在字幕安全的下方三分之一處。
- 所有動畫都是幀驅動的——無 CSS 過渡 / 計時器 /
Date.now()/Math.random()。 - 已提供的屬性(真實截圖路徑)能正確渲染,而不僅僅是
defaultProps。 - 完整的 MP4 已編碼並可播放;(選擇性)為 README 渲染了 GIF。
參考文件
references/screenshot-demo.md— 一個完整可執行的 Remotion 示範:使用 Playwright 以 2 倍解析度擷取截圖、瀏覽器/手機外框元件、一個多步驟組合,可跨多個畫面移動游標並產生點擊波紋,以及一個渲染指令。references/annotation-and-transitions.md— 聚光燈遮罩、箭頭連接器、帶時間軸的說明軌道、推入/滑動與交叉縮放轉場,以及在共享元素上匹配剪輯的模式。