Communitygithub.com

velxio/velxio_docs

실제 Velxio 애플리케이션을 Playwright로 구동하고 Remotion으로 후편집하여 프로모/데모 비디오(및 제품 GIF)를 제작 또는 업데이트합니다. 화면 캡처(커서 표시), 주요 클릭 영역 확대, 자막, 인트로/아웃트로 카드를 포함합니다.

velxio_docs란 무엇인가요?

이 스킬은 Velxio 제품의 프로모션 비디오, 데모 비디오, 제품 애니메이션, UI 변경 후 재렌더링, 또는 특정 흐름의 GIF를 제작하거나 업데이트해야 할 때 사용됩니다. Playwright를 사용해 실제 스테이징 환경의 제품을 처음부터 끝까지(빈 프로젝트 → ESP32 선택 → 220R + LED 추가 → 저항 회전 → 핀 클릭으로 배선 → 스케치 작성 → 실행 → LED 깜빡임) 구동하며, 보이는 커서와 클릭 ripple을 함께 녹화합니다. 녹화된 원본 비디오와 이벤트 데이터를 기반으로 Remotion 프로젝트에서 비트 감지(음악 박자 동기화), 카메라 줌인(각 비트 중심), 자막 캡슐, 인트로/아웃트로 카드, 배경 음악을 포함한 최종 MP4 파일을 렌더링합니다. 특히 여러 트랩(모달 오버레이, 피커 검색 캐시, 핀 오버레이 충돌, 회로 검증기, 커서 위치, 카메라 수학 등)에 대한 우회 방법이 스크립트에 포함되어 있어 안정적인 녹화를 보장합니다. 또한 갤러리 데모 비디오(각 예제별 짧은 비디오)를 제작하는 기본 모드도 지원합니다.

지원 대상✓Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/velxio/velxio_docs/tree/HEAD/skills/velxio-promo-video

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

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

문서

Velxio 프로모 비디오 파이프라인

세 단계로 구성되며, 모든 작업은 이 저장소(velxio_docs; 개발 박스의 /home/dave/velxio_docs)에서 이루어집니다:

  1. 녹화 (Record) — scripts/promo-record.mjs가 스테이징 환경의 실제 제품을 처음부터 끝까지(빈 프로젝트 → ESP32 선택 → 220R + LED 추가 → 저항 회전 → 핀 클릭으로 배선 → 스케치 작성 → 실행 → LED 깜빡임) 구동합니다. 보이는 커서와 클릭 ripple이 삽입됩니다. 각 동작은 {t, x, y, label} 형태로 scripts/promo-events.json에 기록되며, 원본 비디오는 scripts/promo-raw.webm에 저장됩니다.
  2. 비트 그리드 (Beat grid) — scripts/detect-beats.py(librosa)가 사운드트랙을 분석하여 promo/src/beats.json(BPM, 비트, 킥, 스네어)을 생성합니다.
  3. 후편집 (Post) — promo/는 Remotion 프로젝트입니다. prepare.mjs가 녹화본을 복사하고, 로딩 전 모달 부분을 자르고, 컴파일 대기 시간을 제거한 후 src/data.json을 생성합니다. src/Promo.tsx가 카메라 워크(각 비트 중심의 줌인, 각 펀치는 0.34초 이내의 가장 가까운 음악 비트에 SNAPPED됨), 자막 캡슐, SOLID 인트로 카드, velxio.dev 아웃트로, 그리고 페이드 인/아웃이 적용된 음악 트랙을 렌더링합니다.

명령어

cd /home/dave/velxio_docs
VELXIO_SHOTS_EMAIL='[email protected]' VELXIO_SHOTS_PASSWORD='<see memory vstaging-test-user>' \
  node scripts/promo-record.mjs          # 녹화 (~2-4분, 컴파일 시간 포함)
python3 scripts/detect-beats.py promo/public/soundtrack.mp3 --fps 30 \
  --out promo/src/beats.json        # 트랙이 변경될 때만 실행
cd promo && node prepare.mjs
CHROME=$(ls -d $HOME/.cache/ms-playwright/chromium-*/chrome-linux*/chrome | sort | tail -1)
npx remotion render src/index.ts promo out/velxio-demo.mp4 --codec h264 --browser-executable "$CHROME"

GitHub에서 볼 수 있도록 게시된 복사본: media/velxio-demo.mp4 (커밋됨; 덮어쓰기 + 푸시로 동일한 URL 업데이트). promo/out/은 gitignore에 포함됩니다.

검토 절차 (절대 건너뛰지 마세요)

비트 시점에 promo/src/data.json의 ct 필드를 기준으로 프레임을 샘플링하세요. 시간을 추측하지 마십시오. 비트는 테이크마다 이동합니다:

ffmpeg -y -ss <ct> -i out/velxio-demo.mp4 -vframes 1 /tmp/beat.png

확인할 사항: 인트로가 읽을 수 있는지, 각 줌이 대상물을 자르지 않고 보여주는지, 자막이 화면과 일치하는지, 커서가 중요한 부분을 가리지 않는지, 최종 LED가 켜져 있는지.

갤러리 데모 비디오 (기본 모드)

갤러리 예제별 짧은 비디오 하나씩 — 열고, 실행하고, 작동하는 모습을 촬영합니다. 분할 인트로 카드(왼쪽에 로고 + 제목 + 보드, 오른쪽에 전체 회로), 하단 서드, 아웃트로 및 사운드트랙이 포함됩니다.

node scripts/gallery-scan.mjs                     # 406개 예제 인덱스 새로고침
node scripts/gallery-record.mjs [slug ...]        # 1080p 테이크 (완료된 것은 건너뜀)
node scripts/gallery-bbox.mjs [slug ...]          # 회로 위치 측정
node scripts/gallery-render.mjs [slug ...]        # 테이크당 하나의 mp4 생성
  • 선별된 데모 세트는 gallery-record.mjs 상단의 GALLERY에 있습니다; slug는 scripts/gallery-index.json에서 가져옵니다(썸네일 파일명 = slug).
  • 스틸 이미지는 deviceScaleFactor: 2로 캡처되며 회로 bbox로 크롭됩니다: 1080p 프레임 절반을 채울 만큼 선명합니다. 작은 회로를 확대하기 위해 앱을 줌하지 마십시오 — 캔버스 앵커가 중앙을 기준으로 줌하여 회로가 화면 밖으로 벗어납니다; 대신 보기를 재설정하십시오.
  • bbox 패스는 예제마다 새로운 컨텍스트가 필요합니다: 두 번째 클라이언트 측 에디터 로드는 캔버스를 비워 두고 아무것도 측정하지 않습니다.
  • 보드가 없는 예제(Digital / Analog 카테고리)는 컴파일되지 않습니다: Run은 비활성화된 상태로 유지되며 SPICE 엔진이 처음부터 구동합니다.
  • 백엔드-QEMU 보드(STM32, Raspberry Pi)는 "in-browser" 콘솔 라인을 출력하지 않습니다. STM32는 스테이징 환경에서 전혀 실행되지 않습니다(libqemu-arm이 선택적 자산으로 배포되지 않음) — 3초 만에 컴파일되지만 시작되지 않습니다.
  • 원본 테이크(promo/public/gallery/*.webm, 각각 ~3MB)는 gitignore에 포함됩니다; 회로 스틸과 테이크별 JSON은 커밋되므로 재렌더링 시 테이크만 다시 가져오면 됩니다.

음악

promo/public/soundtrack.mp3 = Mixkit "House Vibez" by Lily J (assets.mixkit.co/music/745/745.mp3), Mixkit Stock Music Free License — 상업적 사용 가능, 저작자 표시 불필요. 123 BPM. 파일을 교체하고 detect-beats.py를 다시 실행하여 트랙을 변경하십시오; 라이선스 노트는 promo/public/ATTRIBUTION.md에 최신 상태로 유지하십시오.

트랙은 약 8초의 인트로로 시작됩니다: Promo.tsx의 AUDIO_START는 첫 번째 감지된 비트이므로 오디오가 그 지점부터 시작되고 구성 t=0은 다운비트에 맞춰집니다. 볼륨은 0.55로 고정되며 0.9초 페이드인과 아웃트로 위의 2.2초 페이드아웃이 적용됩니다.

스타일 규칙 (David의 리뷰에서 — 유지할 것)

  • 비디오는 보드-템플릿 모달이 이미 열려 있고 AI 채팅이 이미 최소화된 상태로 에디터에서 시작합니다. 홈 페이지, 로딩, 또는 보이는 최소화 클릭이 없어야 합니다(리코더가 시작 전에 프로그래밍 방식으로 처리; prepare.mjs가 start 마크까지 트림).
  • 인트로 제목은 SOLID 다크 카드 위에 — UI 위에 반투명하게 절대 표시하지 않음.
  • 줌은 대상물을 중앙에 두어야 함: translate+scale로 가장자리 클램프 적용(Promo.tsx), transformOrigin-at-point 사용 금지(대상물이 테두리에 위치하여 잘림, 예: ESP32 카드).
  • 부품 추가 비트는 짧은 유지(~0.5초)를 사용하여 줌이 제때 해제되어 부품이 어디에 놓였는지 볼 수 있게 함.
  • 코드 비트는 전체 에디터 창을 중앙에 배치(fx/fy 재정의 357,280) — 코드가 작성되는 동안 잘린 에디터를 표시하지 않음.
  • Run을 클릭한 후에는 커서를 다른 곳(리코더가 700,620으로 이동)에 배치하여 버튼 스피너가 보이도록 함; Run 비트는 컴파일/실행 클러스터를 중간 정도 배율(1.8)로 줌.
  • 저항기를 수평으로 회전시켜 배치(수직 기본값은 카메라에서 자체 와이어와 겹침).
  • 포인터는 macOS 스타일의 화살표여야 하며 점이 아니어야 함. 핫스팟 계산(saas-product-demo 스킬에서 가져옴): 끝부분이 24x24 viewBox의 (4,3)에 위치하므로 렌더링 너비 W에서 요소는 (-4W/24, -3W/24)만큼 오프셋됨 — 이 계산 없이 모든 클릭이 약 6-8px 정도 빗나감.
  • 줌 펀치는 음악 비트에 맞춰짐(위의 음악 참조); 펀치가 클릭에서 ~0.3초 이상 벗어나지 않도록 함.
  • 클릭 시 모달이 닫히는 비트(choose-blank, add-*)는 lead: 0.45가 필요함: 피크가 클릭 전에 와야 프레임에 카드가 아직 열려 있는 상태가 표시되고, 릴리즈 시 부품이 어디에 놓였는지 드러남. 클릭 자체에 피크가 맞춰지면 이미 닫힌 대화상자에 줌이 머물게 됨.

트랩 (각각 테이크 실패를 유발 — 모두 스크립트에서 처리됨)

  1. /는 로그인 상태에서도 마케팅 랜딩 페이지이며, 에디터는 /editor입니다. 먼저 페이지 내에서 fetch POST /api/auth/login으로 로그인하십시오.
  2. 새 /editor에서는 "Start a new project" 오버레이가 자동으로 열리며(.new-project-overlay), 외부의 모든 포인터 클릭을 가로챕니다. 먼저 이와 상호작용하거나 프로그래밍 방식으로 클릭을 전달하십시오.
  3. 피커의 검색 입력은 이전 쿼리를 유지합니다 — 입력 전에 Ctrl+A + Backspace로 지우지 않으면 "esp32led"처럼 검색합니다.
  4. 피커 카드: .component-picker-modal .card-name에 대해 정확한 제목 일치(일반 텍스트 엔진은 모달 뒤의 Monaco 토큰을 찾음). 결과는 디바운스됩니다 — 최대 5초까지 폴링하십시오. 카드 이름은 정확합니다("Resistor 220 Ω"에는 U+2126 스타일 문자가 포함됨, "Resistor"가 아님; /components-metadata.json 확인).
  5. 보드는 본체에서 드래그하지 않음 — 피커가 놓은 위치(캔버스 오른쪽 가장자리 근처)에 보드를 두고 작은 부품을 라이브 boundingBox 기준 상대적으로, 공간이 있는 왼쪽에 배치하십시오.
  6. 핀 클릭: 앱 자체의 [data-pin-overlay="true"][title=<pin>] div를 사용하되, 호스트 요소에 가장 가까운 후보를 선택하십시오(제목 충돌: 보드 핀 "2"와 저항 핀 "2"). pinInfo 오프셋에서 계산하면 회전된 부품에서 깨집니다. ESP32 핀은 '2','4','GND'로 명명됩니다(D2 아님).
  7. 각 와이어가 제대로 연결되었는지 path[stroke="#1a1a1a"](모든 와이어의 외곽선 경로; 와이어에는 클래스/데이터 속성 없음)를 세어 확인하십시오. 실패 시 Escape + 재클릭으로 한 번 재시도하십시오.
  8. 회로 검증기는 직렬 저항이 없는 LED에 대해 Run을 차단합니다(3.9e12 A 오류). 데모는 GPIO2 -> 220R -> LED A, GND -> LED C를 연결해야 합니다. "Run anyway"가 필요했던 테이크를 절대 제공하지 마십시오.
  9. 빈 템플릿은 기본 스케치를 제공합니다 — 화면에 보이는 주석을 입력하기 전에 Ctrl+A를 누르고, monaco.editor.getModels()[0].setValue(...)를 사용하여 전체 스케치를 설정하십시오(리터럴 타이핑은 Monaco의 자동 닫기 괄호와 충돌).
  10. "Enjoying Velxio? / Star on GitHub" 토스트 메시지는 약 5분 이상 지속되는 테이크를 방해합니다 — 주입된 클리너가 매초 이를 제거합니다.
  11. Playwright는 OS 커서를 기록하지 않습니다: 주입된 #vx-cursor div + mousedown ripple(context.addInitScript)이 보이는 포인터 역할을 합니다.
  12. 컴파일 대기는 실제 시간이 소요됩니다(워밍업 30초 - 콜드 5분): 리코더가 run과 sim-started를 기록하고 prepare.mjs가 해당 구간을 제거합니다. 시뮬레이션 시작은 "in-browser" 콘솔 라인으로 감지됩니다; "guest crashed" = 중단.
  13. Remotion은 --browser-executable을 통해 Playwright의 Chromium으로 렌더링합니다(이 박스에 번들 브라우저가 다운로드되어 있지 않음).

참고 저장소 (2026-08-15 검토)

동일한 장르의 두 Claude-Code 스킬로, 다른 접근 방식을 사용합니다: 스크린샷/개략적 UI에서 합성 커서로 영화를 구성합니다 — 우리의 것은 실제 제품을 녹화합니다. 스킬을 향상시킬 때 포크하십시오:

  • github.com/noamdorr/saas-product-demo-video — Remotion에서 20-45초 비트 동기화 마케팅 필름. 가져올 것: 사운드트랙 비트 동기화(librosa detect-beats.py: 스네어에서 장면 전환, 킥에서 장면 내 이벤트 — 우리 비디오는 무음이므로 음악 추가 및 줌 비트 정렬이 가능한 가장 큰 업그레이드), 커서 핫스팟 수학(SVG 화살표 끝은 24박스의 4,3에 위치 — 점 커서를 화살표로 바꾸는 경우 중요), 타이핑 예산 확인, 반복 플레이북.
  • github.com/Vincentwei1021/video-shotcraft — 데모 소스 + 갤러리(vincentwei1021.github.io/video-shotcraft), 승인된 템플릿(Ink Press), 2.5D 카메라 움직임, 사운드 디자인 및 세 가지 운영 모드(템플릿 / 자율 / 공동 제작)가 포함된 152개의 샷 레시피 카드. 가져올 것: 연출적 샷 어휘와 최종 검토 체크리스트; 본격적인 시네마틱 필름이 필요할 경우 플러그인으로 설치할 수도 있음.

관련

  • 스크린샷 파이프라인: scripts/shots.mjs(동일 저장소) — 장면은 주제가 아닌 경우 AI 패널이 최소화된 상태.
  • GIF: 세그먼트 녹화(Playwright recordVideo) 후 ffmpeg two-pass 팔레트로 변환; 줌+크롭 패턴은 scripts/weather-media.mjs 참조(요소의 boundingBox에서 크롭 영역 가져오기).
  • 스테이징 테스트 사용자: memory vstaging-test-user(s3-tester, pro).
  • 고장난 쇼케이스 프로젝트(날씨 스테이션)는 project/docs-portal-2026-08/STATUS.md(velxio-prod)에서 추적됨.

관련 스킬