bueno-demo를 사용한 데모 비디오 만들기
bueno-demo는 웹 페이지를 스크립트로 탐색하고 Screen Studio 스타일의 클립으로 렌더링합니다. 두 가지 단계가 있습니다: **캡처(capture)**는 실제 Chromium 창을 구동하여 녹화하고, **렌더(render)**는 카메라, 커서, 타이틀을 추가합니다.
각 머신당 한 번씩 설정하기
npm i -D bueno-demo # 또는 npx bueno-demo로 모든 것을 실행
npx playwright install chromium
brew install ffmpeg # 필수; WebP 포스터를 위해 imagemagick 추가
워크플로우
- 스크립트를 작성합니다. JSON 파일입니다(아래 참조). 클립당 하나의 아이디어, 10~15초로 유지하세요.
- 캡처:
npx bueno-demo capture demos/<이름>.json out/<이름> - 느린 로딩 구간 자르기(선택사항):
npx bueno-demo cut out/<이름> <시작-초> <끝-초> - 렌더:
npx bueno-demo render out/<이름> out/<이름>/<이름> --gif - 사용 전에 확인하세요. 콘택트 시트를 만들어 모든 프레임을 검사합니다:
ffmpeg -i out/<이름>/<이름>.mp4 -vf "fps=1,scale=640:-1,tile=3x4" -frames:v 1 sheet.png버그나 개인 데이터가 카메라에 잡히면 스크립트를 수정하거나 잘라낸 후 다시 렌더링하세요.
스크립트
{
"url": "http://localhost:3000/settings",
"viewport": [1440, 900],
"storage": "auth.json",
"keep": "document.querySelectorAll('[data-user-email]').forEach(e => e.textContent = '[email protected]')",
"steps": [
{ "scroll": "[data-testid=billing]" },
{ "click": "[data-testid=plan-toggle]", "after": 1200 },
{ "type": "[data-testid=team-name]", "text": "Northwind", "clear": true },
{ "hover": "[data-testid=save]", "zoom": true },
{ "click": "[data-testid=save]", "zoom": false },
{ "wait": 800 }
]
}
스텝(Steps) – 각각 선택적으로 after(이후 대기 시간, 밀리초)를 가질 수 있습니다:
click: 요소로 부드럽게 이동한 후 클릭합니다.zoom: false는 카메라 줌을 건너뛰며, 페이지 이동이 발생하는 클릭에 사용합니다.type: 클릭한 후text를 입력합니다(delay는 키당 밀리초, 기본값 55;clear: true는 값을 대체합니다).fill: 클릭한 후 한 번에text를 설정합니다. 타이핑으로 제어할 수 없는 입력(예: 날짜 선택기)에 사용합니다.hover: 요소로 부드럽게 이동합니다.zoom: true는 카메라도 그쪽을 비춥니다.upload: 드롭 영역으로 이동하여file(스크립트 기준 상대 경로)을input에 첨부합니다.press: 키 입력, 예:"Escape".scroll: 요소가 보일 때까지 부드럽게 스크롤합니다.wait: 밀리초 단위로 일시 정지합니다.eval: 페이지에서 JavaScript를 실행합니다(카메라에 보입니다).
옵션:
- 로그인:
storage는 Playwright 저장 상태 파일을 가리킵니다(npx playwright codegen --save-storage=auth.json <url>로 저장). 또는"cookiesFrom": "agent-browser"로 서명된 agent-browser 세션의 쿠키를 빌려올 수 있습니다. 쿠키는 절대 출력되지 않습니다. - 개인정보 보호:
keep은 녹화 전과 녹화 중 250ms마다 실행되는 JavaScript로, 실제 이름과 이메일을 대체 문자열로 바꾸어 재렌더링 시 복구되지 않도록 합니다.hide는 CSS 선택자를 추가하여 숨깁니다(Next.js 및 Vercel의 개발 오버레이는 기본적으로 숨겨짐;"hide": false로 표시 가능). - 카메라 밖:
setup은 녹화 전 한 번 실행되는 JavaScript로, 예를 들어 배너를 닫을 때 사용합니다. - 느낌:
travelMs(커서 이동 시간, 기본값 700),settle(로딩 후 대기 시간, 기본값 1500),tail(끝에서 유지 시간, 기본값 1200),cursorStart([x, y]),reducedMotion: true. - 로딩:
waitUntil(기본값networkidle). 비디오를 스트리밍하거나 폴링하는 페이지는 절대 유휴 상태가 되지 않으므로 캡처가 타임아웃됩니다. 이 경우"load"로 설정하고settle이 나머지를 처리하도록 하세요. - 다른 서버: 캡처 시
--base http://localhost:3001을 사용하면 동일한 경로를 다른 곳에서 녹화합니다.
선택자: 가시 텍스트보다 data-testid 또는 구조(#title, input[name=amount])를 선호하세요. 텍스트가 변경되어도 스크립트가 깨지지 않습니다.
렌더 플래그
--zoom 1.6클릭 시 줌 정도(한 번에 두 가지가 중요할 때는 1.3).--speed 0.910% 느리게 재생;--speed 2.5로 빠른 몽타주.--end 9.8해당 초에서 자르기;--hold 1.2마지막 프레임 고정.--matte '#fdfaf1'페이지를 해당 색상의 둥근 창으로 프레임 처리(기본값은 가장자리까지).--title '이벤트 이동' --kicker '이벤트'시작 타이틀 추가;--end-cap종료 카드 추가.--brand brand.json타이틀 및 카드 모양 설정:ink,paper,accent,displayFont/monoFont({ "family", "file", "weight" }),logo,footer,kicker. 경로는 브랜드 파일 기준 상대 경로입니다.--fit페이지 자체 비율로 렌더링(모바일 뷰포트의 경우 세로 모드).--gif960px, 15fps GIF도 함께 출력.
규칙
- 실제 고객 데이터를 절대 녹화하지 마세요. 테스트 계정을 사용하고 개인정보는
keep훅으로 처리하세요. 공유 전에 콘택트 시트를 확인하세요. - 짧고 단일 목적으로. 클립당 하나의 기능;
cut으로 대기 시간을 잘라내세요. - 비디오는 저장소 외부에 호스팅하세요. 스크립트(및 문서에 필요한 경우 포스터)는 커밋하고, MP4와 GIF는 스토리지 또는 CDN에 넣으세요.