explainer-video-pipeline (자동 생성)
사용 시기
사용자가 과학, 제품, 기술 등 주제에 대해 1~3분 분량의 나레이션 설명 영상을 원할 때 사용합니다. 최종 결과물은 음성 해설, 자막, 배경음악, 효과음이 포함된 단일 MP4 파일입니다.
파라미터 및 기본값
사용자에게 주제만 물어보고, 사용자가 다른 값을 지정하지 않는 한 모든 기본값을 사용하세요. 어떤 값을 사용했는지 한 줄로 알려주세요.
| 파라미터 | 기본값 | 다른 값 |
|---|---|---|
topic | 필수 | — |
storyboard_model | claude-opus-5.5가 대본, 나레이션, 스토리보드 작성 | kiro-cli chat --list-models의 모든 모델 ID |
video_engine | opus-5.5: claude-opus-5.5가 각 장면을 그리는 코드 작성 | 다른 코드 모델 (예: claude-sonnet-5.5); seedance (BytePlus ModelArk API, ARK_API_KEY 필요); hybrid (코드로 그린 장면 안에 Seedance 클립 삽입) |
renderer | remotion (React/SVG; Remotion이 헤드리스 Chromium을 프레임별로 구동) | html (Canvas 2D / SVG / GSAP / p5.js 페이지, Playwright로 캡처); manim (Manim Community 장면; 기하, 그래프, 벡터, 단계별 유도에 최적) |
seedance_model | seedance-1-5-pro-251215 | 사용자의 ModelArk 계정에서 활성화된 모든 Seedance 모델 |
tts | polly, 신경망 음성 Zhiyu, cmn-CN, us-east-1 | gtts (무료, 키 불필요, 덜 자연스러운 음성); 기타 Polly 음성/언어 |
captions | 켜짐: Whisper 단어 타이밍, 단어별 강조 표시 자막으로 내장 | 꺼짐 |
whisper_model | small (CPU, int8; 10초 음성에 약 5초 소요) | base (더 빠름), medium (더 정확한 타이밍) |
music | synth (ffmpeg로 만든 로열티 프리 오실레이터 배경음) | none; 사용자가 소유한 음악 파일 경로 |
sfx | 켜짐: scenes.json에 나열된 이벤트를 합성하여 해당 프레임에 배치 | 꺼짐: 모든 장면에서 sfx 제외 |
language | 중국어 (만다린) 나레이션 | Polly와 Whisper가 모두 지원하는 모든 언어 |
size, fps | 1920×1080, 30 fps | 세로 영상의 경우 1080×1920 |
"Opus 5.5로 제작"은 Opus 5.5가 작성자임을 의미합니다: 대본과 그리기 코드를 작성하고, 렌더러가 그 코드를 픽셀로 변환합니다. 텍스트 모델이 비디오를 직접 출력하는 것은 없으며, Seedance만이 직접 생성합니다. 첫 번째 응답에서 한 번 이 점을 언급하세요.
세션이 이미 claude-opus-5.5에서 실행 중이라면 직접 작성하세요. 그렇지 않으면 스토리보드(2단계)를 위해 model="claude-opus-5.5" 및 keep=true로 작업을 하나 생성하고, 장면 코드(5단계)를 위해 spawn_continue로 동일한 실행을 계속한 후, 결과물을 직접 검토하세요.
설정 (머신당 한 번)
도구는 안정적인 캐시 디렉토리(예: ~/.cache/explainer-video/)에 보관하고, 세션 간 초기화되는 $KIROCREW_SCRATCH에는 절대 보관하지 마세요.
- ffmpeg:
aevalsrc,anoisesrc,tremolo,sidechaincompress,ass/libass가 포함된 전체 정적 빌드. Remotion에 번들된 ffmpeg에는 이들이 없습니다.FFMPEG/FFPROBE를 해당 경로로 설정하세요. - Python venv (
boto3 gTTS playwright faster-whisper pillow numpy), 그런 다음 해당 venv에서python -m playwright install chromium-headless-shell실행. faster-whisper 1.2.x는 PyAV 19에서 (unexpected keyword argument 'metadata_errors') 오류가 발생하므로av==16.1.0으로 고정하세요. Whisper 모델이 한 번만 다운로드되도록HF_HOME을 캐시 디렉토리로 설정하세요. - Manim (
renderer=manim의 경우만): pip는 aarch64에서 빌드할 수 없습니다(pycairo, manimpango, moderngl용 휠 없음). 루트 권한이 없으면 micromamba를 사용하세요:micromamba create -p <cache>/manim-env -c conda-forge python=3.12 manim.Text()는 CJK 글꼴에서 작동합니다.MathTex/Tex는 LaTeX 배포판과dvisvgm이 필요합니다. aarch64의 conda-forgetexlive-core에는latex.fmt가 없으므로 수식은 실패합니다. 수식은Text()(유니코드: F = m·a, x², √, →)로 작성하거나, 사용자가 설치한 시스템 TeX Live를 사용하세요.
단계
도우미 스크립트는 이 스킬의 scripts/ 폴더에 있습니다.
- 프로젝트. 사용자의 작업 공간 아래 git 저장소에 프로젝트 폴더를 만드세요.
renderer=remotion의 경우, 직접package.json,tsconfig.json(resolveJsonModule: true),src/index.ts,src/Root.tsx를 만들고npm i remotion @remotion/cli react react-dom을 실행하세요. - 대본 및 스토리보드 (
storyboard_model이 작성).scenes.json작성: 각 장면마다id,narration(음성 대사),visual(화면에 표시될 내용), 선택적manim(Scene 클래스 이름), 선택적sfx:[{"at": FRAME_IN_SCENE, "kind": "whoosh|hiss|pop|rise|thud|PATH"}]. 6~10개의 장면을 사용하고, 각 장면은 하나의 아이디어를 담으며, 제목 장면과 엔드 카드를 포함하세요. 웹 검색으로 사실을 확인하고 README에 출처를 명시하세요. - 참조 이미지. 영상에 실제 객체가 등장할 경우, 명확한 사진을 요청하거나 찾아서
ref/에 보관하세요. 실제 객체의 모양을 기억에서 그리지 마세요: 사진에 엣지 검출을 실행하고, 주요 지점을 측정한 후, 해당 지점에서 모양을 생성하는 작은 스크립트를 저장소에 유지하세요. - 나레이션이 타이밍을 결정합니다.
narrate.py scenes.json . --tts polly실행. 이 스크립트는durations.json(실제 음성 길이에 패딩을 더한 장면별 프레임 수),narration.wav,audio/sNN.mp3를 생성합니다. 장면 코드는durations.json을 읽어 각 장면이 해당 대사 길이만큼 정확히 지속되도록 합니다. - 장면 코드 (
video_engine이 작성).remotion: 장면당 하나의 React 컴포넌트, 장면 시작을 기준으로useCurrentFrame및interpolate/spring으로 애니메이션.html: 하나의index.html파일에window.seek = async (frame) => {...}를 포함하여 프레임 번호와durations.json배열로부터 정확히 해당 프레임을 그립니다.requestAnimationFrame, 벽시계 시간, 시드되지 않은Math.random을 사용하지 마세요.durations.json배열을 페이지에 상수로 붙여넣으세요:file://로 연 페이지는 로컬 파일을fetch()할 수 없으며, 실패는 조용히 발생합니다. GSAP: 일시 중지된 타임라인 +tl.seek(frame / fps). p5.js:noLoop()+seek에서redraw().manim: 장면당 Scene 클래스가 있는 하나의scenes.py파일.os.environ["SCENE_SECONDS"]에서 대상 길이를 읽고self.wait(max(0.04, secs - self.renderer.time))로 끝냅니다.secs에 맞춰 긴 애니메이션 크기를 조정하세요. 프레임 하단 15%는 자막을 위해 비워두세요.seedance:ARK_API_KEY가 설정된 상태에서seedance_clips.py scenes.json .실행.clips/<id>.mp4를 다운로드합니다(URL은 24시간 후 만료).
- 전체 렌더링 전에 스틸 이미지 확인. 주요 장면당 4~6프레임을 렌더링하고, 하나의 축소된 콘택트 시트로 결합하여 단일 이미지를 확인하세요. 독립적인 확인을 위해, 시트와
scenes.json만으로 새 리뷰어를 생성하세요. - 사운드. 장면에
sfx가 있으면sfx.py scenes.json .을 실행하세요. 그런 다음mix_bgm.py . --music <music>: 음성 아래에서 음악을 덕킹하고,sfx.wav를 추가하며,narration_bgm.wav를 쓰고, RMS 레벨을 출력합니다. 음악만 있는 리드 인은 약 −20~−30 dB여야 합니다. −55 dB 이하는 들리지 않음을 의미합니다. - 자막.
captions.py scenes.json . --size <WxH>는 faster-whisper 단어 타임스탬프로 각 대사를 전사하고, Whisper가 동음이의어를 잘못 인식하기 때문에(예: "气体"를 "漆体"로 인식) 스크립트 자체 문자에 매핑합니다.captions.ass(말할 때 각 문자가 강조됨)와words.json(문자별 시간, 5단계에서 화면 강조에 사용 가능)을 생성합니다. - 렌더링 (무음 영상).
remotion:npx remotion render src/index.ts <Comp> out/silent.mp4.html:capture_html.py index.html out/silent.mp4 --frames <durations.json의 합계>.manim:manim_scenes.py scenes.py . --manim <manim-env>/bin/manim --quality h. 각 클래스를 렌더링하고 정확한 프레임 수에 맞게 패딩 또는 트리밍합니다.
- FFmpeg로 합성. 자막 포함:
ffmpeg -i silent.mp4 -i narration_bgm.wav -vf "ass=captions.ass" -c:v libx264 -crf 18 -pix_fmt yuv420p -c:a aac -b:a 192k -shortest final.mp4(자막 없으면-c:v copy사용 및-vf제거). 비디오와 오디오 길이가 약 0.1초 이내로 일치하는지 확인한 후, 최종 MP4에서 4~5프레임을 추출하여 확인하세요. 문장 중간의 프레임을 포함하여 자막 강조를 확인하세요. - 배포. 기능 브랜치에 커밋하고, PR을 열며, 병합 후
gh api repos/<o>/<r>/git/trees/<base>?recursive=1로 파일이 제대로 들어갔는지 확인하세요.
주의사항
- SVG 경로
d=문자열 안에/* */주석을 절대 넣지 마세요. Chromium이/에서 구문 분석을 중단합니다. 6자리 16진수 색상을 사용하세요. - 하드코딩된 절대 프레임 번호를 가진 코드는 장면이 끝난 후에 클라이맥스가 올 수 있습니다.
- Manim에서 객체가 이동한 후에 레이블과 화살표를 배치하거나(또는
always_redraw/add_updater로 연결), 그렇지 않으면 이전 위치에 남아 있습니다.DashedVMobject에는 자체 점이 없습니다: 일반 모양에서 위치를 가져오세요. - pip로 설치한 Playwright는 캐시된 것보다 최신 Chromium 빌드를 필요로 할 수 있습니다.
- 여러 병렬
strReplace호출로 하나의 파일을 편집하지 마세요. 편집 내용이 손실됩니다. 셸 heredoc을 통해 코드를 작성하지 마세요. 가드레일이 차단할 수 있습니다. - Seedance 2.x 모델은 계정 활성화가 필요하며 실제 사람 얼굴이 있는 참조 이미지를 거부합니다. Seedance 1.5 pro 클립은 4~12초입니다.
- Remotion 라이선스: 개인 및 3인 이하 회사는 무료입니다. 대기업은 유료 Company License가 필요합니다.
html및manim은 이를 피할 수 있습니다.