Communitygithub.com

TheNoumanDev/make-video

한 줄의 아이디어를 검증된 MP4 소셜 비디오(YouTube Shorts, Instagram Reels 또는 YouTube 장편)로 제작하는 무료 로컬 AI 파이프라인입니다. 스크립트 작성, 음성 생성(Chatterbox, 사용자 목소리 복제 가능), 자막(Whisper), 음악 및 SFX(FluidSynth), 렌더링, 자동 QA를 모두 로컬에서 처리합니다.

make-video란 무엇인가요?

이 스킬은 macOS Apple Silicon에서 완전히 무료로 실행되는 로컬 AI 비디오 제작 파이프라인입니다. 사용자가 '비디오 만들어줘', '릴스', '쇼츠', '스토리', '설명 영상' 등을 요청할 때 활성화되며, 스크립트 작성부터 최종 MP4 렌더링 및 자동 품질 검사(QA)까지 모든 과정을 처리합니다. 주요 특징으로는 Chatterbox를 이용한 음성 생성(사용자 목소리 복제 기능 포함), Whisper를 이용한 단어 동기화 자막, FluidSynth 기반 음악 및 효과음 생성, 그리고 자동 QA 게이트(음량, 자막 정확도, 시각적 다양성 검사)가 있습니다. 모든 도구는 로컬에서 실행되므로 API 키나 크레딧이 필요 없으며, 한 번 설정하면 이후 프로젝트는 캐시된 모델을 재사용하여 더 빠르게 진행됩니다. 이 스킬은 TheNoumanDev의 zero-dollar-studio 프로젝트의 일부로, @0x45.dev YouTube 채널의 실제 제작 파이프라인입니다.

지원 대상✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/TheNoumanDev/zero-dollar-studio/tree/main/plugins/make-video/skills/make-video

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

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

문서

make-video은(는) 무엇을 하나요?

아이디어를 렌더링되고 검증된 MP4로 변환합니다. 무료 로컬 도구만 사용합니다. 이 스킬로 만든 프로젝트는 AGENTS.md에 자체 규칙이 있으므로 이를 따라야 합니다(애니메이션 순수성, useScale, sec(), 폴더 레이아웃).

0. 비디오 프로젝트 설정 (최초 한 번)

현재 폴더에 tools/make-story.sh가 없으면 아직 비디오 프로젝트가 아닙니다:

  1. 작업 전에 먼저 기계를 확인하세요: uname -sm (Darwin arm64 필요), node --version (20+), brew --version, df -h ~ (약 8 GB 여유 공간). 다른 OS에서는 무엇이 작동하지 않는지 설명하세요(Chatterbox와 테이크 체커는 Apple GPU에서 실행됨). Node나 Homebrew가 없으면 사용자에게 설치 명령어 하나를 알려주고 기다리세요.

  2. 사용자에게 다운로드될 내용을 알리고 승인을 기다리세요. 승인 없이 다운로드를 시작하지 마세요. 다음 표를 보여주세요(모두 무료, 공식 소스):

    다운로드크기용도위치
    npm 패키지 (Remotion 등)~500 MB렌더링node_modules/
    ffmpeg, uv, FluidSynth (Homebrew, 없을 때만)~150 MB오디오/비디오 도구Homebrew
    Python 패키지 (PyTorch, Chatterbox…)~1.5 GB음성, QA.venv/
    GeneralUser GS 사운드폰트~30 MB음악tools/soundfonts/
    Chatterbox 가중치~3 GB음성Hugging Face 캐시 (~/.cache/huggingface), 모든 프로젝트에서 공유
    Whisper small.en~590 MB자막tools/models/
    Whisper large-v3-turbo (선택 사항 테이크 체커)~1.6 GB불명확한 대사 재녹음Hugging Face 캐시

    총 약 6 GB, 10-20분 소요. 더 가벼운 옵션을 제공하세요: SKIP_TAKE_CHECK=1은 테이크 체커를 건너뜁니다(총 4.4 GB). 프로젝트를 생성할 위치를 물어보세요(기본값 ~/videos).

  3. 승인을 받으면, 이 SKILL.md 옆에 있는 template/ 폴더를 프로젝트로 복사하세요(점 파일 포함, cp -R <skill dir>/template/. <dest>/). 그런 다음 git init.

  4. 백그라운드에서 tools/setup.sh를 실행하고 사용자에게 진행 상황을 알리세요: 현재 단계를 말해주고(▶ 줄 출력), 큰 다운로드 중에는 진행률을 보여주세요(du -shL ~/.cache/huggingface/hub/models--ResembleAI--chatterbox, 목표 ~3 GB). 재실행해도 안전합니다: 완료된 단계는 건너뛰고 중단된 다운로드는 재개됩니다. 다운로드가 중단되면(5분 동안 크기 증가 없음) 중지하고 setup을 다시 실행하세요. 실패하면 오류를 읽고 원인(누락된 도구, 디스크 공간, 네트워크)을 해결한 후 다시 실행하세요. 누락된 모델을 우회하지 마세요.

  5. 작동을 확인하세요: tools/make-story.sh stories/fridge-drama FridgeDrama는 약 4분 만에 33초 예제(냉장고에서 세 야채가 논쟁)를 만듭니다. 사용자에게 out/FridgeDrama.mp4를 보여준 다음, 무엇을 만들고 싶은지 물어보세요.

도구는 스스로 모델을 찾습니다(Chatterbox와 테이크 체커는 Hugging Face 캐시에서, 자막은 tools/models/에서). 따라서 설정 후에는 아무것도 구성할 필요가 없습니다. 두 번째 프로젝트는 캐시된 가중치를 재사용하므로 설정이 훨씬 빠릅니다.

1. 브리핑 확정 (누락된 경우에만 질문)

필드기본값
플랫폼 / 형식릴/쇼츠: 1080×1920, 30 fps · YouTube: 1920×1080, 30 fps · 피드 포스트: 1080×1350
길이릴/쇼츠: 15-45초 · YouTube: 3-10분
종류스토리(캐릭터가 말함, §3B 사용) 또는 모션 그래픽(텍스트, 데이터, 다이어그램, §3A 사용)
주제 + 하나의 핵심 메시지시청자가 기억해야 할 한 가지
오디오음성(Chatterbox), 음악 + SFX (tools/music.py), 또는 음악만
음성Chatterbox 내장 음성, 또는 사용자 자신의 녹음을 복제한 음성(§3B). 동의 없이 다른 사람의 목소리를 복제하지 마세요.

2. 코드보다 먼저 스크립트 작성

길이 예산: Chatterbox 속도의 영어 음성은 약 2.6 단어/초입니다. 목표 시간 ≈ 단어 수 ÷ 2.6 + Σ 일시 정지 + 아웃트로. 생성 전에 확인하세요. (냉장고 드라마: 62단어 + 6.4초 일시 정지 + 3초 아웃트로 = 33초.)

세로형 쇼트 폼 페이싱 규칙:

  • 프레임 0부터 화면과 오디오로 후크를 걸어야 합니다. 처음 1.5초가 시청 유지율을 결정하며, 프레임 0은 종종 썸네일이므로 빈 프레임이나 페이드 인으로 시작하지 마세요.
  • 각 줄은 ≤ 12 단어. 자막은 한 번에 ≤ 3 단어를 표시합니다.
  • 매초 무언가 움직여야 합니다.
  • 1080×1920 안전 영역: y=220 위나 y=1540 아래(플랫폼 UI)에는 중요한 것을 배치하지 말고, y≈1000 아래 x≈940 오른쪽에는 배치하지 마세요: 좋아요/댓글/공유 버튼이 오른쪽 가장자리를 따라 있습니다(tools/qa.py --layout에서 실패). 발표자는 왼쪽 아래에 배치하세요.
  • 페이오프나 punchline으로 끝내고, 2-3초짜리 클릭 유도 문구 카드를 추가하세요.

설명 영상 템플릿 ("작동 원리" 및 개발 팁 릴, 45-60초, 120-160단어):

  1. 후크(≤ 3초): 놀라운 사실 또는 결과.
  2. "실제 작동 방식은 이렇습니다": 설명을 여는 한 줄.
  3. 2-4개의 비트, 각각 하나의 숫자 + 하나의 비유 ("비디오는 초당 30장의 사진, 마치 플립북과 같습니다").
  4. "하지만 여기에 함정이 있습니다": 반전, 함정 또는 흔한 실수.
  5. 한 줄의 페이오프, 명확한 클릭 유도 문구하나(저장, 공유 또는 팔로우).

그런 다음 스크립트 아래에 모든 사실 주장과 출처 링크를 나열하고, 확인할 수 없는 것은 표시한 후 음성 생성 전에 수정하거나 삭제하세요. 숫자나 주장이 나올 때 화면에 출처를 표시하세요(작게, 카드 하단).

쇼츠/릴 제작 체크리스트:

  • 눈에 보이는 진행. 단계별 비디오는 <StepCard steps={[{at: 0, title: "다운로드"}, …]} /> (src/components/StepCard.tsx)를 사용하세요: "STEP 2/4" 알약과 분할 막대.
  • 노래방 자막(선택 스타일). <Karaoke words={captions} keywords={["무료"]} style={{left: 60, right: 140, top: 1180}} /> (src/components/Karaoke.tsx): 2-5단어 덩어리가 화면에 표시되고, 말하는 단어는 진하게, 다가올 단어는 회색, 키워드와 강조 단어는 강조 색상으로 표시되어 음소거 자동 재생에서도 시청자가 앞서 읽을 수 있습니다. background는 밝은 카드 느낌을 줍니다. 레이아웃 검사가 볼 수 있도록 qa를 전달하세요.
  • 시리즈 칩. 왼쪽 상단의 에피소드 표시("PART 2")는 게시물을 연속 시청하게 만듭니다.
  • 대비 표시. 전후 비교 또는 "우리 대 그들"은 말로 설명하는 것보다 두 열 카드로 더 효과적입니다.
  • 목록보다 스토리 비트. "시도 1 실패 → 시도 2 실패 → 효과가 있었던 것"은 기능 목록보다 주의를 더 잘 잡습니다.
  • CTA 전에 punchline. 하나의 인간적인 줄, 그 다음 클릭 유도 문구.
  • 진짜 보상(가이드, 프롬프트, 저장소)이 있는 경우에만 "KEYWORD로 댓글 달면 DM 드립니다"를 약속하세요.

TTS 작성을 위한 팁:

  • 줄을 "…"으로 시작하지 마세요: Chatterbox가 임시 채움 단어를 improvise합니다.
  • 줄을 숫자 단어로 시작하지 마세요("Two. The face"는 "to the face"로 나옴). "Second, …"로 작성하세요.
  • 숫자와 특이한 이름은 발음되는 대로 쓰고("five point six", "X Z"), 실제 텍스트는 줄의 caption 필드에 넣으세요.
  • 큰 숫자는 반올림하세요("over 600"): TTS는 "646"과 "87,000"을 왜곡합니다.
  • 후크의 짧은 단어는 흐려집니다("This repo"는 "The three"로 들림). 테이크 체커가 정확히 들을 때까지 다시 작성하세요.
  • 여러 음성이 같은 짧은 단어를 함께 외치지 마세요. 혼합이 번집니다.
  • 구두점이 전달을 지시합니다: "?"는 상승, "."는 하강, CAPS는 강조를 추가합니다.

3A. 모션 그래픽 비디오

  1. src/compositions/_Template → src/compositions/<Name>으로 복사하고, 비트 유형(후크, 포인트, 통계, 목록, CTA)별로 하나의 컴포넌트를 만듭니다.
  2. getSampleIntroDuration이 하는 것처럼 스크립트(비트 합계 - 전환)에서 지속 시간을 계산합니다.
  3. 인라인 defaultProps와 함께 src/Root.tsx에 등록합니다.
  4. 음악만: totalMs, outroStartMs 및 events가 있는 타임라인 JSON을 작성한 다음 tools/music.py를 실행합니다.

3B. 음성 스토리 (캐릭터 + 자막 + 음악)

stories/<slug>/script.json을 생성하세요(stories/fridge-drama/script.json 복사):

  • characters: color, exaggeration (0.3 차분 → 0.9 극적), 선택적으로 refVoice: 복제할 tools/voices/의 깨끗한 10-30초 WAV. 없으면 Chatterbox의 내장 음성이 사용됩니다. 사용자 목소리를 복제하려면: 조용한 방에서 60-90초 동안 자연스럽게 말하게 한 다음, 음악이나 에코가 없는 깨끗한 10-15초 조각을 자릅니다(ffmpeg -ss <start> -t 12 -i note.m4a -af highpass=f=80,loudnorm=I=-18 -ar 24000 tools/voices/me.wav).
  • lines: speaker, text, pauseAfter (초), 선택적 event + eventAt: "start"로 스토리 비트(문 열림, 숨기…)를 표시하여 애니메이션과 음악 모두가 참조합니다.
  • 줄당 선택적 음성 지시: emotion (calm|neutral|warm|excited|dramatic|whisper), pace (slow|normal|fast), emphasis (자막에서 CAPS로 말하고 강조되는 단어), pauseBefore (초). "pace": "slow"와 0.4초 일시 정지는 모든 단어를 명확하게 만듭니다.

그런 다음 하나의 명령어를 실행하세요:

tools/make-story.sh stories/<slug> <CompositionId>     # 음성 → 자막 → 음악/SFX → lint → 렌더링 → 마스터 → QA
SKIP_VOICE=1 tools/make-story.sh …                     # 비주얼만 반복
SAMPLE=15 tools/make-story.sh …                        # 처음 15초만 렌더링하여 승인 받고 중지
도구출력
tools/voice.pypublic/<slug>/lines/*.wav (텍스트 + 음성 설정으로 캐시됨), public/<slug>/voice.wav, stories/<slug>/timeline.json (라인 타이밍, 이벤트, 프레임별 입 모양). 테이크 체커가 설치된 경우 Whisper가 모든 문장을 듣고 불명확한 문장을 재녹음합니다(VOICE_TAKES, 기본값 3).
tools/captions.mjspublic/<slug>/captions.json (Whisper의 단어 타이밍, 스크립트의 철자), stories/<slug>/captions-report.json (단어 오류율 및 줄당 일치 단어, Whisper가 놓친 "채워진" 부분, 전체 matchRate)
tools/music.pypublic/<slug>/music.wav (MIDI → FluidSynth, 컷에 맞춤), public/<slug>/sfx.wav
tools/qa.pystories/<slug>/qa/report.md: PASS / FIX / FAIL

timeline.json / captions.json에서 컴포지션을 빌드하세요(src/compositions/FridgeDrama/data.ts 참조). mouthOpen()으로 입을 움직이고, 활성 화자를 향해 시선을 돌리며, timeline.events.*를 통해 이벤트를 처리하고, timeline.durationInFrames에서 지속 시간을 가져옵니다.

타이밍 변경(텍스트 또는 일시 정지)은 자막을 다시 생성해야 합니다. 자막 시간은 절대적이므로 그렇지 않으면 표류합니다. make-story.sh는 항상 자막을 다시 실행합니다.

4. 확인 (완료하기 전에 항상)

tools/make-story.sh는 tools/qa.py로 끝나며 FAIL 시 0이 아닌 종료 코드를 반환합니다. 파일, 음량(-14 ±1 LUFS, true peak ≤ -1), 자막 정확도, 비트에 맞는 컷(≤ 120ms), 정지 구간(≤ 3초), 시각적 다양성(가장 긴 유사 구간 ≤ 5초), 화면 텍스트를 반복하는 자막을 확인합니다. LAYOUT=<CompId>는 또한 데드 존과 얼굴에 대한 자막을 확인합니다(컴포지션에는 자막 #FF00FF과 얼굴 #00FFFF를 윤곽선으로 표시하는 qa prop이 필요합니다). stories/<slug>/qa/report.md를 읽고 모든 FAIL과 FIX를 수정하세요.

그런 다음 눈으로 확인하세요:

  1. npm run lint.
  2. WER > 0.2인 stories/<slug>/captions-report.json의 줄은 아마 중얼거린 것입니다: 다시 작성하고 재생성하세요(캐시 덕분에 저렴함). Whisper가 놓친 단어는 간격의 음성 부분 위에만 배치되며, 긴 단어가 더 많은 시간을 받고 filled 아래에 나열됩니다: 해당 지점을 들어보세요. matchRate가 70% 미만이면 스크립트와 오디오가 다르므로 계속하기 전에 음성을 다시 생성하세요.
  3. 주요 비트(후크, 각 화자, 각 이벤트, 아웃트로)에서 스틸을 렌더링하고, 하나의 접촉 시트로 결합한 후 실제로 살펴보세요:
    npx remotion still <Id> out/stills/f<N>.png --frame=<N> --scale=0.4
    ffmpeg -i a.png -i b.png … -filter_complex hstack=inputs=K out/stills/contact.png
    
    캐릭터 크기, 안전 영역, 캐릭터를 가리는 오버레이, 아웃트로 뒤의 잔해, 자막 동기화, 텍스트 크기(칩 ≥ 28px, 본문 ≥ 54px, 1080 너비 기준)를 확인하세요.
  4. 최종 MP4에서 4-5프레임을 추출하여 살펴보세요.
  5. 중요한 내용은 맥락 없이 접촉 시트를 비판하도록 새로운 하위 에이전트에게 요청하세요. 새로운 시각은 제작자가 놓친 문제를 찾습니다.

5. 전달

사용자에게 MP4, 제목, 캡션, 3-5개의 해시태그 및 썸네일 프레임을 제공하세요. 명시적 승인 없이는 게시하거나 업로드하지 마세요. 복제된 음성이나 AI 얼굴이 사용된 경우 YouTube의 "변경 또는 합성 콘텐츠" 레이블을 체크하도록 상기시키세요.

시간을 절약하는 규칙

  • 한 번에 하나의 렌더링. 여러 Remotion 렌더링을 동시에 실행하면 기계가 몇 시간 동안 과부하됩니다. 파이프라인은 이미 --timeout=180000 --concurrency=2를 전달합니다.
  • Remotion 패키지는 npx remotion add <pkg>로 추가하고 절대 일반 npm i를 사용하지 마세요. 버전이 일치해야 합니다.
  • 음량: 대화 −16 LUFS, 배경 음악 약 −24, 최종 마스터 −14(2패스, 이미 make-story.sh에 있음). 음성이 음악보다 최소 10dB 이상 크게 유지하세요.
  • Studio는 defaultProps가 Root.tsx의 인라인 객체인 경우에만 prop 편집을 저장할 수 있습니다.
  • 행에 대한 zsh 루프는 for x in "a b c"가 깨지므로 while read -r a b c; do …; done <<EOF로 작성하세요.

더 많은 교훈과 직접 추가하는 방법: reference/lessons.md.

측정된 비용 (M1 Max, 64 GB)

단계시간
Chatterbox 모델 로드실행당 ~20초 (모든 줄이 캐시된 경우 건너뜀)
음성 생성첫 줄 ~55초 (워밍업), 그 후 ~3× 실제 시간
테이크 확인재녹음이 필요한 문장당 ~20-30초
자막 (Whisper small.en, WebGPU)11줄 기준 ~10초
음악 + SFX2-5초
1080×1920, 33초 렌더링~97초 (비디오 1초당 ~3초)
전체 파이프라인음성 캐시 시 ~2분; 처음부터 ~4분

make-video는 TheNoumanDev](https://github.com/TheNoumanDev)가 zero-dollar-studio에서 만들었습니다. @0x45.dev YouTube 채널의 파이프라인입니다.

관련 스킬