agentshot:截圖與示範影片
此工具位於 /path/to/agentshot。執行方式如下:
node /path/to/agentshot/bin/agentshot.mjs <command> ...
在以下說明中,agentshot 即代表該指令。每個指令都會輸出一行 JSON("ok": true|false)。長時間的渲染過程也會在 stderr 輸出進度。
執行 agentshot help 以查看指令列表。
工作流程
- 先閱讀產品的規則:
agentshot style <product>會印出style.json(預設外觀)和guidelines.md(使用者的偏好)。請遵循它們。如果產品是新的,請執行agentshot style <product> --init。 - 捕捉(選擇一種):
- 網頁應用程式或 Expo 應用程式 → 編寫一個包含
"url"的 scenario JSON,然後執行agentshot capture scenario.json。 - Mac 上的 iOS 應用程式 → 一個包含
"simulator"的 scenario(iOS 模擬器中的真實原生應用程式,請參閱 "iOS 模擬器");快速靜態照 →agentshot sim snap --name <capture> --clean-status-bar。 - 桌面程式 → 一個包含
"window"的 scenario:您驅動真實的滑鼠/鍵盤,同時它進行錄製 (請參閱 "桌面應用程式")。僅需靜態照 →agentshot snap --window "<title>" --name <capture>。 使用者執行操作 →agentshot record start/stop。 - 使用者已有檔案(iPhone 截圖 / 螢幕錄影) →
agentshot import <file> --name <capture>。
- 網頁應用程式或 Expo 應用程式 → 編寫一個包含
- 檢查:
agentshot inspect <capture>會列出畫面、元素框(螢幕點位)、點擊、時長以及 對於影片,還有moves(指標移動)、changes(頁面切換:重大的視覺跳躍)、quiet(無移動: 應裁切或加速的部分)以及 scenario 的timeline。根據這些數據規劃裁切和縮放,然後用agentshot frames <capture> --from a --to b確認(一個附帶時間戳的聯繫表;請閱讀它產生的 PNG)。 在進行樣式設定前,請使用 Read 工具查看畫面 PNG。 - 編寫一個 recipe JSON 並執行
agentshot render recipe.json --note "<what changed>"。 - 自行檢查結果:閱讀 PNG;對於 MP4,使用
agentshot frames <product>/<asset>(整部影片)和agentshot frames <product>/<asset> --from 3 --to 4 --every 0.033 --crop x,y,w,h(逐幀檢查裁切或點擊附近)。 修正後重新渲染(會新增一個版本)。 當使用者想要自行調整或微調 recipe 時,在背景執行agentshot preview recipe.json: 它會開啟一個包含場景和滑動條的本地頁面,並在 recipe(或產品的style.json)被編輯時即時更新。 它會輸出一行包含url的 JSON,並持續提供服務。 - 回報 輸出路徑(
results[].output)。--copy-to <dir>也會將其複製到使用者的專案中。 - 學習:當使用者修正或讚揚某些內容時,在產品的
guidelines.md中附加一行包含日期說明的記錄(如果是預設外觀,也更新style.json預設值)。下次使用時重新閱讀。
將 scenarios 和 recipes 保存在使用者的專案中(例如 docs/shots/),以便在使用者介面變更後可以重新執行。
Scenario(捕捉網頁應用程式)
以下 JSON 範例中的註解僅供說明;實際檔案必須是純 JSON。
{
"name": "ellie-today-drag", // 捕捉名稱,需唯一;請加上產品名稱作為前綴
"url": "http://localhost:8081", // 或檔案路徑
"device": "iphone", // iphone | iphone-max | ipad | desktop | laptop
"safeArea": true, // Expo/RN web:Chrome 會回報 iPhone 的安全區域 inset,應用程式會像在裝置上一樣佈局
// ("pad" = 強制為忽略 inset 的應用程式添加內邊距)
"css": "[class*='navigationMenuRoot'] { display: none }", // 隱藏僅在網頁上出現的 chrome 元素(Expo Router 的標籤頁在網頁上會顯示為頂部選單)
"waitFor": "today-list", // 在開始前等待此元素出現
"track": { "row": "text=Plan a birthday" }, // 記錄額外具名元素的框
"steps": [
{ "shot": "main" }, // 全解析度靜態照(用於截圖)
{ "wait": 0.6 },
{ "tap": "add-button" }, // 點擊/輕按一個目標(會先移動到該處)
{ "type": "Buy milk", "into": "title-input" },
{ "press": "Enter" },
{ "drag": "task-birthday", "to": "slot-11am", "duration": 1.4 },
{ "scroll": 400, "duration": 0.8 },
{ "move": [200, 300], "duration": 0.6 },
{ "goto": "/settings" },
{ "waitFor": "settings-title" },
{ "shot": "after" }
]
}
目標:一個純名稱會匹配 data-shot="..." 或 data-testid="..."(React Native 的 testID 在網頁上會變成 data-testid,所以請在您想要指向的元素上添加 testID),或是任何 Playwright 選擇器(text=Save、role=button[name="Save"]、#id、.class),或 [x, y] 形式的 CSS 像素座標。
所有具有 data-shot/data-testid 的元素,連同 track 條目,都會記錄其框體。
時序:預設情況下("timing": "frame")頁面時鐘會被暫停,並每次精確前進一幀(60 fps),每幀都會產生全解析度的截圖,這樣應用程式的動畫在任何解析度下都能保持流暢;捕捉所需的時間會比 scenario 的時間長幾倍。僅當應用程式在受控時鐘下出現異常時(步驟可能超時),才使用 "timing": "real"。agentshot capture 會回報點擊時間(clicks)以規劃 cuts/zoom,以及主控台錯誤/警告(console)。開發者疊加層(Expo LogBox toast、Next.js 指示器)會被隱藏;設定 "devOverlays": true 則會保留它們。
偏好使用一個連續的 cuts 區段,而不是多次硬切換:區段之間的跳躍看起來會很不流暢。
在沒有 testID 的應用程式中尋找目標:使用 Playwright 開啟頁面並列出按鈕/輸入框(role、aria-label、text),然後使用 text=...、role=button[name=/^My daughter/] 或 [aria-label='Your prayer'],並通過 track 為您想要進行抬起/放大鏡操作的框體命名。
在具有黏性頁尾的欄位中輸入文字仍然有效(該欄位會獲得焦點)。
Expo:首先啟動網頁建置(npx expo start --web,通常為 http://localhost:8081)。僅限原生的模組可能無法在網頁上運作;如果某個畫面無法顯示,請向使用者索取 iPhone 截圖/錄影並使用 import。
桌面應用程式(包含 "window" 的 scenario)
agentshot windows 會列出視窗(標題、程序、尺寸)。視窗會根據標題進行匹配,然後根據程序名稱,如果視窗被最小化則會還原並將其置於前景。座標是視窗像素:請先查看靜態照(agentshot snap --window "X" --name x-probe,閱讀 PNG)並為您在 track 中使用的框體命名。
{
"name": "notes-tour",
"window": "Notes", // 標題的一部分或程序名稱
"track": { "nav-recent": [20, 200, 190, 40], "nav-search": [20, 96, 190, 40], "content": [232, 40, 1030, 650], "profile": [16, 718, 150, 62] },
"cursor": [1000, 330], // 指標的起始位置
"steps": [
{ "shot": "home" }, // 靜態照 = 此時記錄的幀
{ "wait": 1 },
{ "click": "nav-recent", "duration": 0.9 }, // 滑動到那裡(緩動曲線,輕微弧線),立即點擊
{ "waitStill": 0.6, "region": "content" }, // 等待畫面改變,然後等待靜止
{ "shot": "recent" },
{ "wheel": 4, "at": [760, 460] }, // 向下滾動 4 格(負數 = 向上)
{ "click": "nav-search" }, { "press": "ctrl+a" },
{ "type": "Weekly plan", "cps": 12 }, // 任何文字,包括非拉丁字母
{ "press": "Enter" }, // 按鍵:enter esc tab space backspace delete arrows home end f1..f12, ctrl/alt/shift/win+x
{ "drag": [100, 300], "to": [400, 300], "duration": 1.2 },
{ "click": [640, 400], "button": "right" }, { "click": [640, 400], "double": true },
{ "note": "beat 2" } // 時間軸中的標記
]
}
-
結果包含
timeline(每個步驟在影片秒數中的開始/結束時間,at= 點擊時刻)和shots(從影片中裁切的靜態照)。Recipes 使用track名稱作為目標(例如對"profile"套用"blur"等)。 -
waitStill首先等待(最多changeTimeout,3 秒)直到區域與之前的狀態不同(change,平均像素差異,預設為 6;設定"change": false則僅等待其靜止),然後再等待給定的秒數內沒有任何變動(threshold0.6)。請使用不包含動畫部分(如播放器、動態背景)的region。 -
到達後立即點擊:游標停留在控制項上約 0.5 秒會導致 Windows 工具提示在影片中閃現。
-
保留舊文字的欄位:在
type之前按press ctrl+a。 -
驅動程式會在錄製之前啟動(需要幾秒鐘)並移動真實的游標:在此期間請勿使用機器。桌面捕捉是 1x,因此放大鏡看起來會模糊;偏好使用
lift。 -
在錄製的任何時間點獲取靜態照:
agentshot snap <capture> --at 12.4 --shot name。 -
微小的變更(例如彈出視窗關閉)可能無法達到整個視窗的
change閾值:請在其周圍指定region。 -
快捷鍵:
mod在 Windows 上是 Ctrl,在 macOS 上是 Cmd("press": "mod+a"),因此一個 scenario 可以在兩個平台上執行。
手動錄製(使用者執行操作;游標會被記錄並由渲染器繪製):
agentshot record --name app-filter --window "Figma" --duration 12 # 錄製 12 秒,然後停止
agentshot record start --name app-filter --window "Figma" # 或開始...
agentshot record stop # ...然後稍後停止
macOS
與 Windows 上相同的指令和 scenario;錄製器/mac.swift 會在首次使用時編譯(需要 Xcode Command Line Tools 和 macOS 14+)。首先執行 agentshot doctor:執行代理程式的應用程式(Terminal、iTerm、Claude、VS Code)需要在「系統設定」>「隱私權與安全性」中啟用螢幕錄製和輔助使用權限(agentshot doctor --request 會開啟提示;授予權限後重新啟動該應用程式)。沒有螢幕錄製權限,視窗標題將僅顯示應用程式名稱且錄製會失敗;沒有輔助使用權限,驅動程式無法點擊或打字。
- 座標(
track、步驟、recipe 目標)是點;靜態照和影片會以顯示器的像素比例呈現(Retina 為 2,inspect會顯示scale),因此抬起和縮放效果會保持清晰。 - ScreenCaptureKit 會記錄視窗本身:它可能被部分遮蓋,但不能被最小化。
node scripts/selftest-mac.mjs會在 TextEdit(以及已啟動的模擬器,如果有的話)上檢查所有功能,並印出失敗的項目。同步檢查:agentshot record ... --show-cursor會將真實游標嵌入影片中;將其與記錄的指標進行比較(agentshot frames對比inspect),就像檢查任何錄影一樣。
iOS 模擬器(macOS)
使用原生應用程式代替其網頁建置版本:獲得真實字體、原生模組和 iOS 動畫。啟動一個模擬器(open -a Simulator),在其中執行應用程式(npx expo run:ios 或開發建置),然後:
agentshot sim devices # 已啟動的模擬器
agentshot sim snap --name app-home --clean-status-bar # 無損靜態照,顯示 9:41 / 滿格電量
agentshot sim record start --name app-flow # 由他人操作...
agentshot sim record stop
一個 scenario 可以使用 idb 來驅動它(brew install facebook/fb/idb-companion,pipx install fb-idb);座標是裝置點(閱讀 sim snap 並將其像素除以 scale):
{
"name": "app-onboarding",
"simulator": "booted", // 或 UDID 或裝置名稱的一部分
"statusBar": "clean", // 捕捉期間顯示 9:41,捕捉後清除
"appearance": "light", // 或 "dark"
"openUrl": "exp://127.0.0.1:8081/--/today", // 在錄製前深層連結(或 "launch": "<bundle id>")
"track": { "add": [330, 760, 48, 48], "title": [24, 120, 340, 44] },
"steps": [
{ "shot": "today" },
{ "tap": "add" },
{ "waitStill": 0.5 },
{ "type": "Buy milk" }, // 輸入到當前聚焦的欄位
{ "press": "enter" }, // enter esc backspace tab space arrows home lock
{ "swipe": [200, 600], "to": [200, 250], "duration": 0.4 },
{ "openUrl": "exp://127.0.0.1:8081/--/settings" },
{ "waitStill": 0.6 },
{ "shot": "settings" }
]
}
靜態照是無損的模擬器截圖;輕按和滑動會變成觸控指標和點擊,因此 recipes 會使用 "pointer": "touch" 和 "device": "iphone-black",就像瀏覽器捕捉一樣。如果沒有 idb,則僅能使用 wait/waitStill/agentshot/openUrl/launch 等步驟。
Recipe(樣式設定和渲染)
{
"name": "today-drag", // 資料庫中的資產名稱
"product": "ellie", // 資料庫資料夾;將套用 style.json 預設值
"capture": "ellie-today-drag",
"shot": "main", // 設定為產出 PNG 靜態照;省略則產出 MP4 影片
"size": "16:9", // 16:9 16:10 4:3 3:2 1:1 4:5 9:16,或寬度/高度
"background": "lavender", // lavender peach sage sky rose mint neutral midnight ink white,
// 任何 CSS 顏色/漸層,或 public/ 下的圖片(backgrounds/x.jpg)
"backgroundBlur": 0.02, // 對於照片背景,佔短邊的比例
"device": "iphone-black", // iphone-black iphone-natural iphone-white browser window none
"url": "app.ellie.so/today", // 瀏覽器列文字;"title": 用於 "window" 的視窗標題
"padding": 0.08, "tilt": 12, // 裝置邊距;3D 傾斜角度(度)
"position": [0.69, 0.5], // 裝置在畫布上的中心位置,為旁邊的標題留出空間
"accent": "#6d5ce8", // 步驟、輪廓、標籤、點擊波紋的顏色
"font": "Gilda Display", "labelFont": "Inter", // 標題 / 抬起標籤字體:Inter Manrope Poppins Nunito Fraunces Lora
// "Playfair Display" "DM Serif Display" "Gilda Display" "Cormorant Garamond" Caveat
"lift": { "target": "task-row", "label": "拖曳到您的日期上", "start": 3.9, "pad": 10, "dim": 0.1 },
"loupe": { "target": "label-chip", "anchor": [0.2, 0.5], "zoom": 2.3, "size": 0.12, "offset": [-0.15, 0.12] },
"annotations": [
{ "t": "..." }
]
}
(由於原始內容被截斷,此為翻譯後的完整內容)