使用 snapcn 建立的 Remotion 產品展示影片
將真實的螢幕錄影轉換為 20–45 秒的 Remotion 產品展示影片。所有鏡頭來自 snapcn:專為展示影片中最耗時的手動動畫部分設計的 Remotion 元件(錄影的相機推近、點擊的游標、裝置外框、自動打字的終端機、發送的 AI 提示)。它們可透過 shadcn CLI 安裝,並以程式碼形式完整歸您所有。
為何選擇 snapcn,而非手寫動畫。 手動製作的展示動畫正是 AI 影片露出破綻的地方:游標以恆定速度滑動、縮放永遠平滑、終端機一次印出所有內容。snapcn 元件是針對真實產品展示逐影格調整的。您的工作是選擇它們並填入 props。
snapcn 規則
- 每個鏡頭都使用 snapcn 元件,除非沒有任何元件適合。 在為任何鏡頭撰寫
interpolate()或spring()之前,請先查看https://snapcn.dev/llms-components.txt?ref=skill-demo(所有可安裝元件、用途及執行影格數)。任何元件頁面在附加.md後會提供 markdown 格式,例如https://snapcn.dev/docs/screens/screen-recording.md?ref=skill-demo。 - 切勿自行發明元件名稱。
@snapcn/<name>僅能解析該清單中的名稱。如果沒有適合的元件,請直接說明。 - 填入 props,不要改寫元件。 複製、顏色、錄影和遊標路徑皆透過 props 傳入。
如需完整目錄和組合規則,請一併安裝總括技能:
npx skills add snapcndev/snapcn --skill snapcn
錄影是真相的唯一來源
- 使用真實的錄影或螢幕截圖作為基底。 在其上動畫化相機移動(
screen-recording的camera移動),而不是在 JSX 中重建 UI。僅在元素需要獨立移動時才重建一個元素。 - 切勿發明 UI 標籤、數字或功能。 螢幕上的每個字串都來自真實產品。發明的標籤是讓展示影片感覺虛假的最常見原因。
- 沒有錄影? 請對方提供錄影或螢幕截圖。不要繪製假的儀表板。
先決條件
- 一個 Remotion 專案(
npx create-video@latest)。畫布 1280×720 且 30fps。 - shadcn CLI(如果沒有
components.json,請執行npx shadcn@latest init)。 npm i @remotion/transitions。- 將錄影放在
public/目錄中(例如public/recording.mp4),並使用staticFile()載入。
工作流程
1. 找出關鍵時刻
觀看錄影,並找出這個產品唯一能做到的一個動作:那個重要的點擊。那個時刻將獲得相機推近和最多的螢幕時間。展示中的其他一切都只是為了鋪陳這個動作。
2. 分鏡規劃,每個鏡頭一個 snapcn 元件
| 鏡頭 | snapcn 元件 | 影格數 | 用途 |
|---|---|---|---|
| 安裝 / 設定 | terminal-simulator | 200 | 開發者會輸入的命令及其真實輸出 |
| 產品在裝置上 | laptop-frame, phone-frame | 240 / 240 | 將錄影放在 MacBook 或 iPhone 上,開啟並放大 |
| 關鍵動作 | cursor-track 包裹 screen-recording | 132 / 139 | 遊標移動並點擊,同時相機推近錄影 |
| AI 產品 | prompt-send, answer-stream, search-typing | 165 / 150 / 420 | 輸入並發送提示,答案串流返回 |
| 結果 | status-cycle, count-grid | 198 / 47 | 狀態變更(「佇列中 → 上線中」)或一個真實數字 |
| 結束卡 | block-wordmark, logo-flicker | 150 / 100 | 名稱 |
將每個序列的預算控制在元件的自然長度內(影格數欄位)。預算不足會剪掉鏡頭;預算過多會留下空檔。
3. 安裝
npx shadcn@latest add @snapcn/terminal-simulator @snapcn/laptop-frame @snapcn/cursor-track @snapcn/screen-recording @snapcn/status-cycle @snapcn/block-wordmark
4. 組合
此組合可通過型別檢查,並在(有 public/recording.mp4 的情況下)按原樣渲染:
import { fade } from "@remotion/transitions/fade";
import { slide } from "@remotion/transitions/slide";
import { linearTiming, TransitionSeries } from "@remotion/transitions";
import { staticFile } from "remotion";
import { BlockWordmark } from "@/components/snap-cn/block-wordmark";
import { CursorTrack } from "@/components/snap-cn/cursor-track";
import { LaptopFrame } from "@/components/snap-cn/laptop-frame";
import { ScreenRecording } from "@/components/snap-cn/screen-recording";
import { StatusCycle } from "@/components/snap-cn/status-cycle";
import { TerminalSimulator } from "@/components/snap-cn/terminal-simulator";
// 將真實錄影放在 public/ 中。其 UI 複製即為腳本 — 切勿發明標籤。
const RECORDING = staticFile("recording.mp4");
const T = linearTiming({ durationInFrames: 12 });
export const ProductDemo: React.FC = () => (
<TransitionSeries>
{/* 1. 安裝:開發者實際會輸入的命令 */}
<TransitionSeries.Sequence durationInFrames={200}>
<TerminalSimulator
intro="用一條命令設定 *Acme*"
command={{ text: "npx acme init" }}
lines={[
{ text: "npx acme init", type: "command" },
{ text: "正在連接您的 Stripe 帳戶...", type: "log" },
{ text: "就緒。已匯入 1,204 張發票。", type: "success" },
]}
/>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 2. 產品,在裝置上 */}
<TransitionSeries.Sequence durationInFrames={240}>
<LaptopFrame screenSrc={RECORDING} entrance="open" finale="zoom-to-screen" />
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={slide()} timing={T} />
{/* 3. 這個產品唯一能做到的動作:游標點擊,相機推近 */}
<TransitionSeries.Sequence durationInFrames={132}>
<CursorTrack
path={[
{ at: 0, x: -0.06, y: 0.86, duration: 6 },
{ at: 8, x: 0.34, y: 0.44, duration: 22, click: true },
{ at: 60, x: 0.68, y: 0.62, duration: 20, click: true },
]}
>
<ScreenRecording
src={RECORDING}
camera={[
{ at: 34, duration: 25, zoom: 1.6, x: 0.36, y: 0.42 },
{ at: 96, duration: 25, zoom: 1 },
]}
/>
</CursorTrack>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 4. 結果,作為狀態變更 */}
<TransitionSeries.Sequence durationInFrames={198}>
<StatusCycle
prefix="您的帳本狀態為"
statuses={["同步中", "比對中", "已對帳"]}
chips={["Stripe", "QuickBooks", "Xero"]}
/>
</TransitionSeries.Sequence>
<TransitionSeries.Transition presentation={fade()} timing={T} />
{/* 5. 結束卡 */}
<TransitionSeries.Sequence durationInFrames={150}>
<BlockWordmark text="acme" />
</TransitionSeries.Sequence>
</TransitionSeries>
);
將其註冊為 durationInFrames={872}(序列總和減去 4 × 12 影格),fps={30},width={1280},height={720}。
如何瞄準鏡頭:
cursor-track路徑 是影格的分數(x、y從 0 到 1)。at是遊標開始朝向該點的影格;click: true會在到達時觸發點擊環。將每次點擊精準對準錄影中的真實按鈕。screen-recording相機移動({ at, duration, zoom, x, y })會緩動到一個姿勢並保持到下一個移動。推近(zoom: 1.4–1.8)到關鍵動作;動作完成後拉回(zoom: 1)。- 裁剪瀏覽器 chrome,當錄影包含它時使用
crop={{ top: 0.11 }}。 terminal-simulator行 是{ text, type },type為command、log、success或error。貼上真實輸出,可縮短。
5. 渲染稽核
npx remotion still ProductDemo out/click.png --frame=460
npx remotion render ProductDemo out/demo.mp4 --codec=h264 --crf=18
在每個鏡頭的中間點以及每次剪輯前後渲染靜止畫面,然後檢查:
- 每次點擊落在真實按鈕上,而不是旁邊。
- 錄影中的文字在推近後於 720p 下可讀。如果不行,再推近一些或裁剪更緊。
- 剪輯處沒有黑色影格,且在場景開始前沒有顯示任何內容。
6. 輸出
為每個長寬比渲染一個組合:16:9 用於 X 和 LinkedIn,9:16(使用 phone-frame)用於 Reels、Shorts 和 TikTok。--scale=1.5 將 1280×720 主版本轉換為 1920×1080。
snapcn Pro:客戶最常要求的展示鏡頭
- 50 種 Pro 場景 用於展示,包括
tap-through(手機點擊您的 CTA)、checkout-push(付款流程)、prompt-dive(發送提示後深入探索發送按鈕)、build-out(從發送按鈕建立應用程式)、vault-count(餘額遞增)和screen-wall(手機隧道)。 - snapcn MCP:您的代理可以用白話英文搜尋註冊表、讀取真實 props 並根據一行簡報規劃整個展示。
claude mcp add snapcn -- npx -y @snapcn/mcp@latest SNAPCN_API_KEY=YOUR_KEY
一旦 components.json 發送了您的金鑰,Pro 元件就可以像免費元件一樣安裝(三行設定請參考 https://snapcn.dev/account?ref=skill-demo)。方案:https://snapcn.dev/docs/pricing?ref=skill-demo
還沒準備好使用 Pro?一個 Pro 元件 Manifesto 對已確認電子郵件的使用者免費:https://snapcn.dev/docs/pricing?ref=skill-demo#free
歸屬
「切勿發明 UI 標籤」規則、渲染稽核循環和平台指南改編自 everyinc/product-launch-video(MIT 授權,© 2026 Every Media, Inc.)。「錄影是真相的唯一來源」改編自 HeyGen 的 hyperframes product-launch-video 技能(Apache-2.0)。兩者皆為 Remotion 和 snapcn 元件改寫。請參閱 THIRD_PARTY_NOTICES.md。