Communitygithub.com

產品展示影片技能

當使用者要求「製作產品展示影片」、「建立應用程式展示影片」、「製作功能發布影片」、「進行 SaaS 展示」、「製作使用者介面導覽影片」、「將產品截圖動畫化為展示」、「為截圖加入動態游標/點擊效果」或「放大使用者介面特定區域」時,應使用此技能。涵蓋將靜態截圖/設計(非螢幕錄製)轉換為精美的動畫展示:設備/瀏覽器框架、動畫游標 + 點擊波紋、縮放/平移至焦點 UI、標註說明、步驟節奏、畫面間轉場以及功能字幕。

產品展示影片技能 是什麼?

此技能旨在將靜態產品截圖或設計稿,轉換為精美且具確定性的動畫展示影片。它特別適用於建立應用程式或 SaaS 的產品示範、功能發布預告、入門導覽影片(長度約 15-90 秒),或是需要透過截圖展示特定點擊路徑、突顯密集儀表板中某個焦點區域的場景。此方法優於傳統螢幕錄製,因為動畫游標會沿著緩動路徑精確移動至目標像素,點擊波紋與畫面狀態變化同步觸發,且可針對任意畫面進行縮放(最高 2 倍,保持清晰)。由於所有動畫參數皆為影格數字的純函數,每個值都具有確定性,當截圖更換時,可重新渲染產生完全一致的影片。此技能與 Remotion 框架深度整合,支援在瀏覽器或裝置框架內嵌入截圖,並提供多種畫面間轉場效果(推入/滑動、交叉縮放、交叉淡變、匹配剪輯)。此外,它也包含完善的輸出驗證流程:透過渲染靜態影格檢查游標位置、點擊效果、縮放區域與字幕正確性,確認無誤後再進行最終的 MP4 或 GIF 編碼輸出。

相容平台~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/iart-ai/ecommerce-video-skills/tree/HEAD/skills/product-demo-video

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

產品展示影片

將靜態的產品截圖或設計稿,轉換為精美的動畫展示 — 無需螢幕錄製器、無抖動的真實游標、無 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> + zod schema + 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 次。

在您完成之前:

  1. 靜態影格在「靜止/點擊/結束」影格渲染清晰 — 無錯誤,截圖確實已載入(非空白)。
  2. 游標落在精確目標上;波紋 + 狀態變化在同一影格;字幕文字正確且在標題安全的下三分之一區域。
  3. 所有動作皆由影格驅動 — 無 CSS 過渡 / 計時器 / Date.now() / Math.random()。
  4. 已出貨的屬性(真實截圖路徑)能正確渲染,而不僅是 defaultProps。
  5. 完整的 MP4 已編碼並可播放;(可選)GIF 已為 README 渲染完成。

參考檔案

  • references/screenshot-demo.md — 一個完整可執行的 Remotion 展示:使用 Playwright 以 2 倍擷取截圖、瀏覽器/手機邊框元件、一個跨多個畫面移動游標並帶有點擊波紋的多步驟組合,以及渲染指令。
  • references/annotation-and-transitions.md — 聚光燈遮罩、箭頭/圓圈標註連接器、一個打字效果的功能字幕軌道,以及四種畫面間轉場,附帶影格驅動的實作與多長寬比(16:9 / 9:16)安全區域說明。

相關技能