產品展示影片
將靜態的產品截圖或設計稿,轉換為精美的動畫展示 — 無需螢幕錄製器、無抖動的真實游標、無 UI 版本偏差。為每個畫面加上邊框,讓合成的游標精確滑動到特定像素,產生點擊波紋,然後縮放到重點區域並加上功能說明。由於輸入是靜態的且動作由程式碼驅動,每個數值都具有確定性,當截圖更改時,可以重新渲染出完全一致的內容。
使用時機
- 應用程式 / SaaS 展示、功能發布預告、入門導覽(15–90 秒)。
- 展示僅有截圖/設計的 UI 之點擊路徑。
- 強調複雜儀表板中的一個焦點區域(縮放至區域 + 標註說明)。
為何截圖優於螢幕錄製
| 螢幕錄製 | 截圖驅動(此技能) |
|---|---|
| 真實游標會偏移、過衝、抖動 | 游標沿著緩動路徑移動到精確目標 |
| 修正一個步驟需重新錄製整個片段 | 更換一個 PNG,重新渲染同一段程式碼 |
| 錄製過程中 UI 改變,滑鼠位置偏離 | 每個畫面都是乾淨的最終狀態素材 |
| 難以進行縮放而不產生像素化 | 以 2 倍(DPR 2)匯出截圖 → 清晰的縮放 |
以顯示尺寸的兩倍(Retina / 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,而不是一個即時頁面。展示匯入了使用者的素材 — 截圖/設計、可選的 Logo — 因此驗證主要確認正確的圖片是否實際載入並位於畫面中。
輸出合約:
- 一個 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 已編碼並可播放;(可選)GIF 已為 README 渲染完成。
參考檔案
references/screenshot-demo.md— 一個完整可執行的 Remotion 展示:使用 Playwright 以 2 倍擷取截圖、瀏覽器/手機邊框元件、一個跨多個畫面移動游標並帶有點擊波紋的多步驟組合,以及渲染指令。references/annotation-and-transitions.md— 聚光燈遮罩、箭頭/圓圈標註連接器、一個打字效果的功能字幕軌道,以及四種畫面間轉場,附帶影格驅動的實作與多長寬比(16:9 / 9:16)安全區域說明。