/dynamic-edit
움직이지 않는 토킹 헤드는 시청자를 금방 지루하게 만듭니다. 하지만 이유 없이 움직이는 것은 더 나쁩니다. 이 파이프라인은 각 단어에 어떤 효과가 어울릴지 결정하고, 이를 사람이 거부할 수 있는 계획으로 작성한 후에야 리소스를 투자합니다.
레포지토리 루트:
THP_HOME=${THP_HOME:-$(cat ~/.config/talking-head-pipeline/root)}
계획을 세우기 전에 다음 문서를 읽으십시오: $THP_HOME/docs/STYLE_RULES.md (제작 규칙), $THP_HOME/docs/LAYOUTS.md (지오메트리 및 캡션 안전 영역), references/plan-format.md (스키마), references/qa.md (승인 기준). 3D 관련: $THP_HOME/docs/3D.md.
입력 조건: 영상은 이미 편집되어 있어야 합니다. 여기서는 무음 제거나 필러 제거를 하지 않습니다. 원본 테이크는 먼저 /autocut으로 보내고, clean.mp4와 작업 디렉토리(단어 정보 포함)를 가져와야 합니다.
계획 단계를 절대 건너뛰지 마십시오. 로토스코핑은 영상 1분당 약 12분이 소요되며, 전체 렌더링은 수십 분이 걸립니다. 잘못된 추측을 텍스트 계획에서 잡아내는 것은 비용이 전혀 들지 않습니다.
워크플로우
1. 프로젝트 스캐폴드
P=<projects dir>/<slug> # 동영상 프로젝트를 저장할 위치 묻기 (Desktop 절대 안 됨)
cp -R "$THP_HOME/template" "$P"
cd "$P"
uv venv --python 3.11 .venv # mediapipe는 3.12 이상에서 휠 미제공
uv pip install --python .venv/bin/python "mediapipe==0.10.21" opencv-python backgroundremover numpy pillow
scripts/download_models.sh # MediaPipe 얼굴 감지기 (레포지토리에 포함 안 됨)
(cd remotion && pnpm install) # 또는 npm install
cp "<autocut workdir>/clean.mp4" remotion/public/raw.mp4
python3 "$THP_HOME/scripts/autocut/verbatim_cut_words.py" "<autocut workdir>" -o remotion/public/words.json
16:9 테이크의 수직 릴: 마지막 두 줄 대신 scripts/prep_vertical.sh "<autocut workdir>" "$P" 사용 (중간 헤드 x 기준 정적 9:16 크롭, 팔로우 크롭 안 함).
2. 인벤토리, 컷, 트래킹
ffprobe -v error -select_streams v:0 -show_entries stream=width,height,r_frame_rate,nb_frames \
-show_entries format=duration -of default=nw=1 remotion/public/raw.mp4
.venv/bin/python scripts/detect_cuts.py remotion/public/raw.mp4 --out remotion/public/cuts.json
.venv/bin/python scripts/track_head.py remotion/public/raw.mp4 --out remotion/public/track.json --cuts remotion/public/cuts.json
- 줌 헤드룸 = 소스 너비 / 타임라인 너비 (2560에서 1920으로는 1.33배 여유). 넘으면 업스케일.
- 종횡비는 계획의 너비/높이에서 자동 감지 (
lib/layouts.ts프로필). 하나의 엔진, 포크 없음. - track.json에서
detectionRate를 확인하십시오. ~0.9 미만이면 얼굴 고정 움직임이 신뢰할 수 없으므로 알립니다. - 컷 감지는 점진적 변화(예: 애니메이션 화면 공유 전환)를 놓칩니다. 세그먼트당 한 프레임씩 샘플링하여 누락된 경계를 cuts.json에 직접 추가하십시오. 화면 공유 세그먼트에는 펀치인, 캡션, 카드를 넣지 않습니다 (
captions.silence에 범위 설정).
3. 단어 교정
words.json에서 모든 고유 명사, 브랜드, 티커, 인물 이름을 확인하십시오. Whisper 계열 모델은 이들을 자주 잘못 인식하며 문장은 여전히 매끄럽게 읽히므로 검토 시 발견되지 않습니다. 단어 파일을 수정하십시오 (두 토큰을 하나로 합쳐도 됨). 절대 렌더를 수정하지 마십시오. 숫자는 숫자로 작성.
4. 계획 작성 후 중단
- 먼저 전체 대본을 읽으십시오. 내러티브의 실제 비트(갈고리, 주장, 숫자, 전환, 폭로, 보상, 말보다 보여주는 것이 나은 순간)를 찾으십시오.
- 각 비트에 대해 효과 선택 가이드를 참고하여 도구를 선택하십시오. 많은 비트에는 아무 효과도 넣지 않습니다.
scripts/build_plan.example.py를scripts/build_plan.py로 복사하고, 단어 앵커("phrase@seconds")를 사용하여 해당 비트를 작성하십시오. 이 스크립트는remotion/plan.json과 캡션을 생성합니다. 이유 없는 이벤트, 시작과 종료 단어 앵커가 없는 이벤트, 너무 좁게 배치된 펀치는 거부합니다.- 사람에게 표를 보여주십시오. 행당 이벤트 하나: 시간, 효과, "X에 도착, Y 후에 종료, 이유 Z". 또한 로토 시간(및 그에 따른 매팅 시간), 줌 헤드룸을 초과하는 리프레임, 약 12초 이상 이벤트 없는 구간, 필요한 3D 렌더를 포함하십시오.
- 승인을 기다리십시오. 그런 다음 디스크에서
plan.json을 다시 읽으십시오. 사람이 직접 편집했을 수도 있습니다.
만약 사람이 특정 순간에 특정 효과를 지정했다면, 그 비트에 대한 계획은 그대로 따릅니다.
5. 계획에 필요한 것만 빌드
- 로토 윈도우:
scripts/render_and_qa.sh가 매트를 생성하거나, 윈도우별로scripts/matte_frames.py사용. - 3D 히어로 타이틀 / 3D 에셋:
tools/render3d(docs/3D.md 참조). 먼저 스틸(--stills)을 보고, 그다음--clip --dir=remotion/public/<name>. 계획 이벤트의at/until과 동일한 프레임 범위를 샷에 넣으십시오. - 사이드 카드:
remotion/src/layouts/cards.tsx에 종류가 정의되어 있음. 필요하면 거기에 새 종류를 추가하십시오. - 화면 장면 페이지:
remotion/src/screen/pages.tsx. 확대할 UI는 코드로 다시 만드십시오. 스크린샷은 2배에서 흐려집니다. - 전체 화면 장면:
scenes/fullscreen/registry.ts(depth,clip,stage). - SFX: 계획이 확정된 후,
scripts/add_sfx.py "$P" sfx_map.json --library <dir>.
6. 스틸로 확인 후 렌더링
스틸은 몇 초면 되고, 렌더는 오후 내내 걸립니다:
cd remotion && npx remotion still src/index.ts Edit ../qa/landing.png --frame=<N>
모든 히어로 착지(및 착지 + 25 프레임), 모든 레이아웃 진입, 모든 전환, 모든 3D 도착을 확인하십시오. 그런 다음:
scripts/render_and_qa.sh "$P" <name> # 로토 윈도우 매팅, 렌더링, QA 시트 작성
렌더링: --concurrency 4-6, nice로 프로세스 우선순위 낮춤, Config.setChromiumOpenGlRenderer('angle') 유지 (이미 remotion.config.ts에 있음). 그렇지 않으면 WebGL 장면이 헤드리스에서 실패합니다. yuv420p bt709로 출력; yuvj420p 파일은 QuickTime에서 검은 화면으로 재생됩니다.
7. QA (references/qa.md) 후 싱크 트림
누군가 보기 전에 references/qa.md의 모든 게이트를 실행하십시오. 그런 다음 렌더의 오디오 지연을 소스와 비교하여 측정하고 트림합니다 (Remotion 렌더는 수십 ms 정도 지연됨; 측정 필수, 추정 금지):
"$THP_HOME/scripts/master/sync_trim.sh" renders/<name>.mp4 remotion/public/raw.mp4 renders/<name>_final.mp4 [--loudnorm -14]
최종 싱크는 5ms 미만을 목표로 합니다. 사람이 원할 때만 라우드니스 노멀라이제이션 적용 (소셜 기본값 -14 LUFS). 최종 파일을 사람에게 보여주십시오.
8. 전달 후 수정: 범위 패치, 전체 비디오 재렌더링 금지
scripts/patch_render.sh --base renders/prev.mp4 --replace 0-1049 --render 0-887 --out renders/next.mp4
--replace는 이전 렌더에서 버릴 범위, --render는 현재 계획에서 대체할 범위입니다 (소스가 재편집되면 두 값이 다름). 패치 부분만 인코딩되고 앞/뒤는 키프레임에서 스트림 복사됩니다. 프레임 수는 검증됩니다. 계획이 존재하는 상태에서 소스에서 더듬는 부분을 제거해야 한다면, build_plan.py로 앵커에서 계획을 다시 빌드하여 모든 효과가 해당 단어와 함께 이동하도록 하십시오.
9. 정리: 사람이 동영상이 완료되었다고 말한 후에만
먼저 물어보십시오. scripts/cleanup.sh는 매트 PNG, 프레임 덤프, QA 시트, 드래프트, venv 및 node_modules를 삭제합니다. 계획, 소스, 트랙, 캡션 및 최종 렌더는 보존됩니다. 매트 재생성에는 영상 1분당 약 12분이 소요되므로, 요청 없이 실행하지 마십시오.
효과 선택 (도구 상자, 순서 아님)
공식은 없습니다. 히어로 단어, 로토, 3D가 없는 비디오도 유효한 계획입니다. 단순한 카메라 응시 영상은 펀치인과 캡션만으로 구성될 수 있습니다. 모든 효과는 스크립트의 무언가에 의해 정당화되어야 하며, 각 이벤트는 이유(내러티브 역할), 진입(도착하는 단어, 움직임이 미리 시작되어 그 단어에 정확히 도착), 종료(떠나는 단어: 그 생각의 끝, 다음 실제 쉼표, 약화 표현 직전의 단어)를 명시해야 합니다. 고정된 유지 시간이나 "잠시 조용해서"는 안 됩니다.
- 얼굴 우선. 처음 2-3초는 화자의 얼굴이어야 하며, 프레임 0부터 읽을 수 있는 갈고리 이미지(검은 화면에서 페이드 인 아님)여야 합니다. 약 2.5초 이전에는 전체 화면 그래픽을 사용하지 마십시오: 자동 재생은 음소거되어 있고, 통계로 시작하면 인포그래픽처럼 보여 스크롤됩니다.
- 펀치인 (주력): 문장 길이, 적게, 목적 있게. 핵심 문장이 구성될 때 도착하고, 문장 전체를 유지하며, 마지막 단어와 함께 해제됩니다. 절대 한 단어만 펀치하지 않으며, 타이머로 간격을 두지 않습니다. 긴 형식의 토킹 헤드에서는 대략 30-45초당 한 번; 숏츠에서는 스크립트가 정당화할 때만 더 조밀하게. 추적된 얼굴에 고정. 연결된 두 구문: 이야기를 전달하는 절반을 펀치합니다. 중첩 악센트(유지 + 핵심 구문에 작은 악센트)가 문장 내 세 번의 펀치보다 낫습니다.
- 사이드 레이아웃 (16:9): 숫자, 목록 또는 비교가 설명되는 동안 화면에 계속 표시되어야 할 때 사용. 주제가 한쪽으로 슬라이드하고, 콘텐츠 크기 카드가 반대쪽에, 카드는 해당 단어에 맞춰 전환되며 숫자가 언급될 때 펀치인됩니다. 긴 형식에서 대부분의 정보 비트에 적합합니다.
- 화면 장면 (16:9): "이렇게 생겼습니다" 워크스루. 비디오당 한두 번만 사용하고 모든 언급에 사용하지 마십시오. 제품 UI를 재현하는 경우 실제 UI와 일대일로 일치해야 하며, 데이터만 변경되고 데이터는 실제여야 합니다.
- 오프셋 리프레임 + 카드: 사이드의 가벼운 버전, 줌 헤드룸 내에서 사용.
- 로토 (주제 뒤): 오프너와 히어로 순간에만 사용. 기본 예산 비디오당 15초, 30초 이상 경고, 60초 이상은 허가 필요. 뒤를 가릴 가치가 있는 것만 통과시켜야 합니다.
- 주제 뒤 히어로 단어: 갈고리, 강한 전환, 명명된 아이디어. 머리 위, 모든 글리프를 읽을 수 있어야 함 (착지 + 25 프레임 스틸 확인). 비디오당 하나, 두 개가 멀리 떨어져 있지 않으면.
- 3D 히어로 타이틀: 큰 주장이나 숫자를 머리 옆이나 가슴 앞에 배치, 모든 프레임 가장자리에서 동일한 여백 (1080 너비 기준 최소 ~90px), 절대 얼굴 위에 배치 금지.
- 3D 에셋: 화자가 언급하는 로고나 객체, 얼굴 옆 빈 공간에서 회전, 겹치면 뒤에 로토.
- 전체 화면 장면: 설명보다 보여주는 것이 명확히 나을 때만, 최대 두 개, 페이드+블러 인/아웃.
- 캡션: 고정된 하단 1/3, 모든 곳(토킹 헤드, 사이드, 화면)에서 동일한 위치와 스타일. 강조 = 악센트 서체 AND 1.22배 크기를 전체 구문에 적용, 두 카드로 분할 금지. 헤드 트래킹 캡션은 요청 시에만 활성화.
- SFX: 보이는 이벤트당 하나(전환, 히어로 착지, 강한 펀치, 카드, 클릭), 미묘하게.
엄격한 규칙
- 얼굴 위에 아무것도 배치 금지. 캡션, 카드, 칩, 로고 또는 3D 객체를 해당 시간 범위의 어떤 프레임에서도 얼굴 상자 위에 배치하지 마십시오. 이동, 축소 또는 로토로 뒤로 보내십시오. track.json에서 측정.
- 화자 위에 텍스트 상자 칩 금지. 카드에 단면 악센트 라인 금지 (상단, 왼쪽, 모든 가장자리): 채우기 틴트 또는 전체 균일 테두리 사용.
- 전체 프레임 페이드만 허용. 타이틀이 남아 있는 상태에서 컨테이너만 페이드 금지.
- 전환: 페이드+블러 (기본값), 일반 페이드, 리퀴드 스팅거. 지그재그/톱니 셔터 금지.
- 줌이나 프레임 가장자리로 텍스트 잘림 금지. 확대된 UI는 캡션 밴드 위에서 페이드 아웃 (
World가장자리 페이드). 캡션은 확대 금지. - 리프레임은 그것이 공간을 만드는 대상과 동일한 렌더에서 전달. 빈 벽을 향한 카메라 움직임 금지.
- 화면의 모든 숫자는 말한 내용 또는 저장된, 출처가 확인된 데이터와 일치하는지 확인. 절대 임의로 생성 금지.
- 객체 및 아이콘은 실제 로고 또는 생성/소싱된 이미지여야 함. 코드는 모션, 텍스트, UI, 차트를 그립니다. 화살촉은 에셋, SVG 아님.
- 화면에 엠 대시 금지. 사람이 요청하지 않는 한 "아래 댓글" / "DM 보내기" 콜 투 액션 금지.
- 비디오 위에 겹쳐진 모든 레이어는 자체
AbsoluteFill이어야 함 (정적 비디오는 절대 위치 형제 아래에 그려져 매트 앞에 그래픽이 조용히 배치됨). - 리프레임에는 이동된
transform-origin대신translate + scale사용.
효과 매개변수 및 측정된 숫자: references/effects.md.