產品啟動影片
產出約 40 秒的影片,其中動態圖形引導敘事,而每個「產品」像素皆由真實應用程式渲染。
此技能的存在是為了解決人們常犯的錯誤選擇:
- 純動態圖形影片看起來專業,但無法證明任何事 - 沒有真實產品。
- 原始的螢幕錄製能證明一切,但看起來業餘 - 沒有動態設計。
答案並非兩者擇一:Remotion 是主時間軸,而產品鏡頭是真實的幀,通過在無頭瀏覽器中驅動實際應用程式來捕獲。
在產品旁建立一個小型的 Remotion 專案:共享的捕獲工具包 + 基本元件,每個應用程式的影片一個目錄(品牌、鏡頭、捕獲腳本、時間軸)。請參閱 references/toolkit.md 了解建議的佈局。
不可妥協的事項
在編寫任何程式碼之前請先閱讀這些。每一項都花費了實際的除錯時間,而且每一項都會無聲地失敗——你會得到看起來合理但錯誤的輸出。
捕獲
| 陷阱 | 發生情況 | 修復方法 |
|---|---|---|
setViewport({deviceScaleFactor: 2}) | page.screencast() 會以系統 DPR 來測量其 ffmpeg 濾鏡鏈,因此它會建立一個 1× 的鏈並丟棄 Retina 細節。沒有錯誤訊息。 | 在瀏覽器端強制設定:--force-device-scale-factor=2 + 在 viewport 中設定 deviceScaleFactor: 0(0 表示「系統預設」)。 |
| 無頭模式下不顯示游標 | page.mouse.move() 會發送頁面能看到的 CDP 事件,但沒有任何東西被繪製出來。 | 透過 evaluateOnNewDocument 注入一個 DOM 游標。將它放在頁面中,而不是在 Remotion 中合成——這樣每個 Remotion 變換(幀內嵌、縮放推近)都會像真實錄製一樣精確縮放它。使用精靈需要反轉每個變換,而且 6px 的偏差就會被視為故障。 |
| 無頭模式下沒有 GPU | 任何 WebGL/three.js 內容都會錄製為空白或黑色面板。 | 使用 --use-gl=angle --use-angle=swiftshader --enable-unsafe-swiftshader。透過像素回讀來驗證,而不僅僅是「上下文是否存在」。 |
| SwiftShader 也會合成頁面 | 一個軟體 GL 驅動程式合成 2560x1440 會將整個分頁限制在大約 8fps,因此每個動畫鏡頭都會錄製成幻燈片。這看起來像是產品很慢,而不是捕獲有問題,所以沒有人會懷疑是旗標的問題。 | 添加 --disable-gpu-compositing。Skia 的 CPU 光柵化器在處理純 2D 時快得多,WebGL 仍然可以工作,A/B 靜態畫面完全相同。在同一頁面上測量:8.2fps → 60.1fps。 |
| 用肉眼判斷流暢度 | 重複的幀在縮圖檢視或逐幀檢視時看起來沒問題。只有在播放時才會發現,而此時已經渲染完成了。 | 計算不重複的幀:ffmpeg -i take.mp4 -vf mpdecimate,showinfo -f null - 2>&1 | grep -c pts_time。遠低於檔案幀數表示有卡頓。 |
page.mouse.click(x, y, {clickCount: 2}) | 發送一次包含 clickCount 元數據的按壓操作。Chrome 永遠不會合成 dblclick。間隔 60ms 的兩次獨立點擊也不會。 | 如果應用程式需要真實的 dblclick,先點擊以移動可見游標,然後在元素自己的座標處在幀內調度該事件。 |
點擊進入 iframe 後使用 page.keyboard.type() | 按鍵會發送到父頁面聚焦的任何元素。如果父頁面將按鍵轉發給應用程式(例如方向鍵導航、快捷鍵),你的打字動作會無聲地驅動 UI,而不是輸入文字。 | 在框架內輸入:frame.type(selector, text)。 |
evaluateOnNewDocument 執行 DOM 操作 | 在 document-start 時執行,此時 document.head 和 document.documentElement 都可能為 null。未經保護的 appendChild 會拋出錯誤並無聲地中止該腳本之後的所有操作。 | 加入保護,並延遲到 DOMContentLoaded。 |
| 錄製導航過程 | 將有用的秒數深埋在檔案中,並使中介檔案的體積膨脹。 | 將每個鏡頭拆分為 setup(不錄製)和 action(錄製)。 |
| 信任標記時間戳 | Screencast 是可變幀率的;編碼後的時間軸會壓縮相對於實際時間,因此 22s 處的標記在檔案中並不在 22s 處。 | 使用標記來大致找到位置,然後通過提取幀並檢視來選擇 startAt。 |
| 遠端/託管資源 | 第三方 CDN 會間歇性地拒絕捕獲瀏覽器;圖像網格會顯示為空的透明棋盤格,這看起來像是產品壞了。 | 等待圖像並發出警告,然後調整鏡頭構圖以避免它們。不要提供帶有空白素材的錄製片段。 |
在應用程式外殼中使用 window.scrollTo | 許多應用程式外殼會滾動一個內部元素(<main class="overflow-y-auto">),而不是視窗。滾動視窗是無聲的無操作,鏡頭永遠不會移動。 | 找到真正的滾動容器並設定其 scrollTop。 |
| 猜測點擊座標 | 應用程式通常只接受特定節點上的互動——例如一個只接受葉子元素(childElementCount === 0)的內聯編輯器,而標題則會將其文字包在 span 中。點擊視覺上明顯的目標不會有任何作用。 | 讀取應用程式自己的原始碼來了解規則,然後詢問頁面其有效目標在哪裡(frame.evaluate),並通過 iframe 的測量框將框架座標映射到頁面座標。 |
渲染
| 陷阱 | 發生情況 | 修復方法 |
|---|---|---|
| 跳過中介檔案轉碼 | Remotion 會任意跳轉;使用普通的 GOP(Group of Pictures),每次跳轉都需要從前一個 I 幀解碼。3 分鐘的渲染會變成 40 分鐘。 | 轉碼為全幀內編碼:-c:v libx264 -crf 14 -g 1 -keyint_min 1 -sc_threshold 0 -pix_fmt yuv420p,加上明確的 bt709 標籤,這樣 Chrome 就不會改變品牌顏色。 |
page.screencast({format:'mp4'}) | 輸出在碎片化 MP4 中的 VP9 格式——支援度很差。 | 使用 format: 'webm',然後進行轉碼。 |
帶有節奏網格的 <TransitionSeries> | 轉場重疊,因此總時長 = 序列總和 − 轉場總和。你的幀網格會無聲地偏移。 | 對於幀精確的剪輯,使用明確的 <Sequence from/durationInFrames>,並在本地進行溶解。斷言鏈的總和等於總時長。 |
比其來源更長的 <Sequence> | 停留在最後一個解碼的幀上——看起來像是停頓,而不是錯誤。 | 限制每個時長不超過實際錄製長度。在註解中記錄來源時長。 |
在重疊的序列上使用 premountFor | 一個預先掛載的序列會在當前序列之上提前渲染——你會得到幽靈般的雙重曝光文字。 | 不要預先掛載共享畫面空間的序列;只在硬切換時預先掛載。 |
| 在合成空間中定位疊加層 | 如果影片元件在內部裁剪和縮放畫面,那麼放置在合成座標中的遮罩或高亮將不會與幀中的任何內容對齊——邊緣會穿過內容。 | 將疊加層放在與畫面本身相同的變換中,或者原生地進行處理,而不是放在影片之上。 |
在合成中使用 Math.random() / Date.now() | 每一幀都會重新計算;文字會閃爍。Remotion 會獨立渲染每一幀。 | 使所有隨機性都成為索引的純函數(一個基於 sin 的雜湊)。 |
Remotion 內部的 CSS 動畫 / 轉場 / Tailwind animate-* | 渲染會凍結或產生垃圾——Remotion 通過 useCurrentFrame() 驅動時間,而不是實際時間。 | 在 useCurrentFrame() 上重建動畫。這也意味著你通常無法重用行銷網站的動畫元件。 |
| 通過偏移影片來建立循環 | 兩個接縫錯誤:如果範圍在 dissolve 上開啟,會出現黑色閃爍;以及在循環處出現硬跳切。 | 為循環建立自己的合成,並將其尾部交叉淡入到其自身開頭的 <Freeze frame={0}>。選擇一個持續運動的鏡頭;任何靜止的鏡頭都接近靜態,不適合自動播放。 |
流程
1. 在設計影片之前,先確認產品事實
這是唯一最重要的步驟。 閱讀影片打算宣稱的每個功能的程式碼。行銷頁面展示的是願景;不要假定產品的功能如其登陸頁面的動畫所暗示的那樣。
這已經發生過一次:一個影片計劃中的核心鏡頭取自行銷網站上的一個動畫元件,該元件展示一個文件在四種不同的寬高比之間變換。而該產品硬編碼了單一的寬高比和固定的匯出階段——那個元件只是一個概念的插圖,而不是一個功能。以此為基礎構建關鍵鏡頭會在主頁上提出一個未經證實的主張。
具體檢查:
- 哪些內容實際渲染?舊的記錄可能無法被當前引擎渲染。
- 哪些路由需要驗證?哪些在沒有先前狀態的情況下會重新導向?
- 每個互動功能實際上需要什麼才能觸發?
2. 用最小的可能測試來降低管線風險
按順序,在建立任何上層結構之前:
- 證明捕獲幾何形狀(帶有角落標記的頁面 → 檔案真的是 2× 嗎?)。
- 證明驗證(瀏覽器能否到達已登入的路由?)。
- 如果涉及任何 3D,證明 WebGL。
- 端到端證明一次互動。
3. 探索,不要猜測
截取每個候選畫面的螢幕截圖,並在花時間進行影片錄製之前向用戶展示縮圖目錄。內容選擇主導製作價值:平庸的示範內容會讓一部精美的影片變成一個平庸產品的廣告。
4. 刻意選擇示範內容
優先選擇產品自己的品牌。展示一個知名的第三方更具說服力,但會將另一個公司的商標放在主頁上,而且用一個第三方替換另一個並不會改變這一點。自我參照的內容也能形成閉環:銷售該工具的作品是由該工具本身製作的。
如果內容還不存在,創建它是設計工作,而不是捕獲工作——它是影片後半部分的每一個幀。刻意起草它,產出幾個候選方案,讓用戶選擇。
5. 按照節奏網格剪輯
120 BPM ⇒ 1 小節 = 60 幀 = 2 秒(30fps)。讓每個剪輯點落在 30 的倍數上,每個幕的邊界落在 60 的倍數上。這不需要任何成本,而且剪輯版本可以輕鬆產生。
6. 通過觀看來驗證
每次渲染後,提取幀並實際觀看它們。建立一個帶有標籤的縮圖目錄。迄今為止發現的所有實際缺陷——空白的標誌、顯示錯誤頁面的鏡頭、在淺色面板上難以辨認的標題、因測量錯誤的裁剪而產生的暗帶、穿過標籤的遮罩縫隙——都是通過觀看幀發現的,而不是通過任何測試通過。
在靜音狀態下觀看,因為這就是它自動播放時的樣子。
編輯規則
這些是區分一個「有效」的影片和一個「好」的影片的關鍵。
螢幕上的每個主張都必須得到旁邊影片素材的支持。 曾經有一個剪輯,在顯示「分享連結」的影片素材上,沒有任何東西顯示分享。要嘛展示它,要嘛在一張卡片上清楚地說明它——不要暗示。
注意那些在上下文中誠實,但在影片規模下會變得虛假的主張。 一個在小字中標註為*「說明用」*的數字,一旦成為行銷影片中一個固定的主要畫面,就會變成一個強有力的斷言。將這些內容排除在固定畫面之外。
引用產品的動畫,不要重新發明。 使用應用程式自己的緩動曲線和入場詞彙。為所有進入或落地的內容使用一個曲線。不要有彈跳—— overshoot 會讀作猶豫不決。
兩個背景色,絕不使用中灰色。 使用深色背景進行陳述,使用淺色背景進行解釋。從產品自己的設計標記中挑選。
一個重點色,節儉使用 —— 游標、承載句子含義的那個詞、正在改變的狀態。不是裝飾。
畫面中沒有不是為了觀眾而存在的東西。 真實的電子郵件地址、組織名稱、操作者與應用內助手的對話、開發模式徽章。優先使用應用程式自己的機制(用於折疊側邊欄或關閉橫幅的 cookie)而不是 CSS 技巧——不要在鏡頭上出現閃爍。
一個「關鍵鏡頭」值得最多的時間。 選擇那個展示競爭對手結構性無法做到的事情的時刻,然後:鎖定鏡頭,沒有剪輯,沒有文字疊加在上面,讓音樂淡出。靜止告訴眼睛主體在移動,而不是鏡頭。將說明文字放在之後——在反應之前放置文字會告訴人們該想什麼。
可讀性勝過覆蓋率。 一個分散在四個螢幕上的鏡頭可能會讓它們都無法閱讀。通常停留在一個螢幕上更好。
當 UI 無法執行時,建立節奏而不是拍攝它。 一個靜態畫面無法一次介紹三個東西。如果節奏需要產品不支援的順序,在 Remotion 中使用產品的真實文案和設計標記本地合成它——並使其在視覺上與影片素材區分開來,這樣它看起來像是一個說明,而不是一個假的螢幕截圖。
如果沒有旁白,卡片承載 100% 的意義。 預留閱讀時間。
與用戶討論,不要獨自決定
- 標語和螢幕文案。 提供幾個按角度分組的選項,並附上推薦和理由。請注意,影片需要一個示範提示,而網站標題需要一個持久的定位陳述——它們不必是同一句話。
- 選擇哪些內容來展示 —— 展示縮圖目錄。
- 音樂。 你無法取得音樂授權。設計影片使其在靜音狀態下也能運作,並提供一個提示表(BPM、任何 Drop 發生的位置),以便之後提供的音樂可以對齊到節奏網格。當音樂到來時,在放置之前檢查其形狀:隨時間測量響度,而不是假設它有 intro 或 drop 可以對齊。
- Remotion 授權。 對個人、非營利組織和員工不超過 3 人的公司免費;超過此限制需要商業授權。在交付前提醒用戶。
命令(形式)
捕獲永遠不會啟動伺服器,也不會猜測埠——驗證 URL 通常是固定的。
# 終端機 1 — 產品已在運行
pnpm --filter <app> dev # 或等價命令
# 終端機 2 — 影片專案
pnpm install
pnpm check-webgl # 如果有任何 3D
pnpm capture:<app> # 或單個鏡頭:pnpm capture:<app> <shot>
pnpm mezzanine:<app> # 必選 — 請參閱陷阱
pnpm studio
pnpm render:<app> # 根據需要輸出 mp4 / webm / loop / poster
已登入畫面的驗證:優先借用現有的 session cookie,而不是註冊一個臨時用戶(空帳戶會在每次拍攝前強制進行緩慢的內容生成)。
發佈到頁面
兩種形式,由用戶決定:
- 短循環,點擊播放完整影片。 最輕量——幾百 KB 自動播放,完整的影片只有在……
…[此處內容已截斷,等待輸入]