產品展示影片
將靜態產品截圖或設計圖轉變為精緻、動畫化的展示影片 — 無需螢幕錄製工具,不會有抖動的真實游標,也沒有 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 倍是最佳點 — 足夠的細節,保留上下文 |
| 為功能加上說明文字 | 在縮放期間停留 | 一個好處短語,例如「一鍵匯出」 |
一次只移動攝影機或游標,很少同時移動兩者 — 同時移動會分散注意力。
為截圖加上框架
原始截圖看起來像錯誤報告;加了框架的截圖則像產品。將每個畫面放在瀏覽器或裝置的 Chrome 風格框架中,並搭配品牌背景。
// 瀏覽器框架 — 放入截圖,得到一個可信的視窗
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 過渡或 wall clock — 影片渲染器需要每一幀都是影格編號的純函數,否則游標會不同步並閃爍。
import { useCurrentFrame, interpolate, spring, useVideoConfig } from "remotion";
// 在 startFrame 和 startFrame+dur 之間,從 `from` 緩和移動到 `to`
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)的安全區域備註。