app-preview-craft — 商店截圖、社交卡片與 3D 裝置影片
此技能製作出的所有內容都是一個頁面(stage/stage.html),由主題設定樣式,並由無頭 Chrome 捕捉:靜態圖片會進行螢幕截圖並由 sharp 完成後處理,影片則逐格渲染並傳送至 ffmpeg。同一個頁面也驅動著預覽工作室,因此使用者在那裡看到的內容與 CLI 匯出的結果完全一致。
0. 找到技能,完成一次性設定
以下路徑是相對於存放此 SKILL.md 的目錄。 解析一次路徑,然後在所有指令前加上該路徑 — 整份文件中的 $SKILL 都代表該目錄:
SKILL=/absolute/path/to/app-preview-craft # 包含 SKILL.md、scripts/、stage/ 的資料夾
# 不確定安裝在哪裡?(技能資料夾,然後是 Claude Code 插件快取)
find ./.claude/skills ./.agents/skills ./.goose/skills ~/.claude/skills ~/.agents/skills \
~/.gemini/skills ~/.config/goose/skills ~/.claude/plugins \
-path '*app-preview-craft*/scripts/cli.mjs' 2>/dev/null | head -1
然後檢查機器。當缺少套件時,--fix 會在技能目錄內執行 npm install:
node "$SKILL/scripts/doctor.mjs" --fix
醫生腳本必須以 Ready. 結束。缺少 ffmpeg 只是一個警告(靜態圖片仍然可以運作)。如果它報告沒有 WebGL,則 3D 主題無法渲染 — 請告知使用者,而不是默默切換到平面主題。
輸出內容會放到使用者目前工作的目錄(shell 的 cwd),除非他們用 --out 指定另一個資料夾。永遠不要將渲染結果寫入 $SKILL。暫存狀態存放在 $TMPDIR/app-preview-craft/ 中,並在每次執行後清除。
1. 工作流程
-
選擇類別(命令列的第一個參數),根據使用者的要求:
類別 製作內容 預設尺寸 app-store一個集合:每張投影片一張截圖,每種尺寸各一張,加上 overview.pngiphone-6.91320×2868social-card一張卡片(或 --all所有投影片),適用於 og/X/LinkedIn/Instagram/限時動態og1200×630screen-video僅使用螢幕錄影製作的 2D 動態影片;可接受螢幕錄製檔案 reel1080×1920device-videothree.js 裝置展示影片 reel1080×1920device-mockup3D 主圖靜態圖片,可選擇是否透明背景 mockup-landscape2400×1600 -
收集內容。 從使用者的專案中取得螢幕截圖(PNG/JPG/WebP)和/或錄影(MP4/MOV/WebM),每張投影片一張,按順序排列。除非使用者提供文案(請參閱 §4),否則請自行撰寫文案。如果沒有螢幕截圖,則會使用內附的範例應用程式「Tempo」— 這在展示主題時可以接受,但絕不能用於最終交付物。
-
選擇主題。 使用者指定的主題優先。對於 App Store 集合,請將應用程式的商店類別與 §3 的表格進行比對,說明您選擇了哪個主題以及原因。當使用者猶豫不決時,請先向他們顯示選項:
node "$SKILL/scripts/cli.mjs" gallery app-store # → ./gallery-app-store.png讀取產生的圖像(以便為使用者呈現),讓他們選擇。工作室(§8)是當他們想要瀏覽和微調時的更好解決方案。
-
渲染。
node "$SKILL/scripts/cli.mjs" app-store shots/01.png shots/02.png shots/03.png \ --theme ledger \ --title "每一分錢,*清楚記錄*" --title "*智慧適應*的預算" --title "*設計*保障隱私" \ --subtitle "一行說明的優勢…" --subtitle "…" --subtitle "…" \ --size iphone-6.9,ipad-13 --set palette.accent=auto -
回報前,先檢查。 讀取
overview.png(適用於集合)、靜態圖片,或從影片中提取影格(--frames 1,4,mid,end會渲染 PNG 影格而非影片 — 用於檢查動畫效果成本較低)。檢查是否有標題被截斷、文字覆蓋到裝置、裝置遮蓋到裝飾元素、或是空的螢幕畫面。使用--set/每張投影片的覆蓋設定進行修正,然後重新渲染。 -
回報 輸出檔案的路徑、主題和尺寸,以及 — 每當出現 3D 裝置時 — 說明
CREDITS.txt已寫入,且 CC-BY 授權聲明必須伴隨圖片一起使用(§7)。
2. 尺寸
node "$SKILL/scripts/cli.mjs" list sizes --category app-store 會輸出尺寸表格。任何 WxH 格式的尺寸也都可以使用。一次使用多個尺寸:--size iphone-6.9,iphone-6.5,ipad-13。
- App Store Connect 要求 iPhone 應用程式使用 6.9 吋尺寸集(
iphone-6.9),iPad 應用程式使用ipad-13;其他尺寸為選用。PNG 輸出會扁平化(Apple 不接受透明背景)。 - 平板電腦尺寸會自動將手機換成平面的平板電腦框架,除非主題是無框的。當應用程式有 iPad 截圖時,請為那些投影片提供 iPad 截圖。
- 應用程式預覽影片:
--size app-preview(886×1920)或app-preview-ipad,長度 15–30 秒,30 fps。會自動添加靜音立體聲 AAC 音軌(Connect 預期有音訊)。 - Google Play:
play-phone、play-tablet和play-feature(1024×500,社交卡片尺寸)。
3. 主題
list themes --category <c> 會輸出這些主題及其佈局。每個類別至少有 5 個主題。
app-store — 每個主題都模仿一個熱門應用程式類別
| 主題 | 應用程式類別 | 靈感來源 | 外觀 |
|---|---|---|---|
stride | 健康與健身 | Strava, Nike Run Club | 亮橘色,壓縮的全大寫藥丸形狀,速度條紋,傾斜手機 |
ledger | 金融 | Revolut, Monzo, Robinhood | 午夜藍網格,薄荷綠→青色漸層文字,鍍鉻球體 |
serene | 健康與正念 | Calm, Headspace | 粉彩極光,斜體襯線重點,無框螢幕置於柔和色塊上 |
canvas | 生產力 | Notion, Things, Linear | 溫暖紙張,筆記本網格,大型襯線字體,平面墨水色手機 |
sizzle | 飲食 | DoorDash, Uber Eats, Deliveroo | 陽光黃色,圓點圖案,紅色螢光筆重點,傾斜手機 |
wander | 旅行 | Airbnb, Hopper, Booking | 黃昏漸層,帶有復古太陽,橫跨整個集合(全景) |
mixtape | 音樂與音訊 | Spotify, Apple Music | 您的螢幕畫面模糊處理成發光背景,巨大輪廓字詞 |
arcade | 遊戲 | Apple Arcade, 手機遊戲發布美術圖 | 合成波網格,霓虹邊框,光滑 3D 玩具 |
snapshot | 照片與社交 | Instagram, BeReal, VSCO | 三張無框截圖像照片般扇形展開,溫暖底片網格 |
pulse | 健康資料與穿戴裝置 | Oura, WHOOP, Apple Health | 臨床黑色,深紅色光芒,標題位於正面 Pro Max 下方 |
這些主題借用了一種氛圍,而非品牌:不會出現這些應用程式的標誌、名稱或美術圖。
social-card
launch(極光 + 傾斜手機)、spotlight(光束 + 鏡面地板)、pastel-fan(三張扇形展開的螢幕)、bento(螢幕裁切網格)、neon-grid(合成波)、editorial(紙張、襯線字、雙色調螢幕)、duo(MacBook + 手機 — 為筆電傳入一個 desktop 螢幕畫面)。
screen-video(2D)
carousel、stack(卡片飛走)、scroll(長截圖在手機內滾動)、zoom-tour(全版 Ken Burns 效果,移動到每個投影片的 focus 點)、wall(傾斜的螢幕牆)、store-preview(App Store 預覽風格 — 使用 --size app-preview)、grid-reveal。
device-video(3D)
turntable、orbit(相機弧線運動)、float(可循環)、rise(相機推近)、flip(背面 → 正面揭示)、trio(三個模型扇形展開)、desk(MacBook 上蓋打開,手機滑入其旁;兩者皆立於 scene.floor 上)、spotlight(在鏡面上 360° 旋轉)、synthwave、keyframes(您自己的裝置和相機移動,來自 motion.keys — 請參閱 §5)。
device-mockup(3D 靜態圖片)
studio、noir、pedestal、levitate、lineup(每款手機型號)、flatlay、desk-duo。加上 --transparent 可產生去背 PNG。
4. 文案
- 每張投影片的標題:≤ 6 個詞,表達好處而非功能。用
*星號*將 1–2 個詞框起來,以主題風格凸顯它們;" | "會強制換行。 - 副標題:一個簡短的句子。可選的標籤(Kicker):上方的一個詞標籤。
- 前兩張投影片承載主要訴求 — 大多數購物者不會繼續往下滑。
- 絕不虛構評分、下載量、獎項或新聞引用。像
rating和laurels這樣的裝飾元素僅用於使用者提供的真實數據;在不確定的時候詢問使用者。 - 文案中不要提及競爭對手名稱,或使用超出商店指南允許範圍的 Apple/Google 商標。
5. 設定任何東西
解析順序,越後面優先級越高:
內建基礎值 → 佈局預設值 → 主題(及其 extends 鏈)→ 自訂主題檔案 → 專案設定檔 themeOverrides → CLI 快捷鍵 → --set → 每張投影片的 theme。
- 快捷鍵:
--layout --device --finish --pose --font --body-font --bg --bg2 --bg3 --ink --sub --accent --accent2 --background --pattern --background-image --clean-status-bar --no-decor --duration --fps --speed --intro --outro。 --set path=value可以任意主題鍵值(可重複)。list options會輸出具有型別和範圍的文件化路徑。值會自動轉型;JSON 可用於列表/物件:--set device.pose=5,-15,4 --set 'decor=[{"kind":"sparkles","count":8}]'。device.pose是x,y,z度。主題大致保持在 ±20° 偏航角和 ±6° 翻滾角以內,以便在商店縮圖尺寸下螢幕仍可閱讀;更陡的角度雖然可行,但會犧牲可讀性。- 顏色接受
auto= 第一張截圖中最鮮豔的顏色:--accent auto。 --device iphone-17-pro | iphone-17-pro-max | iphone-12-pro | galaxy-s21-ultra | macbook-pro-16 | flat[:phone|phone-android|tablet|browser] | frameless | none,或是使用者自有模型的 ID(§7)。- 佈局在相同類型內可以互換(
list layouts):靜態圖片 —hero-top、hero-bottom、tilt、duo、fan、split、big-type、callout、bento、laptop-phone、showcase、pedestal、lineup、flatlay;影片 —carousel、stack、scroll、zoom-tour、wall、phone-swap、grid-reveal、turntable、orbit、float、rise、flip、trio、desk、spotlight、keyframes。 - 您自己的動畫:
keyframes佈局透過motion.keys移動一個 3D 裝置和相機,它是一個包含{ "at": 0..1, "x", "y", "size", "pose": [rx, ry, rz], "cam": { "yaw", "pitch", "dist" }, "ease" }的列表。at是整個影片的比例;某個鍵未提供的值會保持前一個鍵的值;第一個鍵從主題自身的姿勢開始。 緩動函數:linear inOutCubic inOutSine outCubic outQuart outBack inOutQuart outExpo。--theme keyframes --set 'motion.keys=[{"at":0,"y":1.4,"pose":[0,70,0]},{"at":0.3,"y":0.62,"pose":[4,-20,3],"ease":"outQuart"},{"at":1,"pose":[0,15,0],"cam":{"dist":0.9}}]'。 沒有使用任何動畫函式庫:每一個影格都是其時間的純函數,這使得影格可以按任何順序渲染。使用--frames 0,2,mid,end檢查動態。
自訂主題是 JSON(或 .mjs)檔案,包含任何主題鍵的子集,加上 extends:
{ "extends": "app-store/ledger", "name": "Acme", "palette": { "accent": "#ff5a1f" },
"type": { "display": "bricolage", "weight": 800 }, "device": { "finish": "#1c1f24" } }
使用 --theme path/to/acme.json 傳入,或將其放入 ./.app-preview-craft/themes/(或
~/.app-preview-craft/themes/)並使用 --theme acme。list themes 會顯示自訂主題。
專案設定檔。 node "$SKILL/scripts/cli.mjs" init app-store 會寫入 app-preview-craft.json;
之後 node "$SKILL/scripts/cli.mjs"(不帶參數)會渲染它,而旗標仍會覆蓋它。$SKILL/examples/app-preview-craft.json 是一個完整的、可運作的範例:包含每張投影片的文案、裝飾元素和主題覆蓋設定、一個自訂主題檔案、一個桌面螢幕畫面,以及一個 jobs 列表,可以用一個指令渲染 App Store 集合、社交卡片、模型圖片和影片。設定檔中的路徑會相對於設定檔本身解析。
每張投影片的鍵值:screen、desktop(筆電顯示器)、title、subtitle、kicker、
theme(僅用於該投影片的覆蓋設定)、decor(替換該投影片的主題裝飾)、
focus: [x, y, zoom](zoom-tour 目標)、hold(影片中的停留秒數)、trim: [start, end]
和 at(靜態圖片使用錄影檔的哪一秒)、bigWord(big-type 佈局)。
裝飾項目是 {kind, x, y, scale, rotate, style, layer, delay, …},其中 x/y 為頁面比例,style 為 glass | solid | light | dark | outline:
| kind | 額外鍵值 |
|---|---|
badge | text、icon(star bolt heart check sparkle trophy leaf lock music pin flame bell chart shield globe play) |
rating | score、label、starColor |
laurels | top、text、bottom |
chips | items[]、icons[]、width、lead |
notification | app、title、body、time、icon(圖片路徑)或 glyph、width |
stat | label、value、trend、trendColor |
callout | 截圖中要放大的 rect: [x, y, w, h]、w、border、radius |
arrow | w、h、text(手寫筆記)、flip、stroke |
logo | name、src(應用程式圖示路徑) |
store-badge | top、text 或 src 用於官方徽章美術圖 |
sparkles confetti | count、colors[]、area: [x0, y0, x1, y1]、seed |
blob | size、color、opacity(位於裝置後方) |
orbs rings shapes | 3D 基本體:count、shapes[]、finish(glossy chrome matte glass iridescent)、area、items[] |
credit | text(預設為模型授權行) |
6. 螢幕畫面與處理
- sharp 在 Chrome 啟動前會準備好每張截圖:
screen.cleanStatusBar(重新繪製 9:41 / 滿電 iOS 狀態列 — 僅限手機形狀的截圖)、tint+tintAmount、duotone: "#dark,#light"、saturate、brightness、sharpen,以及用於blur-shot背景的預先模糊背景。 - 在 iPhone 型號上,動態島(Dynamic Island) 會繪製成一個合併的黑色膠囊形狀,覆蓋在型號的膠囊和相機挖孔上,與 iOS 顯示的相符。請提供動態島區域為空白的截圖(任何一般的 iOS 截圖皆可);
cleanStatusBar會保留兩側的時間和圖示。 - 比顯示器高的截圖在影片中會滾動(
scroll主題),並在靜態圖片中顯示其頂部(screen.fit=top)。 - 錄影檔會由 ffmpeg 以輸出影格率分割成影格;在影片中,每個錄影檔的投影片會持續與剪輯相同的時間(使用
hold覆蓋,使用trim裁切)。靜態圖片使用一個影格(at,預設:中間)。 - 筆電顯示器會將手機截圖以信箱模式置於模糊副本上,除非該投影片有
desktop螢幕畫面。desktop也可以接受錄影檔。在desk影片中,筆電螢幕播放其獨立的媒體。 - 螢幕畫面檔案不必是標準解析度或比例:它們會被裁切並調整大小以適合顯示器。除非螢幕實在太窄,否則不應出現背景露出的情況。
7. 3D 裝置型號
型號是 .glb 檔案。內建模組([email protected] 的設計)在輸出影片旁以 CREDITS.txt 形式附帶 CC-BY 4.0 授權。型號 ID 可以與圖片一起傳遞給協作者。使用者可以透過將 .glb 檔案放入 ./.app-preview-craft/models/ 或傳遞 --device /path/to/model.glb 來新增自己的型號。如果型號缺少紋理(僅材質),它會反射場景:設定 'model.lighting': "studio" 以獲得最佳效果。list devices 會列出所有可用的型號。
8. 工作室 — 所見即所得編輯器
node "$SKILL/scripts/cli.mjs" studio # 預覽主題並即時編輯
node "$SKILL/scripts/cli.mjs" studio screens/ # 載入一個資料夾的截圖
node "$SKILL/scripts/cli.mjs" studio app-preview-craft.json # 從設定檔載入
這會開啟 http://localhost:3775。工作室是 stage/stage.html,運作方式與 CLI 輸出完全相同 — 因此沒有差異。介面圍繞著主題輪播、時間軸和並排的設定編輯器建構。您可以點擊分享按鈕來複製一個 URL,該 URL 會將整個場景編碼在片段中 — 除了影片。 將該 URL 傳送給協作者:他們的瀏覽器會渲染相同的預覽,無需下載技能。
將編輯後的 URL 貼回來(使用者點擊匯入),或貼到 --url 中以無頭模式渲染它。
快速回饋迴圈。 當工作室執行時,所有 CLI 渲染(在單獨的終端機中)都會透過 websocket 即時將預覽推送到工作室。使用者可以在查看結果的同時調整主題參數,並在滿意時點擊匯出。
9. 多工作業
設定檔中的 jobs 列表會依次渲染每個作業。之後執行 node "$SKILL/scripts/cli.mjs" [job-name] 只會渲染該命名的作業。
"jobs": [{"name": "release-v2", ...}, {"name": "social-launch", ...}]
10. 輸出
- 圖片:PNG(含選項用於 WebP、JPEG、AVIF、TIFF 以及 sharp 支援的任何格式)
- 影片:MP4 H.264(預設),使用
--format webm輸出 WebM VP9 - 套裝樣板(Mockup Packs):
--out zip會將多個作業輸出壓縮成一個.zip - 預設命名:
{theme}-{slide_index}-{size}.png。使用--prefix變更。 - 所有輸出始終包含一個
metadata.json,其中包含使用的指令、主題鍵、軟體版本以及用於重現結果的散列值。
11. 測試與提示
--frames 1,4,mid,end:渲染靜態影格而非整個影片,用於快速檢查動態。--dry-run:列印 resolved 設定而不渲染任何內容。與jq搭配使用效果很好。list子指令:themes、sizes、options、layouts、devices、decor、fonts— 全部接受--category和--kind過濾器。doctor:驗證依賴項。透過doctor.mjs加入更多檢查。gallery:輸出一個包含所有主題/尺寸組合的網格圖片,對於展示和文件非常有用。init:為使用者的專案產生一個設定檔樣板。- 為了獲得最快的迭代速度:使用
--size small(600×400 畫布)和--frames end。 - 處理非常大的截圖:sharp 會將影像調整為顯示器解析度(max 2000px 寬),這對於所有輸出來說已足夠。使用
config.screen.sizing: "native"強制保留解析度。
12. 安全性
- 截圖和錄影檔僅透過檔案系統路徑讀取。沒有網路請求。
- 自訂
.glb模型在沙盒化環境中載入;它們不能執行任意程式碼。 stage/stage.html在所有渲染中禁用eval()和內聯腳本。- 設定檔被視為使用者提供的 JSON;路徑會進行清洗以防止目錄遍歷。
13. 貢獻
拉取請求請提交至 [email protected]。此技能使用 MIT 授權。
app-preview-craft — 從截圖到商店素材,只需一個指令。