뮤직 비디오 (모션 그래픽)
노래를 들을 수 없습니다. 모든 시각적 요소는 측정된 데이터에 의존하므로, 첫 번째 작업은 항상 송 폴더입니다. 노래 데이터가 잘못되면 모든 프레임이 잘못됩니다.
도움말은 이 파일 옆에 있습니다. 스킬 폴더의 run.py로 실행하세요 (기본 설치 경로 표시; 다른 위치에 설치했다면 조정하세요):
python3 ~/.claude/skills/music-video/run.py song-folder SONG.mp3 OUT_DIR [--fps 30] [--lyrics-lang en|tr] [--lyrics-text known.txt]
python3 ~/.claude/skills/music-video/run.py analyze SONG.mp3 # 비트/마디/구간을 JSON으로
python3 ~/.claude/skills/music-video/run.py dance2d SONG.mp3 --out DIR --analysis OUT_DIR/song-map.json --start 23.8 --dur 14.3 [--render]
노래를 들었다고 주장하지 마십시오. "분석 결과로부터"라고 말하세요.
1. 송 폴더 (항상 먼저)
| 파일 | 내용 | 도구 |
|---|---|---|
| passage.<확장자> | 오디오, 바이트 동일 복사본 (sha256 확인); 최종 믹스에 그대로 사용 | — |
| song-map.json / .md | BPM, 비트, 다운비트/마디, 에너지 구간 (calm/build/high), 비트당 에너지, 드롭 | Beat This! → aubio CLI → 내장 numpy 추적기 |
| stems/ | 보컬 / 드럼 / 베이스 / 기타 (캐시됨, 재실행 빠름) | demucs htdemucs (선택 사항) |
| envelopes.json | 믹스 및 각 스템의 프레임당 음량 (dB + 0..1) | numpy |
| hits.json | 킥 / 스네어 / 하이햇 공격 시작점 및 강도 0..1 | 드럼 스템에 대한 대역 분할 스펙트럼 플럭스 |
| notes.json | 멜로디 및 베이스 음표 (선택 사항) | basic-pitch |
| lyrics-passage.json / .md | 단어 시간이 포함된 가사 줄 | 보컬 스템에 whisper.cpp whisper-cli`` |
| song-story.md | 작성할 템플릿: 주제, 음성, 분위기 호, 구간별 핵심 이미지 | 사용자, 가사 + 지도로부터 |
| README.md | 각 파일의 내용, 단위 (초), FPS | 생성됨 |
규칙:
- 구간은 에너지 구절입니다 (노래 자체 에너지로 순위가 매겨진 2마디 구절), 절/후렴이 아닙니다. song-story.md에서 직접 이름을 지정하세요.
--lyrics-text에 실제 가사(한 줄에 한 줄)를 제공하면 whisper의 단어에 정렬됩니다. 일치하지 않는 단어는 보간된 시간을 얻습니다 (matched: false). 이 옵션이 없으면 줄은 whisper의 원시 출력입니다. 확인하세요. 조용한 보컬 스템 위의 줄은suspect로 표시됩니다 (whisper는 기악에서 환각 현상을 일으킵니다). 기악곡은 whisper를 건너뜁니다.- 모든 무거운 단계는 실패하는 대신 저하됩니다: Beat This! 미설치 → aubio (외부 CLI) → numpy 추적기 (실제 다운비트 없음, 4/4 추측); demucs 미설치 → 믹스 전용 엔벨로프 및 히트; basic-pitch 미설치 → notes.json 없음; whisper 미설치 → 가사 없음. 실행의
warnings에 무엇이 생략되었는지 표시됩니다. 사용자에게 알리세요. - hits.json은 플래시, 흔들림 및 스케일 팝에 충분히 좋지만 드럼 트랜스크립션은 아닙니다: 하이햇도 스네어에서 발사되며, 베이스 음표가 스네어 대역으로 누출될 수 있습니다.
- song-story.md는 재실행 시 절대 덮어쓰지 않습니다. 가사와 분석이 지원하는 것만 작성하고, 의미를 만들어내지 말고 머리말을 "알 수 없음"으로 남겨두세요.
2. 창의적 계획 (렌더링 전에 표시)
- song-story.md에서 나온 하나의 콘셉트, 하나의 세계, 하나의 팔레트, 가사용 오픈 라이선스(OFL) 폰트 하나.
- 구간 → 장면 표: 구간 변경 = 장면 또는 카메라 변경; 후렴/최고 에너지 구간은 가장 큰 시각적 아이디어를 얻고, 매번 변주를 주어 반복; 드롭 = 다운비트에서 컷, 플래시 또는 스케일.
- 핵심 줄에만 가사 타이포그래피 (단어 시간에 맞춰 운동학적 단어), 모든 줄에 가라오케처럼 넣지 않음.
- 잔잔한 음악에서는 구절과 에너지에 맞춰 템포; 추적된 모든 비트에 하드 컷하지 마십시오. 컷 수보다는 뚜렷한 표현 방식의 수가 더 중요합니다.
- 계획(표 + 3~4개의 설명 또는 렌더링된 스틸)을 보여주고 전체 렌더링 전에 승인을 받으세요.
- 먼저 읽어볼 가치가 있는 구성 요소: HyperFrames 자체의
music-to-video스킬 (github.com/heygen-com/hyperframes,skills/music-to-video/, Apache-2.0)에는 비트 컷 모션 프리미티브(플래시 컷, 크래시 줌, 휘핑, 크로매틱 스플릿, 화면 흔들림, 운동학적 문자…) 및 가사 레이아웃 카탈로그가 있습니다.
3. 내장 2D 댄스 비디오
보세요: 평면 캐릭터 (둥근 어두운 머리, 둥근 선 팔다리, 색깔 있는 셔츠와 신발), 아치형 거울 문, 보라색/청록색/금색/분홍색의 회전하는 태양 폭발 배경, 굵고 좁은 (Anton) 가사 단어와 하나의 악센트 단어, 다양한 색상의 거울 춤추는 복사본 줄, 필름 스트립, 왕관 및 체스 소품. Devarf의 YouTube 실험(모든 노력 수준으로 만든 하나의 뮤직 비디오)의 "낮은 노력" 2D 비디오에서 영감을 받았습니다.
계획자 (musicvideo/dance2d.py, 순수 및 시드 사용):
- 창은 다운비트에 스냅됩니다; 비트당 하나의 포즈 키, 포즈는 비트에 도착합니다;
- 다운비트는 큰 포즈(build: armsUp / point / clap, high: jump / armsUp)와 전체 무릎 굽힘을 얻습니다;
- 동작 세트(4비트 구절)는 에너지 수준에 따라 매 마디 변경되며 절대 연속으로 두 번 반복되지 않습니다;
- 장면은 구간 시작과 4마디마다 컷됩니다 (팔레트 교체, 태양 폭발 속도는 수준에 따라, 방향은 번갈아; calm/build에서는 문, high에서는 체스 + 5명의 댄서 줄, 리더에게 왕관);
- 댄서 복사본: calm 1명, build 3명, high 5명;
- 가사 JSON
[{start, end, text, accent}](창 초 단위) → 각 단어는 비트에 맞춰집니다.
리그 (runtime/char2d.js, window.Char2D): 피벗이 있는 SVG 그룹 (엉덩이 > 다리 > 정강이 > 신발, 몸통 > 팔 > 팔뚝, 머리). 팔다리 각도는 바깥쪽-양수 도(0 아래, 90 옆, 180 위)이므로 하나의 포즈가 양쪽에서 작동합니다; 지면 고정은 아래쪽 발을 바닥에 유지합니다 (스쿼트는 자동으로 내려갑니다), air는 점프를 위해 들어 올립니다. 포즈: idle, stepL/R, armsUp, swayL/R, pointL/R, clap, jump, squat, handsOnHips (mirror(p)는 양쪽을 바꿉니다). poseAt(keys, t)는 유지한 다음 마지막 ≤0.26초 동안 부드럽게 전환하며 큰 히트에서는 오버슈트가 있습니다. runtime/dance2d.js는 window.MV_DANCE에서 계획을 그립니다; 하나의 GSAP 트윈이 프록시 세터를 구동하여 draw(t)를 호출하므로 모든 프레임은 t의 순수 함수입니다.
dance2d의 출력: DIR/plan.json 및 DIR/project/ (HyperFrames 프로젝트). --render 사용 시 DIR/dance2d.mp4도 함께 생성: 1920×1080, 30fps, H.264 yuv420p, 창에 해당하는 노래 자체 오디오(AAC, 페이드 없음). CC BY 라이선스 음악은 화면에 --credit 필요.
렌더링은 사용자의 선택입니다. --render는 npx hyperframes render를 실행하며, 헤드리스 Chrome/Chromium을 다운로드하고 구동합니다. 사용하기 전에 물어보세요. 이 옵션이 없으면 프로젝트 폴더까지의 모든 작업은 Python만으로 작동합니다. GSAP는 번들로 제공되지 않습니다: gsap.min.js를 runtime/에 넣거나 MV_GSAP를 설정하세요. 그렇지 않으면 프로젝트는 렌더링 시 jsDelivr CDN에서 GSAP 3.14.2를 로드합니다.
4. 내장 리그를 넘어선 캐릭터 (직접 가져오기)
이 스킬은 3D 모델을 제공하지 않습니다. 사용자가 3D(Three.js) 캐릭터를 원하는 경우:
- 완성된 비디오에 재배포를 허용하는 라이선스의 모델을 사용하세요(예: CC0 모델, 또는 사용자가 자신의 Mixamo 계정에서 다운로드한 캐릭터 및 애니메이션 - 완성된 비디오 내에서는 괜찮지만, 원시 파일은 재배포하거나 공개 저장소에 커밋할 수 없음);
- 라이선스를 확인하지 않고 다른 프로젝트의 예제 모델을 절대 복사하지 마십시오;
- 또는 라이선스 문제가 전혀 없는 절차적 프리미티브(캡슐, 구, 상자를 간단한 본 체인에 연결)를 사용하세요.
프레임 결정성은 여전히 적용됩니다:
mixer.setTime(t * rate)각 프레임, 절대mixer.update(dt)사용 금지;rate = song_bpm / clip_bpm; 마디 경계에서 클립 전환.
5. 렌더링 규칙 (모든 렌더러)
- 모든 것은
t = frame / fps의 순수 함수입니다.Date,requestAnimationFrame델타, 시드 없는Math.random()사용 금지. - hits.json의 킥/스네어에 대한 작은 히트(카메라 흔들림, 빛 플래시, 스케일 팝); envelopes.json에서 밝기 또는 광채.
- 출력: 1920×1080 (또는 Reels/Shorts용 1080×1920), 30fps, H.264 yuv420p, AAC, 노래(또는 선택한 창)와 동일한 길이.
- 광과민성: 초당 3개 이상의 전체 프레임 플래시 금지.
- 예산: 더 많은 사고 시간은 더 나은 모션을 제공하지만, 한 세션 내에서 검토하세요. 단일 뮤직 비디오에 대한 다중 에이전트 검토 루프는 토큰을 빠르게 소모하고 한도 초과 후 재시작하는 경향이 있습니다.
6. 전달 전 확인 사항
- 끝까지 재생됨; 지속 시간 == 노래(또는 창) 지속 시간 ±1프레임.
- 오디오 스트림은 원본 노래입니다 (디코딩된 PCM 해시 비교, 또는 지연 0에서 상호 상관 피크).
- 동기화 지점 확인: 후렴 다운비트에서 5프레임을 렌더링하고 히트 포즈/플래시가 해당 지점에 있는지 확인.
- 구간별 연락처 시트 (
ffmpeg -i out.mp4 -vf "fps=1,scale=480:-1,tile=4x4" sheet.jpg)를 실제로 확인. report.md: 무엇을 만들었는지, 왜, 어떻게, 무엇을 확인했는지, 무엇이 확실하지 않은지 기록.