Product Demo Video
SaaS 출시 동영상처럼 보이는 제품 데모입니다. 스크린캐스트가 아닙니다.
핵심 아이디어: 화면을 녹화하지 마세요. Playwright로 고해상도 스크린샷과 실제 요소 좌표를 캡처한 후, Remotion에서 해당 자료를 애니메이션화합니다. 이렇게 하면 카메라, 리듬, 자막을 완전히 제어할 수 있으며 — 사용자가 "더 빠르게", "줌 더 크게", "이 단계 빼줘", "10초 버전 만들어줘"라고 말할 때 10초 만에 다시 렌더링할 수 있습니다. 재녹화는 느리고 결과도 더 나쁩니다.
흐름
- 설정 (프로젝트당 한 번) →
node <skill>/scripts/setup.mjs - 스크립트 →
demo.json작성 (references/roteiro.md참조) - 캡처 →
node .demo-video/tools/capture.mjs demo.json capture/(Playwright) - 렌더 →
node .demo-video/tools/render.mjs --capture capture/ --out out/(Remotion) - 전달 →
out/<name>.mp4(1080p) +out/<name>.gif(HTML 포함 가능) - 반복 →
demo.json을 편집하고 변경된 단계만 실행
시간/카메라/자막이 변경되었습니까? 렌더만 다시 하세요(3단계, 약 30초). 앱 흐름이 변경되었습니까? 캡처도 다시 하세요(2단계).
포르투갈어 요청에서 스크립트로
사용자는 자연어로 흐름을 설명합니다("에이전트를 만드는 방법 보여줘"); 이를 선택자로 번역하는 것은 당신의 역할이며, 앱을 보면서 — 절대 추측하지 마세요. #submit을 추측하면 4번째 장면에서 실패하는 전체 캡처를 낭비하게 됩니다.
- 화면을 열고 브라우저 도구로 DOM을 읽으세요.
- 선택자를 수집하세요. 강건성 순서:
[data-testid=...]>#id> 가시 텍스트(text=Novo agente) > CSS 경로. CSS 경로는 레이아웃이 처음 변경될 때 깨지고, 텍스트는 인터페이스가 번역될 때 깨집니다. - 캡처 전에 사용자에게 흐름을 확인하세요 — 스크립트를 보여주고 단계 순서가 맞는지 물어보세요. 사용자는 제품을 알고 있지만, 당신은 모릅니다.
- 앱에 로그인이 필요하면, 사용자에게 먼저
auth.mjs를 실행하라고 요청하세요.
앱을 열 수 없을 때(내부 제품, 접근 권한 없음)는, 선택자나 HTML이 포함된 화면 스크린샷을 요청하세요 — 추측하는 것보다 빠릅니다.
스크립트는 진리의 원천입니다
단일 JSON이 Playwright 와 Remotion을 제어합니다. 무엇이든 캡처하기 전에 스크립트를 작성하고 사용자에게 보여주세요 — 그곳에서 수정하는 것은 저렴하고 나중에 수정하는 것은 비쌉니다. 전체 스키마는 references/roteiro.md에 있습니다.
{
"name": "criar-agente",
"url": "https://app.exemplo.com",
"viewport": { "width": 1600, "height": 900 },
"scenes": [
{ "action": "goto", "value": "/dashboard", "camera": "wide", "caption": "대시보드", "duration": 2 },
{ "action": "click", "target": "[data-testid='new-agent']", "camera": "zoom", "caption": "에이전트 만들기", "duration": 2 },
{ "action": "type", "target": "#agent-name", "value": "재무 분석가", "camera": "focus", "duration": 2.5 },
{ "action": "click", "target": "button[type=submit]", "camera": "zoom", "duration": 1.5 },
{ "action": "wait", "value": 1200, "camera": "wide", "caption": "3번의 클릭으로 완료", "duration": 2.5 }
]
}
설정 (프로젝트에서 처음)
node "$HOME/.claude/skills/product-demo-video/scripts/setup.mjs"
.demo-video/ (Remotion 컴포지션 + .demo-video/tools/의 도구들)을 생성하고, 종속성을 설치하며 Chromium을 다운로드합니다 — 약 300MB. 실행하기 전에 사용자에게 확인하세요; 그 후에는 캡처와 렌더링이 몇 초 안에 완료됩니다. .demo-video/, capture/, .auth/를 .gitignore에 추가할 것을 제안하세요.
결과를 실시간으로 확인하려면, cd .demo-video && npx remotion studio를 실행하면 스크러버가 있는 미리보기가 열립니다 — 타이밍을 확인하기 위해 렌더링하는 것보다 훨씬 좋습니다.
카메라 연출
좋은 데모와 나쁜 데모를 구분하는 것은 효과가 아니라 리듬입니다. 효과가 있는 규칙:
wide로 시작하고 끝내세요. 시청자는 줌 전에 위치를 파악하고 결과를 봐야 합니다. 영화 전체를 줌하면 피곤하고 방향 감각을 잃습니다.- 의도당 한 번의 줌, 클릭당이 아닙니다. 같은 영역에서 연속 클릭 =
zoom의 단일 장면. 클릭할 때마다 줌 인/아웃하면 멀미가 납니다. focus는 타이핑에만 사용하세요. 텍스트 필드는 읽을 수 있어야 하지만, 버튼은 그렇지 않습니다.- 장면당 2~3초. 1.5초 미만이면 아무도 자막을 읽지 못하고, 4초 이상이면 불필요한 시간이 됩니다. 좋은 데모는 15
25초, 58개의 장면입니다. - 자막은 레이블이지, 문장이 아닙니다. "에이전트 만들기", "데이터 연결". 최대 약 4단어, 동사로 시작, 마침표 없음. 모든 장면에 자막이 필요하지는 않습니다.
- 불필요한 시간은 원천에서 잘라내세요. 로딩, 리디렉션, 진입 애니메이션: 비디오에서 정지된 시간을 남기지 말고 장면에서
settle을 사용하세요.
카메라는 장면 간에 연속적입니다(easing으로 보간됨), 따라서 움직임은 이미 부드럽습니다 — 스크립트에서 추가 장면으로 이를 보완하려고 하지 마세요.
텍스트 레이어는 내레이션입니다
오디오는 없습니다(GIF에는 없고, 비디오는 피드에서 음소거로 재생됩니다). 이야기를 전하는 것은 타이포그래피이며, 계층 구조가 있을 때만 작동합니다: 모든 텍스트의 무게가 같으면 시청자는 무엇이 단계이고 무엇이 논점인지 알 수 없습니다.
| 스타일 | 역할 | 사용 시기 |
|---|---|---|
title (장면) | 전체 화면 시작/종료, sub와 함께 | 처음에 1번, 가끔 끝에 1번 |
hero | 전환점 — 크고 중앙에, 그라데이션 위에 | 데모당 최대 1번 |
label | 단계 레이블(기본값), 선택적 sub와 함께 | 대부분의 장면 |
stat | 제품을 정당화하는 숫자: "22초", "3번의 클릭" | 종료 시 1번 |
note | 보조 세부 정보, 눈에 띄지 않게 | 단계에 주의 사항이 필요할 때 |
나머지를 뒷받침하는 두 가지 규칙: 데모당 hero 하나(두 개는 아무것도 아님), 그리고 stat이 닫습니다 — 큰 숫자는 시청자의 머리에 가장 마지막에 남습니다. 임원용 데모의 경우, 아크는 일반적으로 title → labels → 결정적 순간의 hero → 마지막의 stat입니다.
"highlight": true는 장면의 요소를 제외한 전체 화면을 어둡게 만듭니다. 이는 세트에서 가장 강력한 무기이므로 가장 망치기 쉽습니다: 시청자가 반드시 그 요소를 가져가야 할 때 사용하고, 장식용으로 사용하지 마세요. 카메라가 안정된 후에 들어가고, 결과를 숨기지 않기 위해 동작 순간에 저절로 사라집니다.
자격 증명
절대 demo.json에 비밀번호를 넣지 마세요. 선호도 순서대로 두 가지 옵션:
"auth": { "storageState": ".auth/state.json" }— 이미 로그인된 세션,node .demo-video/tools/auth.mjs <url>로 한 번 생성(브라우저를 열고 사용자가 수동으로 로그인)."auth": { "login": { "user": "#email", "pass": "#password", "submit": "button[type=submit]" } }자격 증명은 환경 변수DEMO_USER/DEMO_PASS에 저장.
데모가 실제 데이터를 표시하는 경우, 스크립트에서 "redact": ["selector"]를 사용하여 캡처 전에 민감한 요소를 흐리게 처리하세요 — PNG에서 이미 흐리게 처리되어 나오므로 복구할 수 없습니다.
출력
| 형식 | 용도 | 방법 |
|---|---|---|
demo.mp4 1920×1080 | 랜딩, LinkedIn, YouTube | 기본값 |
demo.gif 960×540 | README, 문서, 이메일, HTML | --formats mp4,gif (기본값) |
demo-square.mp4 1080×1080 | Instagram/피드 | --formats mp4,square |
GIF는 무겁습니다. render.mjs는 이미 Remotion에 내장된 ffmpeg를 통해 palettegen(비디오 전용 팔레트)을 사용합니다 — 아무것도 설치할 필요가 없습니다. 그래도 15초 960px은 약 3.5MB입니다. README의 경우 --gif-width 720 --gif-fps 12를 선호하세요. 그러면 1.5MB 미만으로 줄어듭니다.
HTML에 포함하려면: <img src="demo.gif" width="720" alt="...">. 사용자가 MP4를 허용한다면 <video autoplay loop muted playsinline>은 약 10배 더 가볍습니다.
제품을 건드리지 않고 설치 테스트
assets/exemplo/에는 가짜 앱(app-exemplo.html)과 해당 스크립트가 있으며, 모든 작업(title, shot, click, type, select, hold, redact)을 실행합니다. 이 작업을 먼저 실행하면 "스킬이 고장났다"와 "앱 선택자가 잘못되었다"를 구분할 수 있으며, 이는 첫 번째 실제 데모에서 문제가 발생했을 때 비용이 많이 드는 의문입니다.
문제 발생 시
- 선택자를 찾을 수 없음 →
capture.mjs가 장면에서 실패하고 어느 것인지 알려줍니다. 사용자에게 URL/화면을 요청하고 다른 선택자를 추측하기 전에 브라우저로 검사하세요. - 줌이 흐림 → 스크립트에서
scale을 3으로 늘리거나(스크린샷 3배), 줌을 줄이세요. - 비디오가 자막과 동기화되지 않음 → 장면의
duration이 결정합니다. 거기서 조정하세요. - 컴포지션, 카메라, 커서 및 시각적 사용자 정의 세부 정보:
references/remotion.md를 참조하세요.
