ndemo은(는) 무엇을 하나요?
웹 애플리케이션의 나레이션이 포함된 화면 녹화 데모 비디오를 제작합니다.
설정
처음 사용 시, 명령어를 실행하기 전에 반드시 도구 키트를 빌드해야 합니다.
${CLAUDE_SKILL_DIR}/dist/cli.js 파일이 존재하는지 확인하십시오. 없으면 다음을 실행하십시오:
cd ${CLAUDE_SKILL_DIR} && npm install && npm run build
그런 다음 필요에 따라 Playwright 브라우저를 설치하십시오:
cd ${CLAUDE_SKILL_DIR} && npx playwright install chromium
설치를 확인하십시오:
${CLAUDE_SKILL_DIR}/ndemo doctor
명령어
모든 명령어는 ${CLAUDE_SKILL_DIR}/ndemo를 통해 실행됩니다:
| 명령어 | 설명 |
|---|---|
${CLAUDE_SKILL_DIR}/ndemo open <playbook> | 브라우저 데몬 실행, 앱으로 이동 |
${CLAUDE_SKILL_DIR}/ndemo close | 브라우저 데몬 종료 |
${CLAUDE_SKILL_DIR}/ndemo reset | 앱 URL로 다시 이동 (초기 상태) |
${CLAUDE_SKILL_DIR}/ndemo page-state | 현재 페이지 접근성 트리 출력 |
${CLAUDE_SKILL_DIR}/ndemo page-state --screenshot | 동일 + .ndemo/screenshot.png에 스크린샷 저장 |
${CLAUDE_SKILL_DIR}/ndemo play <playbook> | 모든 세그먼트 재생 |
${CLAUDE_SKILL_DIR}/ndemo play <playbook> --segment <id> | 하나의 세그먼트 재생 (먼저 되감기) |
${CLAUDE_SKILL_DIR}/ndemo play <playbook> --from <id> | 해당 세그먼트부터 끝까지 재생 |
${CLAUDE_SKILL_DIR}/ndemo play <playbook> --to <id> | 해당 세그먼트 이후 중지 |
${CLAUDE_SKILL_DIR}/ndemo play <playbook> --audio | TTS 나레이션 오디오와 함께 재생 |
${CLAUDE_SKILL_DIR}/ndemo render <playbook> | 전체 파이프라인: TTS → 재생 → 병합 → mp4 |
${CLAUDE_SKILL_DIR}/ndemo render <playbook> --output <path> | 특정 출력 파일로 렌더링 |
${CLAUDE_SKILL_DIR}/ndemo doctor | 의존성 확인 |
워크플로우
1단계 — 플레이북 생성
각 플레이북은 사용자 프로젝트의 demo/ 디렉토리 아래에 있는 자체 디렉토리에 위치합니다. 디렉토리 이름은 플레이북 이름과 일치합니다.
demo/
my-feature/
my-feature.yaml ← 플레이북
fixtures/ ← 설정 중 복원할 파일
audio/ ← 생성된 TTS 파일 (자동)
video-raw/ ← 원본 녹화 (자동)
demo.mp4 ← 최종 출력 (자동)
플레이북을 작성하기 전에, 데모가 안정적이고 반복 가능하게 작동하기 위해 앱이 어떤 상태여야 하는지 생각해보십시오:
- 사용자가 로그인해야 합니까? → 조건부 로그인 단계 추가
- 데모가 수정하는 파일/데이터를 복원해야 합니까? → 원본을 플레이북의
fixtures/디렉토리에 복사하여 설정에서 복원할 수 있도록 함 - 데모가 특정 콘텐츠가 존재하는 것에 의존합니까? → fixtures에서 생성하거나 설정 셸 명령어를 통해 생성
데모 중에 수정될 모든 파일을 플레이북 디렉토리의 fixtures/ 하위 디렉토리에 복사하십시오. 설정 단계에서 각 실행 전에 파일을 다시 복사하여 데모가 항상 깨끗한 상태에서 시작되도록 합니다.
디렉토리와 YAML 파일을 생성하십시오. 전체 플레이북 스키마는 다음과 같은 최상위 섹션을 지원합니다:
# demo/edit-page/edit-page.yaml
app:
url: http://localhost:8080/wiki
viewport: # 선택 사항, 기본값 1920x1080
width: 1920
height: 1080
scale: 2 # 장치 배율 (기본값 2)
zoom: 1.25 # CSS 확대/축소 수준 (기본값 1.25)
colorScheme: light # "light" 또는 "dark" (기본값 "light")
setup:
# 데모 중 수정된 파일 복원
- run: cp demo/edit-page/fixtures/page.txt data/pages/page.txt
# 이전 실행의 아티팩트 정리
- run: rm -f data/cache/*.tmp
# 필요한 경우 로그인 (조건부 — 이미 로그인된 경우 건너뜀)
- type: click
target: { role: link, name: "Login" }
if:
hidden: ".user-info"
- type: type
target: { role: textbox, name: "Username" }
text: admin
if:
visible: ".login-form"
- type: type
target: { role: textbox, name: "Password" }
text: password
if:
visible: ".login-form"
- type: click
target: { role: button, name: "Sign in" }
if:
visible: ".login-form"
done:
visible: ".user-info"
titleCard: # 선택 사항 제목 카드 (첫 번째 프레임으로 표시)
title: "Editing a Wiki Page" # 눈에 띄게 표시
subtitle: "A quick tour of the editor" # 선택 사항 부제목
duration: 3000 # 밀리초 단위 유지 시간 (기본값 3000)
tts: # 선택 사항 TTS 설정
provider: openai # "openai" (기본값) 또는 "elevenlabs"
voice: alloy # TTS 음성 이름 (기본값 "alloy")
speed: 1.0 # 음성 속도 배수 (기본값 1.0)
recording: # 선택 사항 녹화 설정
outputDir: "." # 플레이북 기준 출력 디렉토리 (기본값 ".")
fps: 30 # 비디오 프레임 속도 (기본값 30)
segments:
- id: intro
narration: "Welcome to our wiki. Let's edit a page."
intent: "show the wiki start page"
timing: after # "after" (기본값) 또는 "parallel"
actions:
- type: wait
duration: 2000
- id: open-editor
narration: "Click the edit button to open the editor."
intent: "click the edit button"
actions: []
**세그먼트 타이밍(timing)**은 나레이션에 대한 액션 실행 시점을 제어합니다:
after(기본값) — 나레이션이 먼저 재생된 후 액션이 실행됩니다.parallel— 나레이션이 재생되는 동안 액션이 실행됩니다.
먼저 모든 세그먼트를 나레이션(narration)과 의도(intent)와 함께 작성하십시오. 액션(actions)은 빈 배열로 남겨둡니다. 플레이북 경로를 ndemo 명령어에 전달할 때는 절대 경로를 사용하십시오.
2단계 — 브라우저 열기
${CLAUDE_SKILL_DIR}/ndemo open /absolute/path/to/demo/my-demo/my-demo.yaml
3단계 — 각 세그먼트 작성
빈 액션이 있는 각 세그먼트에 대해:
a) 현재 페이지 상태를 읽습니다:
${CLAUDE_SKILL_DIR}/ndemo page-state
b) 접근성 트리 출력을 확인합니다. 세그먼트의 의도(intent)에서 참조하는 요소를 찾습니다. 트리의 요소를 사용하여 플레이북 YAML에 액션을 작성합니다.
대상(target) 작성 방법 — page-state 출력의 정보를 사용하십시오:
page-state에 [button "Settings"]이 표시되면:
target: { role: button, name: "Settings" }
page-state에 [searchbox "Search reports" value=""]이 표시되면:
target: { role: searchbox, name: "Search reports" }
기타 대상 필드 — 요소를 가장 잘 식별하는 것을 사용하십시오:
target: { selector: "#my-element" } # CSS 선택자
target: { testId: "submit-btn" } # data-testid 속성
target: { label: "Email" } # aria-label
target: { placeholder: "Search..." } # placeholder 텍스트
target: { text: "Click me" } # 표시되는 텍스트 내용
하나 이상의 대상 필드가 필요합니다. 여러 필드를 결합하여 일치 범위를 좁힐 수 있습니다.
팁: 웹 앱의 소스 코드는 프로젝트 저장소에서 사용할 수 있습니다. 접근성 트리만으로 충분하지 않은 경우 구성 요소 소스에서 data-testid 속성, 클래스 이름 또는 ID를 찾아보십시오.
완료 조건(done conditions) 작성 방법:
done:
visible: ".settings-panel" # 요소가 나타남
hidden: ".loading-spinner" # 요소가 사라짐
networkIdle: true # 보류 중인 요청 없음
stable: 500 # 500ms 동안 DOM 변경 없음
url: "**/settings" # URL 변경됨
text: # 요소가 텍스트를 포함함
selector: ".results"
has: "Q3 Revenue"
attribute: # 요소가 속성을 가짐
selector: html
name: data-theme
value: dark
timeout: 10000 # 기본 제한 시간 재정의 (ms)
페이지를 변경하는 모든 액션에는 반드시 완료 조건(done condition)이 있어야 합니다. 그렇지 않으면 페이지가 준비되기 전에 다음 액션이 실행될 수 있습니다.
시각적 변경 후에는 wait 액션을 추가하여 시청자가 변경된 내용을 볼 수 있도록 하십시오:
- type: wait
duration: 2000 # 2초
c) 세그먼트를 테스트합니다:
${CLAUDE_SKILL_DIR}/ndemo play /absolute/path/to/demo/my-demo/my-demo.yaml --segment <id>
d) 실패하면 ${CLAUDE_SKILL_DIR}/ndemo page-state를 실행하여 현재 화면에 무엇이 있는지 확인하고, 액션을 조정한 후 다시 시도하십시오.
e) 세그먼트가 작동한 후, 다음 세그먼트를 작성하기 전에 page-state를 다시 읽으십시오 — 페이지가 변경되었습니다.
4단계 — 검토
${CLAUDE_SKILL_DIR}/ndemo play /absolute/path/to/demo/my-demo/my-demo.yaml
브라우저에서 전체 시퀀스를 시청하십시오. 사용자에게 올바른지 물어보십시오.
TTS 나레이션과 함께 검토하려면 (OPENAI_API_KEY 및 ffplay 필요):
${CLAUDE_SKILL_DIR}/ndemo play /absolute/path/to/demo/my-demo/my-demo.yaml --audio
이 명령은 각 세그먼트에 대한 TTS 오디오를 생성하고 (콘텐츠 해시로 캐시됨), 브라우저 액션과 함께 오디오를 재생하며, 액션이 나레이션 길이와 일치하도록 타이밍을 조정합니다. 나레이션 텍스트가 변경되면 오디오가 자동으로 다시 생성되고 이전 파일은 삭제됩니다.
5단계 — 반복
사용자가 변경을 요청할 수 있습니다. 일반적인 패턴:
| 사용자 말 | 수행할 작업 |
|---|---|
| "잘못된 버튼" | page-state 실행, 올바른 요소 찾기, 대상 업데이트 |
| "너무 빠름" / "너무 느림" | 대기 시간 조정, --audio로 다시 재생하여 타이밍 확인 |
| "나레이션을 ...로 변경" | narration 필드 편집 |
| "X를 보여주는 단계 추가" | 새 세그먼트 삽입, 액션 작성 |
| "그 단계 제거" | YAML에서 세그먼트 삭제 |
| "세그먼트 X부터 다시 재생" | ${CLAUDE_SKILL_DIR}/ndemo play --from <id> |
| "처음부터 다시 시작" | ${CLAUDE_SKILL_DIR}/ndemo reset 후 다시 재생 |
각 변경 후, 영향을 받는 세그먼트를 다시 재생하여 확인하십시오.
6단계 — 렌더링
사용자가 승인하면:
${CLAUDE_SKILL_DIR}/ndemo render /absolute/path/to/demo/my-demo/my-demo.yaml
이 명령은 TTS 나레이션이 포함된 최종 mp4 파일을 생성합니다.
설정 단계 참조
설정 단계는 데모가 시작되기 전에 실행됩니다 (open, reset, play, render에서). 셸 명령어 또는 브라우저 액션이 될 수 있습니다.
셸 명령어는 프로젝트 작업 디렉토리(ndemo가 호출된 디렉토리)를 기준으로 실행됩니다. run 명령어의 모든 경로는 프로젝트 루트를 기준으로 해야 합니다.
셸 명령어 — 파일 작업에는 run을 사용하십시오:
setup:
- run: cp demo/my-feature/fixtures/original.txt data/page.txt
- run: rm -f data/cache/*.tmp
- run: ./scripts/reset-db.sh
브라우저 액션 — 세그먼트 액션과 동일한 구문:
setup:
- type: click
target: { role: button, name: "Login" }
- type: type
target: { role: textbox, name: "Username" }
text: admin
조건부 단계 — if를 추가하여 조건이 충족되지 않으면 건너뜁니다:
setup:
# 이미 로그인된 경우에만 로그인
- type: click
target: { role: link, name: "Sign in" }
if:
hidden: ".user-menu" # 사용자 메뉴가 표시되면 건너뜀
# 특정 페이지에서만 실행
- type: click
target: { role: button, name: "Reset" }
if:
url: "**/admin/settings" # 이 페이지가 아니면 건너뜀
조건 필드:
visible: "<selector>"— 선택자가 표시되는 요소와 일치하는 경우에만 단계 실행hidden: "<selector>"— 선택자가 표시되는 요소와 일치하지 않는 경우에만 단계 실행url: "<pattern>"— 현재 URL이 일치하는 경우에만 단계 실행 (**= 모든 경로)
액션 유형 참조
| 유형 | 필수 필드 | 참고 |
|---|---|---|
| click | target | |
| type | target, text | 선택 사항 delay (ms) 키 입력 간 지연 시간 (기본값 80) |
| hover | target | |
| scroll | target | 요소가 보일 때까지 스크롤 |
| wait | duration (ms) | 시청자를 위한 일시 중지 (기본값 1000ms) |
| press | key | 키보드 키, 예: "Enter", "Escape" |
| select | target, option | 드롭다운 선택 |
세그먼트 ID 규칙
- 소문자 영숫자와 하이픈 사용:
open-settings,toggle-dark - 플레이북 내에서 고유해야 함
- 오디오/비디오 파일 이름으로 사용되므로 짧게 유지하십시오.
문제 해결
- 브라우저가 응답하지 않음:
${CLAUDE_SKILL_DIR}/ndemo close를 실행한 후 다시open하십시오. 브라우저 데몬 출력은.ndemo/daemon.log에서 확인하십시오. - 요소를 찾을 수 없음:
${CLAUDE_SKILL_DIR}/ndemo page-state를 실행하여 현재 화면의 접근성 트리를 확인하고 대상(target)을 업데이트하십시오.