Explainer
얼굴 없는(faceless) 설명 영상은 하나의 연속적인, 코드로 만들어진 애니메이션 세계(단면도, 확대된 메커니즘, 물체를 쥐고 있는 손)에 음성을 입히고, 상단에 자막을 표시하며, 배경 음악이 없는 영상입니다. 출력은 1080×1920 mp4입니다.
작성하기 전에 다음 문서를 읽으십시오:
script-craft.md: 스크립트 구성 방법(훅, 반전, 상상, 메커니즘, 뒤집기, CTA)과 템포.craft-rules.md: 시각 요소를 생동감 있고 입체적으로 만드는 요소. 처음 만든 버전은 대부분의 규칙을 위반합니다.
가장 어려운 부분은 각 비트에 대한 시각적 은유입니다. 두 번째로 어려운 부분은 모든 프레임을 움직이게 하고 깊이감 있게 조명하는 것입니다. 코드는 쉬운 부분입니다.
모드
- 한 번에 제작(기본값): 중단 없이 개념에서 최종 영상까지 진행합니다. 판단은 직접 내리고 최종 결과를 보고합니다.
- 검토: 사용자가 검토나 승인을 요청하면 스크립트와 스토리보드 단계에서 각각 멈춥니다. 사용자의 메모를 반영하여 수정하고 계속 진행합니다.
설정 확인 (한 번)
PATH에 ffmpeg가 있어야 하고, remotion/node_modules가 존재해야 함(없으면 remotion/에서 npm install 실행), .env에 FISH_API_KEY가 있어야 함(.env.example 복사). 키가 없으면 voice --placeholder로 모든 것을 빌드하고, 마지막 단계로 voice를 다시 실행하고 렌더링해야 한다고 사용자에게 알립니다.
레이아웃
projects/<개념>/ (개념은 슬러그, 예: how-fridges-work):
script.txt,storyboard.mdcomposition.tsx(레이어 스택),timeline.ts(TL),captions.ts,words.ts(생성됨),scenes/S01.tsx …public/vo.wav,vo/(원본 녹음 및 정렬),out/(렌더링, 스틸)
핵심 라이브러리는 remotion/src/core입니다(씬에서 ../../../remotion/src/core로 임포트):
makeTimeline→TL.at("구"),TL.end("구")Captions,Drift,Bokeh,Vignette,handheld,Backdrop,Dust,FootnoteCamera(WorldSvg,camAt,toScreen),Label,Sparks,Snow/Rain- 이징,
ramp,keys,rand, 폰트SANS/MONO
도구: python3 bin/explainer.py … (-h 실행)
| 명령어 | 기능 |
|---|---|
new <c> | 프로젝트 스캐폴딩 |
voice <c> [--voice-id ID] [--speed 1.0] | Fish Audio 음성 및 단어 타임스탬프 → words.ts, public/vo.wav (−14 LUFS). wpm 출력 |
voice <c> --placeholder [--wpm 200] | API 호출 없이 무음 오디오 및 합성 타이밍 |
stills <c> <sec>… | 해당 초의 프레임 → out/에 하나의 연속 시트. 확인 |
studio <c> | Remotion Studio에서 실시간 미리보기 (사용자용) |
render <c> [--blur] | 60fps mp4 → out/. --blur는 240fps로 렌더링 후 60fps로 평균 내 모션 블러 적용 (약 4배 느림) |
qa <c> | 활성 검사: 정지 프레임 10% 미만, 고정 실행 0.3초 미만. 실패하면 종료 코드 1 및 각 고정 구간 이름 출력 |
워크플로우
-
스크립트.
new <c>실행.- 사용자가 스크립트를 제공한 경우, 있는 그대로 사용합니다 (숫자와 기호만 단어로 수정).
- 그렇지 않으면
script-craft.md에 따라script.txt를 작성합니다: 기본적으로 일상적인 사물 형식(270–320단어), 제품 및 네트워크의 경우 시스템 형식. 체크리스트를 실행합니다. - 검토 모드: 승인을 위해 중단.
-
음성.
voice <c>실행 후 출력된 wpm 확인 (목표 190–215; 벗어나면 제안된--speed로 다시 실행).- 음성은
--voice-id, 없으면FISH_VOICE_ID, 없으면 Fish 기본값. 복제된 음성 ID도 동일하게 작동합니다. - 모델은
--model, 없으면FISH_MODEL, 없으면s2.1-pro. script.txt가 아닌words.ts에 맞춰 작업하십시오. 음성이 숫자를 발음하므로TL.at()과 자막 구문은 음성과 일치해야 합니다.
- 음성은
-
스토리보드 (
storyboard.md). 먼저 World 섹션을 채우고, 비트당 한 행씩 추가합니다. 비트의 은유를 만들려면 시청자가 무엇을 볼지 생각해 보십시오:- 확대: 단면도 또는 분해도.
- X-레이: 물체 내부.
- 시간 지연: 이동하는 파동, 전환되는 부품.
- 측정: 상승 또는 하강하는 수치.
"상상" 시나리오는 탈출 세계(excursion world)가 되고, 각 메커니즘 비트는 홈 다이어그램으로 돌아갑니다. 스토리보드 확인을 실행합니다.
- 검토 모드: 승인을 위해 중단.
-
빌드. 스토리보드의 각 샷에 대해 하나의 씬 파일을
scenes/에 작성하고composition.tsx에 추가합니다.- 각 씬은
t를 입력받아 순수 함수로, 자신의 시간 창 밖에서는null을 반환합니다. - 타이밍: 모든 이벤트는
TL.at("정확한 단어")에 동기화됩니다. 절대 초(raw seconds)를 사용하지 마십시오. - 연속성: 동일한 다이어그램을 공유하는 비트는 하나의 카메라 경로(A4)로 하나의 씬에 있어야 합니다.
- 이동: 각 씬은 이동하며 등장하고, 이전 씬의 퇴장과 겹칩니다(A2).
- 씬별로 SVG ID에 접두사를 붙입니다.
- 각 씬은
-
반복. 각 샷의 핵심 단어에서
stills를 실행하고 크래프트 규칙 A와 B에 대해 확인합니다. 그런 다음render와qa를 실행합니다. 발견된 모든 FROZEN 구간은 해당 샷 내에서 움직임의 전달자(A1b)를 부여하여 수정합니다.captions.ts구문을 수동으로 작성합니다: 구문당 하나의 강조된 주요 명사(호박색, 발음될 때 팝업). -
전달. 최종
render는qa를 통과해야 합니다(사용자가 최대한의 완성도를 원하면--blur사용). 사용자에게 제공:- mp4 경로
- 스크립트
- 스토리보드의 비트별 한 줄 요약
- 아직 실제 음성이 필요한 대체 음성 정보
위험 신호: 멈추고 수정
| 생각 | 규칙 |
|---|---|
| "이 비트에 새로운 설정이 신선함을 유지해 준다" | C1: 홈 다이어그램 1개 + 탈출 세계 1–2개. 개수를 세십시오 |
| "결정적 순간에 완전히 멈춰서 긴장감을 준다" | A1c: 피사체는 멈추되, 카메라와 주변은 계속 움직이게 하십시오 |
| "배경 음악, 그레인, 드롭을 추가한다" | D, B8: 음성만; 그레인 없음; 깊이는 조명에서 나옵니다 |
| "페이드 인" / "다음 씬으로 크로스페이드" | A2: 이동하며 등장, 퇴장, 전환 |
| "전체적인 드리프트가 생동감을 유지할 것이다" | A1b: 각 샷은 10–60 px/s 크기의 중간 크기 움직임 요소가 필요합니다 |
| "이 비트를 위해 더 가까운 카메라로 컷한다" (동일 다이어그램) | A4: 하나의 세계, 하나의 카메라; 키프레임을 넘겨주십시오 |
| "균일한 조명도 괜찮다, 다이어그램이니까" | B1: 어둠 속으로의 감쇠, 가장자리 조명, 비네트 |
| "활성화될 때 전체를 색조 처리한다" | B4: 원인에서 전파하고, 앞면과 흐름을 갖추십시오 |
| "사각형으로 물체를 표현해도 괜찮다" | B2: 한 번의 해부학 패스; 당겨서 드러날 것을 고려해 만드십시오 |
"괜찮아 보인다, qa는 건너뛰자" | E: qa는 반드시 통과해야 함; 눈은 정지를 놓칩니다 |