overlays: 음성에 싱크된 그래픽, Premiere에 배치하기
두 개의 스킬, 하나의 워크숍
여기 (overlays): 배치 및 편집 | 워크숍 (motion-design): 제작 |
|---|---|
대본, .prproj 타임라인, 구문 앵커로 작성된 계획 | 유일한 Remotion 프로젝트: motion-design/src/, src/illustration/ 내 오버레이 컴포지션 (BrandedVideo, LowerThirdTrack, Screencast, Scene, FondAnime) |
소싱: 사진, B-롤, GIF (gifs.py), 웹 캡처, 이메일 카드 (mail-cards.py) | public/: 폰트, scenes/<video>/ (장면 미디어), sfx/ (사운드) |
사이트 데모 녹화 (screencast-record.py) | 테마 (src/illustration/theme.ts), 사운드 팔레트 (reference/sound-palette.md, scripts/make-sfx.py, scripts/son.py) |
render-segments.py, screencast-render.py, montage-tella.py: 워크숍 내부에서 렌더를 시작한 다음 모든 것을 Premiere XML에 배치 | 음악, 믹스 |
두 폴더는 이웃이어야 합니다 (<skills>/overlays와 <skills>/motion-design). 스크립트는 ../motion-design을 통해 워크숍을 찾습니다. 새 장면 컴포넌트는 motion-design/src/illustration/scenes/에 작성되고, 새 사운드는 워크숍의 신스 레시피에 추가됩니다. 설치 (머신당 한 번, 플러그인 설치): bash "${CLAUDE_PLUGIN_ROOT}/install.sh" --data "${CLAUDE_PLUGIN_DATA}". 수동으로, 네 개의 스킬 폴더를 나란히 복사한 상태에서 키트 루트에서 bash install.sh를 실행합니다. 플러그인 업데이트 후 워크숍의 node_modules 링크가 사라지면 설정 라인을 다시 실행합니다. 자세한 내용은 키트의 INSTALL.md를 참조하세요.
편집 황금률 (기본 설정, 채널에 맞게 조정)
비디오는 음성이 이끕니다. 그래픽은 말한 내용을 다시 설명하지 않습니다. 그래픽은 그렇지 않으면 느낄 수만 있었을 것 (고유명사, 인용구, 장소, 제목, 숫자)을 고정하거나, 말하는 대상을 보여줍니다 (문서, 사이트, 다이어그램).
두 가지 수준의 장식:
- 가벼움: 챕터당 1개의 프리미엄 + 45~60초마다 1개의 로우어 서드 (인트로 0-30초와 결론 제외);
- 빽빽함 (데모, 조사 또는 튜토리얼 영상): 영상의 60~70%를 덮는 애니메이션 장면, 각 장면은 단어에 싱크되며, 3초 이상 움직임이 없는 장면은 없음. 토킹헤드는 제자리를 유지함.
말하지 않으면 원하는 수준을 물어보세요. 기본적으로 애니메이션을 적용하지 마세요: 인트로 (시청자가 남을지 결정), 친밀한 일화 (애니메이션은 감정을 죽임), 긴장을 조성하는 질문, 결론 및 행동 촉구, 형용사 목록.
카메라에서 말해진 대본과의 차이점 (숫자, 용어, 근사치)은 화면에서 수정됩니다: 러프 컷이 보고서에 표시하고, 계획은 새 테이크를 요청하지 않고 음성에 올바른 값을 배치합니다.
규칙 제로: 참조 타임라인은 Premiere 프로젝트의 것이며, 절대 러프 컷의 것이 아닙니다
순서는 항상: 러프 컷 (rough-cut) -> 편집자가 Premiere에서 편집을 검토하고 변경 -> 오버레이입니다. 그 사이에 컷이 이동하고, 클립이 드롭되며, 지속 시간이 변경됩니다: 러프 컷에서 계산된 시간은 30초에서 1분 정도 차이가 나고 요소는 비디오 끝 이후에 종료됩니다.
러프 컷 후에는 하드 스탑합니다. 사용자가 "러프 컷 다음 오버레이, 알아서 해"라고 말해도 러프 컷 XML을 전달한 다음 사용자가 Premiere에서 승인했다고 말할 때까지 기다립니다. 그 전에는 계획도, 시간도, 배치도 없습니다. 시간에 의존하지 않는 것만 진행할 수 있습니다 (이미지와 GIF 소싱).
python3 scripts/timeline-from-prproj.py "/path/clip.MOV" --list # 어떤 시퀀스가 클립을 가지고 있는지
python3 scripts/timeline-from-prproj.py "/path/clip.MOV" --sequence "Derush_v1"
# -> <clip>_transcription.json (SEQUENCE 시간의 단어) + <clip>_timeline.json (클립 -> 시퀀스 매핑)
선택한 시퀀스에서 푸티지의 클립을 읽고 (틱 = 254016000000/s) <clip>_Derush_vN_work/words_premiere.json (프로젝트의 대본, 이미 러프 컷에 의해 재정렬됨)의 단어를 가져옵니다. 여러 시퀀스가 클립을 가지고 있으면 추측을 거부하고 (코드 2), 어느 것인지 묻습니다. 하나의 시퀀스에 여러 클립이 있으면 모두 순서대로 전달합니다 (A.MOV B.MOV --sequence "..."). 각 타임라인 항목과 각 단어는 media를 가지며, 출력은 첫 번째 클립의 이름을 사용합니다. 단어가 깔끔하게 잘리면 클립 내에서 시작하는 경우에만 유지됩니다 (컷보다 최소 80ms 전). 실제로 잘린 단어는 그것을 가리키는 앵커를 끊습니다: 앵커를 이전 단어 + offset으로 이동합니다. 마지막으로 배치된 요소가 시퀀스의 실제 끝보다 앞에 있는지 확인합니다.
러프 컷의 cuts_final.json이나 맵을 절대 재사용하지 마세요. Premiere 프로젝트 없이 (클립 단독): python3 scripts/transcribe.py "/path/clip.mp4" (로컬 whisper.cpp, Apple Silicon에서 15분 분량 푸티지에 약 5분 소요).
사용자가 편집을 반환하면 먼저 비교를 실행하세요: Premiere에서 변경한 사항이 가장 신뢰할 수 있는 피드백입니다. 시퀀스를 러프 컷 XML과 비교하고, 각 반복되는 차이를 수정, 확인 또는 규칙으로 전환한 다음 오버레이 계획을 작성합니다. 사용자가 최종 편집을 승인하면, 전달된 오버레이 XML에 대해 동일한 작업을 수행합니다: 제거하거나, 이동하거나 (2 프레임 이상), 크기를 조정하거나, 추가한 것 (V1에 붙여넣은 자체 푸티지는 제외)은 수정, 확인 또는 규칙이 됩니다. 제거되거나 이동된 것이 없으면 해당 전달 방법이 올바른 것입니다: 유지하세요.
파이프라인
0. (선택 사항) B-롤
클립 옆에 Brolls/ 폴더, NN_description_K.mp4 형식의 파일 (번호, 설명, 변형):
python3 scripts/match-brolls.py "/path/clip.mp4" # -> 완성할 <clip>_broll-script.json
각 B-롤에 대해: 변형 (file), 시간 (timecode MM:SS, 대본에서 확인됨), durationSec (null = 원본 길이). V2에 배치됩니다. 사이트 데모 전에 실행하세요 (--force는 파일을 덮어씁니다). 변형의 연락처 시트를 보고 선택하세요 (변형당 3 프레임). 파일 이름이 종종 거짓말을 합니다 ("street-photography-portrait"가 밤 도시의 드론 샷일 수 있음). 화자가 문자 그대로 보여주지 않는 문장에는 B-롤을 절대 배치하지 마세요. B-롤이 재생되는 동안 오버레이 사운드도 없습니다.
0 bis. (선택 사항) 일러스트 사진
사람, 작품, 책, 장소를 인용하는 비디오용:
- 매니페스트: 비디오 대본에서, 등장 순서의 엔티티 ->
illustrations-manifest.json:참조 대본은 어떤 형식이든 될 수 있습니다 (텍스트, Markdown, 문서): 올바른 철자와 보여줄 대상을 제공합니다.{"version": 1, "dest": "Illustrations", "items": [ {"n": 1, "categorie": "reference", "nom": "First Last", "sujet": "portrait", "url": "https://...", "fallback_urls": [], "note": "source: ..."}]} - URL: 무료 소스 (Wikimedia Commons, 공식 사이트, 오픈 액세스 박물관)를 먼저, 그 다음
python3 scripts/serp_images.py "Name Title" --num 5 --min-width 1200(SerpAPI를 통한 Google 이미지, 키SERPAPI_API_KEY). 이미지가 올바른지 확인하세요 (썸네일을 보세요. 페이지 제목만 보지 마세요. 경매 로트 페이지는 함정입니다). 비디오가 판매되는 경우 권리를 확인하세요. - 다운로드:
python3 scripts/source-illustrations.py illustrations-manifest.json->Illustrations/NN-category-name-subject.ext(바이트 확인, 너비 측정. URL 누락 시 exit 1). - 타이밍:
python3 scripts/match-photos.py "/path/clip.mp4"-><clip>_photos-script.json, 대본에서 이름의 퍼지 검색으로 미리 채워진 시간 (음성 인식은 고유명사를 왜곡합니다). 항상 각 시간을 대본에 대해 수동으로 다시 확인하세요 (퍼지 매치는 첫 번째 대신 늦은 언급을 가져올 수 있음).enabled: false는 사진을 삭제합니다. 사진은 V3에 배치되며, B-롤보다 우선 순위를 가집니다 (사진과 겹치는 B-롤은 XML에서 제거되고 기록됨).
사진 처리: 절대 자르지 마십시오 (원본 비율, 세로는 세로로 유지). 사진은 모든 면에 여백이 있는 (프레임의 약 86%) 평면 배경 위에 위치하며, 상단과 하단 가장자리에 닿는 전체 프레임 포함이 아닙니다. 매니페스트에 .webp 없음 (Premiere는 XML에서 0 길이 미디어로 읽음: sips -s format jpeg로 변환). 너비 800px 미만의 사진은 흐릿하게 보입니다: render-segments.py는 LOW RES 경고를 출력하고, 전달하기 전에 해당 사진을 나열합니다. 장면에 표시된 책 표지는 웹에서 가져온 게시자의 시각 자료 (공식 사이트, HD 목업)이며, 화자 자신의 푸티지에서 가져온 이미지가 아닙니다.
화자가 대상을 보여줄 때는 아무것도 가리지 않습니다. 대본에서 "여기", "여기 보이는 것처럼", "이것", "봐"와 같은 단어를 작품 언급 근처에서 스캔하세요. 화자가 책이나 카메라를 렌즈에 대고 있는 것입니다. 그 창에는 전체 화면 사진이 없습니다 (편집자는 전달된 편집본에서 모든 그러한 표지를 제거했습니다). 표지는 데모 전이나 후에, 또는 전혀 배치하지 않습니다.
0 ter. GIF 및 밈 (기본, 옵션이 아님)
2~4분마다 하나의 GIF, 분위기나 자기 비꼼의 순간 ("이것은 매우 강력하게 밀어붙입니다", "나는 이 모든 것을 지어내고 있습니다")에, 인트로에는 절대 사용하지 않으며, 기술적인 문장을 문자 그대로 설명하는 데 사용하지 않습니다. 단어에 도착하는 gif 장면 (오버레이, 흰색 프레임, 반복)과 효과음.
python3 scripts/gifs.py chercher "that's a bug" --planche gifs-sheet.jpg # 목록 + 번호가 매겨진 연락처 시트
python3 scripts/gifs.py prendre <id> --nom bug --public <video> # 소스 MP4 + 장면 데이터
선택하기 전에 연락처 시트를 보세요 (GIPHY 제목은 보여지는 것을 말하지 않습니다. 영어로 검색하는 것이 종종 더 잘 작동합니다). prendre는 MP4 (.gif가 아님)를 Illustrations/gifs/에 다운로드하고, gifs.json (모든 GIF의 소스)을 유지하며, motion-design/public/scenes/<video>/gifs/에 복사하고 gif 장면의 data (src, srcW, srcH, loopSec)를 출력합니다. 키 GIPHY_API_KEY (무료). GIF는 종종 보호된 작품을 재사용합니다: 판매되는 비디오에서는 사용을 자제하세요.
1. 클립의 프레임 속도 및 포맷 (CRITICAL)
ffprobe -v error -select_streams v:0 -show_entries stream=r_frame_rate,width,height -of csv=p=0 "/path/clip.mp4"
render-segments.py는 JSON에서 제공하지 않을 때 클립의 속도와 크기를 읽습니다. 60fps 클립에서 30fps JSON은 모든 것을 2배로 이동시킵니다. 29.97에서 n 시퀀스 프레임은 n x 1.001 / 30초 동안 지속되며, 각 렌더는 클립을 커버해야 합니다 (tailFrames와 TenirFin 컴포넌트가 처리합니다). 클립은 자체 MEDIA의 속도로 기록됩니다: Premiere는 <in>을 클립의 <rate>가 아닌 <file>의 속도인 29.97로 읽습니다. 스크립트는 <ntsc>TRUE와 함께 in = round(t x fps x 1000/1001)를 씁니다.
세로 9:16 (릴): 동일한 파이프라인, 동일한 JSON. 로우어 서드는 세로를 감지하고 캡션 영역 위로 올라갑니다. 사진은 그대로 유지됩니다 (배경에 띠). 16:9 B-롤은 너비를 채우는 배율을 얻습니다. 릴 규칙 (전달본과 최종 편집본 비교에서): 2~3초 사진 (기본 2.5초), 관련 초상화 사진만큼 길고 사진과 함께 시작하는 로우어 서드, 요청하지 않는 한 재고 B-롤 없음, 화자가 대상을 보여줄 때 표지 없음. 항상 하나의 로우어 서드를 스틸 이미지로 렌더링하고 회색 프레임에 합성하여 시리즈 전에 세로 레이아웃을 확인하세요.
2. 제안하기 전에 읽기
전체 대본을 읽으세요. 찾을 것: 사람 이름 (로우어 서드 "nom"), 작품 제목 ("oeuvre"), 장소 ("lieu"), 용어 또는 운동 ("term"), 강력한 인용구 (프리미엄 quote-full), 부분 발표 (section-title 또는 챕터 카드), 눈에 띄는 숫자 (stat 장면), 논의되는 문서, 교환 및 사이트 (증거 장면, 데모). 인용된 모든 이름, 작품 또는 책은 어딘가에 표시되거나 (매달린 장면, 사진, 카드) 표시되지 않는 이유가 기록됩니다. 화자 자신의 말로 각 다이어그램의 내용을 읽으세요 (대본에서 다시 읽음). 절대 해석하지 마세요: 잘못된 다이어그램 (깔때기의 잘못된 수준에 배치된 프로필)은 의역에서 비롯됩니다.
3. 모든 프리미엄은 한 문장으로 구상됩니다
"내가 보고 싶은 것: 문장은 크게, 이탤릭체로, 왼쪽에 악센트 규칙, 작은 속성." 설명이 "나타나는 텍스트"라면 프리미엄이 아닙니다: 로우어 서드 또는 없음.
4. 기본 카탈로그
| 유형 | 구성 요소 / 종류 | 트랙 | 데이터 | 지속 시간 |
|---|---|---|---|---|
motion (전체 화면 프리미엄) | quote-full | V5 불투명 | text, author?, source? | 10-14초 |
lower-third | lower-third-nom | V6 알파 | name, years?, tag? | 6초 |
lower-third | lower-third-oeuvre | V6 | title, author, year? | 6초 |
lower-third | lower-third-lieu | V6 | place, date | 6초 |
lower-third | lower-third-term | V6 | term, subtitle? | 6초 |
section-title | V6 | eyebrow?, title | 4초 | |
scene | "애니메이션 장면" 참조 | V5 / V6 / V7 | data, cues | 음성을 따름 |
10초 이내에 인용된 이름과 그 작품: tag에 작품이 있는 단일 "nom" 로우어 서드. 화자 자신의 인용구: author 없는 quote-full (그들의 음성이 서명). 애니메이션은 마지막 18프레임에 걸쳐 자동 페이드 아웃으로 종료됩니다.
5. 단어까지의 시간 (CRITICAL)
절대 추정하지 마세요: <clip>_transcription.json에서 단어를 찾고 start를 가져옵니다. 요소는 단어의 시작에 나타납니다 (로우어 서드는 최대 0.5초 앞설 수 있음. 문장의 시작에 동기화하면 너무 일찍 오는 발표로 읽힘). render-segments.py는 유효한 시간 없이 세그먼트를 거부하고 모든 시간을 대본에 대해 확인합니다 (OK / WARN / UNKNOWN). 또한 JSON에서 프레임 속도를 확인하세요 (1단계).
6. 쓰기 전에 계획 제시
| # | 시간 | 지속 시간 | 유형 | 구성 요소 | 이유 |
|---|-------|------|-------------|-------------------|--------------------------------|
| 1 | 01:24 | 6초 | lower-third | lower-third-nom | First Last의 첫 번째 언급 |
| 2 | 02:14 | 12초 | motion | quote-full | 1부의 피벗 인용구 |
JSON을 작성하고 렌더링하기 전에 승인을 기다리세요.
7. 렌더링 및 가져오기
(cd ../motion-design && npm ci) # 한 번
python3 scripts/render-segments.py "/path/clip.mp4" # 모든 것: 렌더 + XML
python3 scripts/render-segments.py "/path/clip.mp4" --lower-thirds-only
...
[번역을 위해 잘림]