Communitygithub.com

thread-of-ariadne/agentshot

Windows 및 macOS에서 제품 스크린샷과 데모 비디오를 만듭니다. 웹 앱/Expo 웹 앱/데스크톱 윈도우/iOS 시뮬레이터/iPhone 파일을 캡처하고, 스타일을 지정한(배경, iPhone/브라우저/윈도우 프레임, 리프트, 루페, 화살표, 단계, 블러, 확대/축소, 커서, 컷) 후 PNG 또는 MP4로 렌더링하여 버전 관리된 라이브러리에 저장합니다. 사용자가 스크린샷, 목업, 도움말 센터 이미지, 변경 로그 사진, 소셜 게시물(X/Instagram), 데모/B-롤 비디오 또는 앱의 화면 녹화를 요청할 때 사용하세요.

agentshot란 무엇인가요?

agentshot은 개발자와 AI 에이전트가 제품 스크린샷과 데모 비디오를 제작할 수 있도록 설계된 전문 도구입니다. 웹 앱(Expo 포함), iOS 시뮬레이터, 데스크톱 애플리케이션 등 다양한 소스에서 캡처를 지원하며, 사용자 지정 스타일(배경, 디바이스 프레임, 확대/축소, 텍스트 라벨, 화살표 등)을 적용하고 고해상도 PNG 이미지나 MP4 비디오로 렌더링합니다. 모든 결과물은 버전 관리 라이브러리에 저장되어 추후 재사용 및 변경 추적이 가능합니다. 이 도구는 Capture(캡처), Reciple(레시피, 스타일 지정 및 렌더링), Render(렌더링)의 3단계 워크플로우를 기반으로 하며, 각 단계는 JSON 형식의 구성 파일로 제어됩니다. 특히 사용자 피드백을 제품별 guidelines.md와 style.json에 자동으로 반영하여 학습하는 기능을 갖추고 있어, 반복적인 작업에서도 일관된 결과물을 얻을 수 있습니다.

지원 대상✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/thread-of-ariadne/agentshot/tree/main/skill/agentshot

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

agentshot: 스크린샷과 데모 비디오

도구는 /path/to/agentshot에 있습니다. 다음과 같이 실행합니다:

node /path/to/agentshot/bin/agentshot.mjs <명령어> ...

아래에서 agentshot은 해당 명령어를 의미합니다. 모든 명령어는 JSON 한 줄("ok": true|false)을 출력합니다. 긴 렌더링 작업은 stderr에 진행 상황을 출력합니다. 명령어 목록은 agentshot help를 실행하세요.

워크플로우

  1. 먼저 제품의 규칙을 읽습니다: agentshot style <product>는 style.json(기본 스타일)과 guidelines.md(사용자가 선호하는 사항)를 출력합니다. 이를 따르세요. 제품이 새 것이라면 agentshot style <product> --init을 실행합니다.
  2. 캡처 (다음 중 하나를 선택):
    • 웹 앱 또는 Expo 앱 → "url"이 포함된 시나리오 JSON을 작성하고 agentshot capture scenario.json을 실행합니다.
    • Mac에서 iOS 앱 → "simulator"가 포함된 시나리오(iOS 시뮬레이터의 실제 네이티브 앱, "iOS 시뮬레이터" 참조); 빠른 정지 이미지 → agentshot sim snap --name <capture> --clean-status-bar.
    • 데스크톱 프로그램 → "window"가 포함된 시나리오: 녹화 중에 실제 마우스/키보드를 사용하여 조작합니다("데스크톱 앱" 참조). 정지 이미지만 필요하면 → agentshot snap --window "<title>" --name <capture>. 사용자가 직접 조작하는 경우 → agentshot record start/stop.
    • 사용자가 이미 파일을 가지고 있는 경우(iPhone 스크린샷/화면 녹화) → agentshot import <file> --name <capture>.
  3. 검사: agentshot inspect <capture>는 쇼트, 요소 박스(화면 포인트), 클릭, 지속 시간 및 비디오의 경우 moves(포인터 이동), changes(페이지 전환: 큰 시각적 점프), quiet(움직임 없음: 컷 또는 속도 향상) 및 시나리오 timeline을 나열합니다. 이 숫자를 바탕으로 컷과 확대/축소를 계획한 다음, agentshot frames <capture> --from a --to b(타임스탬프가 있는 연속 이미지 시트; 출력된 PNG를 읽으세요)로 확인합니다. 스타일을 지정하기 전에 쇼트 PNG를 읽기 도구로 살펴보세요.
  4. 레시피 JSON을 작성하고 agentshot render recipe.json --note "<변경 내용>"을 실행합니다.
  5. 직접 결과를 확인합니다: PNG를 읽습니다. MP4의 경우 agentshot frames <product>/<asset>(전체 비디오) 및 agentshot frames <product>/<asset> --from 3 --to 4 --every 0.033 --crop x,y,w,h(컷 또는 클릭 주변을 프레임별로 확인)를 실행합니다. 수정하고 다시 렌더링합니다(새 버전이 추가됨). 사용자가 직접 레시피를 스크러빙하거나 조정하려는 경우, 백그라운드에서 agentshot preview recipe.json을 실행합니다: 로컬 페이지에 장면과 스크러버를 열고 레시피(또는 제품의 style.json)가 편집될 때 실시간으로 업데이트됩니다. url이 포함된 JSON 한 줄을 출력하고 계속 서빙합니다.
  6. 출력 경로를 보고합니다(results[].output). --copy-to <dir>는 이를 사용자 프로젝트에 복사합니다.
  7. 학습: 사용자가 수정하거나 칭찬할 때, 제품의 guidelines.md에 날짜가 포함된 줄을 추가합니다(기본 스타일인 경우 style.json 기본값도 업데이트). 다음에 읽으세요.

시나리오와 레시피는 사용자 프로젝트(예: docs/shots/)에 보관하여 UI 변경 후 다시 실행할 수 있도록 하세요.

시나리오 (웹 앱 캡처)

아래 JSON 예제의 주석은 설명일 뿐입니다. 실제 파일은 일반 JSON이어야 합니다.

{
  "name": "ellie-today-drag",          // 캡처 이름, 고유해야 함; 제품 이름으로 접두사 사용
  "url": "http://localhost:8081",       // 또는 파일 경로
  "device": "iphone",                   // iphone | iphone-max | ipad | desktop | laptop
  "safeArea": true,                     // Expo/RN 웹: Chrome이 iPhone safe-area 여백을 보고하면 앱이
                                        // 기기에서처럼 레이아웃됨 ("pad" = 여백을 무시하는 앱에 패딩 강제 적용)
  "css": "[class*='navigationMenuRoot'] { display: none }",  // 웹 전용 크롬 숨기기(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) 또는 CSS px 단위의 [x, y]와 일치합니다. data-shot/data-testid가 있는 모든 요소는 해당 박스와 함께 track 항목에 기록됩니다.

타이밍: 기본적으로("timing": "frame") 페이지 시계가 일시 중지되고 한 번에 정확히 한 프레임씩 진행됩니다(60fps). 각 프레임에 대해 전체 해상도 스크린샷이 제공되므로 앱 애니메이션이 모든 해상도에서 부드럽게 유지됩니다. 캡처는 시나리오보다 몇 배 더 오래 걸립니다. 제어된 클록에서 앱이 중단되는 경우에만 "timing": "real"을 사용하세요(단계가 시간 초과됨). agentshot capture는 클릭 시간(clicks)을 보고하여 cuts/zoom을 계획하고 콘솔 오류/경고(console)도 보고합니다. 개발자 오버레이(Expo LogBox 토스트, Next.js 표시기)는 숨겨집니다. "devOverlays": true로 유지할 수 있습니다. 여러 개의 하드 컷보다 하나의 연속된 cuts 세그먼트를 선호하세요. 세그먼트 간 점프는 어색해 보입니다.

testID가 없는 앱에서 대상 찾기: Playwright로 페이지를 열고 버튼/입력 필드를 나열한 다음(role, aria-label, 텍스트) text=..., role=button[name=/^My daughter/] 또는 [aria-label='Your prayer']를 사용하고, track을 통해 리프트/루페하려는 박스 이름을 지정하세요. 고정 하단 영역이 있는 필드에 입력해도 작동합니다(필드가 포커스를 받음).

Expo: 먼저 웹 빌드를 시작하세요(npx expo start --web, 일반적으로 http://localhost:8081). 네이티브 전용 모듈은 웹에서 작동하지 않을 수 있습니다. 화면이 깨지면 사용자에게 iPhone 스크린샷/녹화를 요청하고 import하세요.

데스크톱 앱 ("window"가 있는 시나리오)

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 (비디오에서 잘라낸 정지 이미지)이 있습니다. 레시피는 track 이름을 대상으로 사용합니다("profile"에 대한 "blur" 등).

  • waitStill은 먼저(최대 changeTimeout, 3초) 영역이 이전과 달라질 때까지 기다린 다음(change, 평균 픽셀 차이, 기본값 6; "change": false로 설정하면 안정될 때까지만 기다림), 주어진 초 동안 아무것도 변경되지 않을 때까지 기다립니다(threshold 0.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"). 따라서 하나의 시나리오가 두 OS에서 실행됩니다.

수동 녹화(사용자가 직접 조작하고 커서는 렌더러에서 기록 및 그림):

agentshot record --name app-filter --window "Figma" --duration 12   # 12초 녹화 후 정지
agentshot record start --name app-filter --window "Figma"           # 또는 start...
agentshot record stop                                               # ...하고 나중에 정지

macOS

Windows와 동일한 명령어와 시나리오가 적용됩니다. recorder/mac.swift는 첫 번째 사용 시 컴파일됩니다(Xcode 명령줄 도구와 macOS 14+ 필요). 먼저 agentshot doctor를 실행하세요. 에이전트를 실행하는 앱(터미널, iTerm, Claude, VS Code)은 시스템 설정 > 개인정보 보호 및 보안에서 화면 녹화 및 손쉬운 사용 권한이 필요합니다 (agentshot doctor --request가 프롬프트를 엽니다. 권한 부여 후 해당 앱을 다시 시작하세요). 화면 녹화 권한이 없으면 창 제목이 앱 이름으로만 표시되고 녹화가 실패합니다. 손쉬운 사용 권한이 없으면 드라이버가 클릭하거나 입력할 수 없습니다.

  • 좌표(track, 단계, 레시피 대상)는 포인트입니다. 정지 이미지와 비디오는 디스플레이의 픽셀 스케일로 기록됩니다(Retina에서 2, inspect가 scale을 표시). 따라서 리프트와 확대/축소가 선명하게 유지됩니다.
  • ScreenCaptureKit은 창 자체를 기록합니다. 부분적으로 가려질 수 있지만 최소화되면 안 됩니다.
  • node scripts/selftest-mac.mjs는 TextEdit(시뮬레이터가 부팅된 경우 시뮬레이터 포함)에서 모든 것을 확인하고 실패한 항목을 출력합니다. 동기화 확인: agentshot record ... --show-cursor는 실제 커서를 비디오에 기록합니다. 이를 기록된 포인터(agentshot frames vs 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

시나리오는 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": "<번들 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" }
  ]
}

정지 이미지는 무손실 시뮬레이터 스크린샷입니다. 탭과 스와이프는 터치 포인터와 클릭이 되므로, 레시피는 브라우저 캡처와 마찬가지로 "pointer": "touch"와 "device": "iphone-black"을 사용합니다. idb가 없으면 wait/waitStill/agentshot/openUrl/launch 단계만 작동합니다.

레시피 (스타일 지정 및 렌더링)

{
  "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": "Drag it onto your day", "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": [
    { "type": "arrow", "from": [517, 346], "to": [554, 484] },
    { "type": "step", "at": [0.6, 0.12], "label": "1", "content": "Tap +" },
    { "type": "cut", "at": 4.3 },
    { "type": "blur", "target": "profile", "radius": 0.04 },
    { "type": "pointer", "visible": true, "color": "#ff4500", "size": 18 },
    { "type": "zoom", "start": 0, "end": 4.3, "scale": 1.1, "anchor": [0.5, 0.5] },
    { "type": "speed", "range": [4.3, 7.5], "rate": 1.5 },
    { "type": "title", "text": "Drag tasks", "position": [0.08, 0.08], "color": "#1a1a2e", "size": 24 },
    { "type": "subtitle", "text": "Reordering made easy" }
  ]
}

agentshot fields recipe.json은 알려진 모든 필드와 설명을 출력합니다.

렌더러 동작

  • 장면은 1~2초의 기본 opening(로고/제품 이름 표시, "opening": false로 비활성화)과 buffer로 구성됩니다. 컷 at은 이 순서를 유지합니다.
  • 컷("type": "cut")이 없으면 전체 캡처가 하나의 세그먼트로 렌더링됩니다.
  • 뷰: 기본적으로 1.0 = 전체 캔버스에 맞춤. "view": "fill"은 캡처 콘텐츠가 비율을 유지하며 프레임을 채우도록 확대/축소합니다. "view": [0.1, 0.1, 0.8, 0.8]은 재사용 가능한 자르기를 위해 캔버스의 직사각형 영역을 정의합니다.
  • step 및 arrow가 "animate": true이면 나타나고 페이드인/아웃되며, "frame": 10 동안 유지됩니다.
  • 블러는 대상 상자를 흐리게 합니다. 포인터 애니메이션은 포인터가 이미 그 위에 있지 않는 한 블러 뒤에 숨겨집니다(블러된 영역을 가리키는 화살표가 보이도록).
  • 루페는 대상의 확대된 원형 뷰를 보여주며 커서 바로 다음에 움직입니다.
  • 리프트는 대상 위에 떠 있는 라벨이 있는 확대된 패널입니다. start가 없으면 컷 바로 후입니다.
  • 속도는 rate 배속으로 재생됩니다.
  • 첫 번째 컷 전의 오프닝은 "opening": false로 비활성화하거나 "opening": { "text": "...", "position": [0.5, 0.5] } 으로 사용자 정의할 수 있습니다.
  • "view": [x, y, w, h]는 캔버스 좌표에서의 뷰포트입니다. 콘텐츠가 이 직사각형을 채우도록 확대/축소됩니다. "view": "fill"은 콘텐츠가 닿는 첫 번째 가장자리로 확대됩니다.
  • 캡처의 속도 조정(speed), 컷(cut), 타이틀(title)은 현재 세그먼트에만 영향을 미칩니다.
  • 자르기: "crop": { "x": 0.1, "y": 0.08, "w": 0.8, "h": 0.7 }은 장면이 렌더링되기 전에 적용됩니다(확대/축소 전). "padding": 0.02는 콘텐츠 주변에 작은 여백을 추가합니다.
  • 서체는 무료 Google Fonts 목록에서 선택합니다. 오프닝 텍스트의 마지막 줄은 작게 표시됩니다.
  • 스크롤은 target에 대해 예를 들어 0.5초의 페이드 전환을 추가합니다. 하나의 영역에서 스크롤하는 여러 장면(scrolls에 나열)은 같은 대상으로 간주되어 하나의 페이드 전환만 생성됩니다.

컬러 배경

lavender  peach   sage   sky    rose    mint   neutral  midnight  ink   white
#ceb5f3  #ffceae #b3e0c6 #b2d6f0 #f3b5c6 #a3e0d0 #e8e4e0  #1e1e2a  #2a2a3a #ffffff

배경의 예는 https://agentshot.site/backgrounds에서 확인할 수 있습니다.

자르기 마커 (crops)

레시피는 capture로부터 crops 배열을 참조할 수 있습니다: 각 자르기는 "name"을 가지며, 레시피의 키 경로에서 "capture": "base-capture"``, "crop": "crop-name"으로 사용됩니다.

{
  "captures": [
    { "name": "base", "url": "http://app", "device": "desktop", ... },
  ]
}

이는 캡처 정의를 재사용하고 자르기별로 다른 스타일을 적용할 수 있게 합니다.

스타일 (style.json)

agentshot style <product>(또는 --init으로 새 제품 생성)의 출력입니다.

{
  "background": "white",
  "device": "browser",
  "accent": "#000000",
  "font": "Inter",
  "shot": null,
  "size": "16:9",
  "padding": 0.04,
  "tilt": 8
}

레시피는 style.json의 키를 재정의합니다. 새 기본값이 마음에 들면 agentshot style <product> --set <key> <value>.

내보내기

agentshot export <product> --dir path/to/project --formats png,mp4 --copy-to docs/shots

agentshot list <product>는 모든 에셋과 버전을 나열합니다. agentshot rename <product>/<asset> <new-name>.

렌더링 문제 해결

  • 비디오가 더듬거리거나 품질이 낮음: 더 높은 fps(기본 30, 60으로 시도)를 설정하거나 "quality": "high"를 설정하세요.
  • 컬러가 일치하지 않음: HDR이 꺼져 있는지 확인하세요. macOS에서 '하이 다이나믹 레인지' 설정을 조정하세요.

기여

보고된 문제와 기능 요청은 GitHub 저장소를 참조하세요.

라이선스

MIT

관련 스킬