Community程式設計與開發github.com

iart-ai/ecommerce-video-skills

從您的螢幕截圖、價格和圖片資料夾中,直接生成電子商務/產品影片——產品示範、促銷廣告和相片幻燈片。

ecommerce-video-skills 是什麼?

此技能旨在將靜態產品截圖或設計稿轉化為精緻的動畫示範影片。它適用於建立應用程式或 SaaS 示範、功能發布預告、入門引導等場景。其核心優勢在於,所有動畫(如游標移動、點擊波紋、畫面縮放)皆由程式碼驅動,確保每次渲染結果一致,且可透過更換單張截圖輕鬆更新,克服了傳統螢幕錄影中游標抖動、UI 版本不一致等問題。技能基於 Remotion 框架實現,支援將多張 2 倍解析度的截圖放入瀏覽器或手機外框中,並自動生成流暢的動畫路徑,包括游標平滑移動至目標像素、點擊時的波紋反饋、放大至指定 UI 區域以凸顯細節,以及為每個步驟添加簡短的圖說標註。螢幕之間的切換提供推入、交叉縮放、淡入淡出等多種風格。最終輸出為 MP4 影片,並提供完整的驗證流程,包括渲染靜態幀檢查、導出影片及批次處理腳本,確保產出品質。

相容平台~Claude Code~Codex CLI✓Cursor
npx skills add iart-ai/ecommerce-video-skills

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

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

說明文件

產品示範影片

將靜態產品截圖或設計稿轉化為精緻的動畫示範——無需螢幕錄影、無抖動的實際游標、無 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> + 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 已編碼並可播放;(選擇性)為 README 渲染了 GIF。

參考文件

  • references/screenshot-demo.md — 一個完整可執行的 Remotion 示範:使用 Playwright 以 2 倍解析度擷取截圖、瀏覽器/手機外框元件、一個多步驟組合,可跨多個畫面移動游標並產生點擊波紋,以及一個渲染指令。
  • references/annotation-and-transitions.md — 聚光燈遮罩、箭頭連接器、帶時間軸的說明軌道、推入/滑動與交叉縮放轉場,以及在共享元素上匹配剪輯的模式。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相關技能