릴 캡션 + 오버레이은(는) 무엇을 하나요?
이미 편집된 9:16 릴(보통 2160x3840, 30fps, 예: talking-head-edit의 출력)을 받아서
캡션과 오버레이를 추가합니다. 모든 것은 두 렌더러가 읽는 하나의 edit.json(프레임 단위의 캡션 페이지 및 오버레이)으로
구동되므로 HyperFrames와 Remotion 버전이 프레임 단위로 일치합니다.
SK=~/.claude/skills/reel-captions-overlays
PY=$($SK/scripts/find_python.sh) # faster-whisper large-v3 + opencv ($REELKIT_PYTHON, repo .venv, 또는 python3)
AUDIO_PY=~/.cache/reel-audio/venv/bin/python # 음악 스테이지 (scripts/setup_audio.sh가 생성)
ANA_PY=~/.cache/reel-audio/analysis-venv/bin/python # 레퍼런스 스타일 분석 (scripts/setup_audio.sh --analysis)
기본 도구: HyperFrames (Apache-2.0, [email protected] 고정). Remotion (4.0.539)은 패리티
빌드로 유지됩니다. Remotion은 개인 및 최대 3명의 회사에 무료입니다. 더 큰 회사는 상업적 사용을 위해 유료 회사 라이선스(remotion.pro/license)가 필요합니다. HyperFrames에는 그러한 라이선스 조건이 없습니다.
워크플로우
- 설정 (첫 번째 패스).
$SK/scripts/new_reel.sh <reel.mp4> <workdir>단어 타임스탬프(large-v3)로 전사하고, 0.5초마다 얼굴 박스(faces_src.json)와 샷 컷(cuts.txt)을 감지하고,overlays.example.json을<workdir>/overlays.json으로 복사한 후 중지합니다. overlays.json작성. 먼저words_raw.json을 읽으십시오.corrections: 토큰 시퀀스로 브랜드 이름 수정, 예:["Ackme"]→"Acme",["re","-motion,"]→"Remotion,",["Acme","Voice."]→"Acme Voice.". 브랜드 쌍을 하나의 토큰으로 결합하면 한 캡션 페이지에 유지됩니다. 외국어 줄은 정확히 말한 그대로 유지합니다(예: "Même voix, autre langue.").sansWindows: B-roll 컷어웨이, 테이크오버 및 promptDemo 범위의[시작, 끝]초. 거기의 캡션은 굵은 산스(동일한 75% 레인)로 전환됩니다.overlays: 아래 스타일 사양 및 그래픽 계획 참조. 시간은 단어 타이밍에서 가져온 초 단위입니다.sponsored: true: 유료 또는 브랜드 릴의 경우. 데모-비트 규칙(후원 릴 아래)과 확인 경고를 활성화합니다.
- 두 프로젝트 빌드.
$SK/scripts/new_reel.sh <reel.mp4> <workdir> <workdir>/overlays.json - 렌더링 전에 확인.
cd <workdir>/hyperframes && npx [email protected] snapshot --at 2.5,20,30 --no-end(또는remotion/디렉토리에서npx remotion still Reel x.png --frame=N --scale=0.5) - 렌더링. Chrome이 필요하므로 Bash 샌드박스 외부에서 실행하십시오(
dangerouslyDisableSandbox). 샌드박스 내부에서는 Chrome이 Mach-port 조회 시 중단됩니다.<workdir>/hyperframes/render.sh <out>_captions_hyperframes.mp4는 1080x1920 레이아웃을 2160x3840으로 2배 업스케일하여 CRF 16, faststart로 렌더링합니다.<workdir>/remotion/render.sh <out>_captions_remotion.mp4는 동일하게--scale=2, CRF 16, AAC 192k 및 faststart로 렌더링한 후scripts/repair_remotion.py를 실행합니다(주의사항 참조).
- 검증.
$PY -I $SK/scripts/verify.py <reel.mp4> <out.mp4> <workdir>/edit.json <workdir>/faces_src.json <workdir>/qc <label>(프레임, 손상된 프레임, 가독성, 카드 가장자리 또는 CTA 제안이 실패하면 종료 코드 1과 FAIL 출력; 60초 4K 릴에서 약 9분 소요)- 프레임 수와 지속 시간이 소스와 일치하는지 확인합니다.
- 모든 프레임에서 손상(잘못된 비디오 프레임 또는 검은 타일)을 검사합니다.
corrupt_frames는 0이어야 합니다. - 5개의 캡션 페이지를 스팟 체크합니다: 페이지가 시작되기 1프레임 전에 밴드가 비어 있어야 하고, 2프레임 후에 채워져 있어야 합니다.
- 모든 오버레이 아래에서 얼굴 박스 픽셀 변화를 측정합니다. 전체 프레임 테이크오버 및 promptDemo 카드를 제외하고는 약 0이어야 합니다(이것들은 의도적으로 얼굴을 가리므로 얼굴, 손상 프레임 및 가독성 검사에서 제외됩니다).
demo_beats(promptDemo 오버레이 또는"demo": true인 오버레이)를 나열합니다.edit.json에sponsored: true가 있고 데모 비트가 2개 미만이면 WARN을 출력하고warnings에 추가합니다(하드 실패는 아님; 릴을 수정하거나 보고서에 이유를 설명하십시오).- BEFORE/AFTER 구분자 (v7, 경고). 각 promptDemo 이전 -> 이후 행 쌍에 대해
before_after: 두 클립이 공유하는 단어, 편집의 간격, 렌더링에서 측정된 무음, 그리고 편집에 전환 밴드와 전환 SFX가 있는지 여부를 보고합니다(build_editba). 이 모든 것(간격 >= 400ms, 밴드, SFX) 없이 단어를 반복하는 쌍은 WARN을 출력합니다: 구분자 없는 반복된 줄은 편집 결함으로 읽힙니다(promptDemo 참조). - CTA 제안 (v7, 하드 체크).
offer가 있는cta는 완전히 보여야 하며 >= 2.5초, >= 40px(360px 폰에서 13+ px), 실제로 그려져야 합니다(밴드의 픽셀 변화).<label>_offer_mobile.jpg는 폰 크기로 보여줍니다; 확인하십시오.offer가 없는 CTA가 있는 후원 릴은 WARN을 받습니다. - 폰 크기에서의 가독성: 8개의 캡션 페이지를 360px 너비로 다운스케일하고 획 두께, 텍스트 높이 및 아웃라인 헤일로(글리프 휘도에서 주변 링을 뺀 값)를 측정합니다. 최소값: 획 >= 4.0px, 높이 >= 28px, 헤일로 >= 130.
legibility_ok는 true여야 합니다.<label>_mobile.jpg는 크롭을 보여줍니다; 확인하십시오. - 모든 오버레이의 중간에 있는 하나의 스틸로 연락처 시트를 작성하고 동기화 크롭 시트를 작성합니다. 보고하기 전에 둘 다 여십시오.
- 음악 + SFX (기본 스테이지;
--no-music또는MUSIC=0으로 건너뛰기).<workdir>/music_plan.json을 작성하십시오(첫 번째 패스에서music_plan.example.json에서 복사됨; 기본 스타일 프리셋steady-funk-bed사용; 아래 음악 및 사운드 디자인 참조), 그런 다음$SK/scripts/music_stage.sh <out_hyperframes.mp4> <workdir> <out>_music.mp4이것은 음성 아래에 배경음과 SFX를 믹싱하고, 비디오 스트림 복사(재인코딩 없음)로 영상에 먹싱하고 오디오를 비디오 길이에 맞게 자르고,<out>_music_mobile.mp4폰 복사본을 만들고(MOBILE_OUT=으로 다른 위치에 배치),music_verify.py를 실행하며, 계획의 프리셋에 대한 스타일 검사를 포함합니다. PASS를 출력해야 합니다. 기존 출력을 덮어쓰지 않습니다(FORCE=1로 허용). 또한 음악 아래에서 음성이 6dB 미만인 모든 문장을 실패로 처리합니다(voice_over_music보고서,--min-voice-over-music): 중요한 것은 모든 라인이 잘 들리는지 여부입니다. 배경음은 음성 아래 약 13dB의 꾸준한 언더킹되지 않은 그루브이므로, 섹션 평균이 통과하더라도 하나의 조용한 문장이 그 안에 빠질 수 있습니다. talking-head-edit 음성 레벨링 또는 세그먼트별 게인으로 상위에서 실패를 수정하고, 전체 배경음을 낮추지 마십시오. 일반적인 통과 인터뷰 릴은 최소 11.2dB, 중앙값 14.1dB로 측정되었습니다.<workdir>/qc/music_sections.png를 여십시오. 첫 번째 실행은~/.cache/reel-audio/venv를 생성합니다(scripts/setup_audio.sh). - 폰 복사본 (전송용, 음악 스테이지를 건너뛴 경우):
ffmpeg -i <out.mp4> -vf scale=720:1280:flags=lanczos -c:v libx264 -preset slow -crf 22 -maxrate 2800k -bufsize 5600k -pix_fmt yuv420p -c:a copy -movflags +faststart <out>_mobile.mp4(60초에 약 14-19MB, 25MB 제한 미만). 마스터링된 오디오를 복사하고 절대 재인코딩하지 마십시오: 두 번째 AAC 인코딩(128k)은 한 릴의 실제 피크를 -1.3dBTP에서 -0.7dBTP로 높였습니다.
스타일 사양 (레퍼런스 릴 기준)
아래 모든 크기는 1080x1920 디자인 공간(2배 렌더링) 기준입니다. 공유 CSS는 templates/style.css입니다.
- 캡션 (v2: v1 캡션은 얇은 흰색 선으로 폰에서 읽기 어려웠습니다. 더 굵고, 더 크고, 아웃라인 처리된 것이 기본입니다.)
- 페이지당 한 단어, 가끔 두 단어: 짧은 기능어는 이웃 단어와 결합하고 브랜드 쌍은 붙입니다.
- 텍스트는 말한 대로 대소문자와 구두점을 사용합니다("content.", "Then"). 절대 대문자로 바꾸지 마십시오. 단어별 강조 없음: 페이지당 1-2단어로는 노이즈만 추가합니다.
- 글꼴: DM Serif Display (번들,
@fontsource/[email protected]고정, OFL) 136px, 흰색. 절대 캡션에 Instrument Serif regular와 같은 얇은 세리프로 돌아가지 마십시오. Instrument Serif는 종이 또는 빨간색 카드 타이틀용으로 유지됩니다. - 아웃라인: 단어의 스트로크 복사본(
data-t가 있는::before,-webkit-text-stroke: 6px, 따라서 글리프 외부 3px)을 거의 검은색(86%)으로 채우기 뒤에 그려서 글자를 얇게 만들지 않습니다. 그림자: 0 0 3px, 0 5px 12px 및 0 14px 34px, 모두 어두운 색상. - 맞춤:
build_edit.py는templates/fonts/caption_metrics.json에서 페이지당fs를 설정하여 페이지가 820px를 초과하지 않도록 합니다(예: "automatically."는 127px). 글꼴이 변경되면scripts/caption_metrics.py로 메트릭을 다시 생성하십시오. - 배치: 높이의 75%(y=1440)에 중앙 정렬된 하나의 레인, 화자의 손과 마이크 아래, 하단 20% UI 위. 클로즈업에서만 턱 + 6%(최대 76%로 제한)로 떨어집니다. 일반적인 책상 설정에서 손은 55-72%에 위치하므로 "턱 아래" 레인(60%)은 손에 놓입니다.
- 애니메이션: 4프레임 팝(scale 0.86→1, y 14→0, 페이드)이 한 프레임 일찍 시작되어 첫 프레임에 단어가 보입니다.
- 페이지는 단어의 시작 프레임에서 정확히 시작하여 다음 페이지까지, 또는 일시 정지가 있으면 단어 끝 + 0.2초까지 유지됩니다.
- B-roll 및 테이크오버 캡션: Inter 900, 120px, tracking -0.03em, 동일한 아웃라인 및 75% 레인.
- 타이틀 펀치 카드 (
titleCard, 후크 구문용)- 벽돌색
#B23A2E박스, 너비 810px(75%), 상단 y=190. - 위쪽 줄: Anton ALL CAPS 118px. 아래: 흰색 Instrument Serif 부제목 62px.
- 하단은 프레임 높이의 약 23%에 위치합니다. 이것은 의도적으로 레퍼런스(상단 가장자리 22-28%)보다 높습니다. 얼굴이 약 26%에서 시작하기 때문입니다.
- 벽돌색
- CTA (
cta)- 흰색 이탤릭 세리프 "Comment"(82px) 위에 빨간색 박스 안의 Anton 키워드(196px, 예: "GUIDE"). 타이틀 카드와 동일한 상단 밴드.
- 박스는 킥커 후 3프레임에 나타납니다.
- 제안 라인 (
offer, 후원 릴, v7): 종이 카드에 턱 아래 브랜드 제안, 예: "내 링크를 사용하여 무료 14일 체험." 브랜드 자체 표현을 사용하십시오.\n은 줄 바꿈을 설정하고, ALL-CAPS 단어("FREE")는 흰색-빨간색 박스를 얻습니다. "Comment / WORD"는 주요 요소로 남습니다. 제안은 지원 라인입니다.build_edit.py는offerF(offerAt에서 파생, 기본값 CTA 시작 + 10프레임),offerY(CTA 창에 걸쳐--faces에서 턱 + 3%, 높이의 55-60%로 유지, 약 1385px에서 캡션 잉크 위),offerFs(Inter, 720px에 맞춤, 최대 46px; 40px 미만에서 경고)를 파생합니다. 카드는 780px 너비(x 150-930, 오른쪽 UI와 겹치지 않음)이고 -1.5° 기울어져 있습니다. - 제안은 완전히 화면에 >= 2.5초 표시되어야 합니다. 릴이 CTA를 말한 후 너무 빨리 끝나면 마지막 프레임을 유지하십시오:
$SK/scripts/hold_end.sh <reel.mp4> <frames> <reel_hold.mp4>는 컷을 스트림 복사하고, 마지막 프레임의 N개 인코딩된 복사본을 디지털 무음과 함께 추가하고, 음성이 샘플 동일하게 디코딩되는지 확인합니다. 릴이 음악 비트 직전에 끝나도록 N을 선택하십시오(비트 k = k * 60 / bpm,cue_at0), CTAend와 음악 계획 섹션end를 새 길이로 설정하고, 새--frames로 build_edit를 실행하십시오. 배경음은 유지 아래에서 재생되고 마지막 프레임과 함께 잘립니다(예: 32프레임, 68.2초에 끝나며, 110 BPM 배경음의 비트 125(68.207초) 직전; 제안이 완전히 3.2초 표시됨).
- 화면 테이크오버 (
takeover, 도구 또는 제품 언급용, 1.5-3초 유지)- 전체 프레임 진한 빨간색
#8E1F17과 미묘한 8x14 밝은 빨간색 격자. - 흰색 둥근 검색 필(왼쪽 돋보기; 오른쪽 마이크 및 렌즈)의 굵은 이탤릭 쿼리가 14프레임에 걸쳐 입력됩니다.
- 그 아래, 도구 이름(세리프 128px), 한 줄 설명, 빨간색 파형 및 2-3개의 칩이 있는 흰색 둥근 카드.
- 절대 실제 제품 UI를 가짜로 만들지 마십시오. 텍스트만 있는 중립 카드를 사용하십시오. 음성은 그 아래에서 계속됩니다.
- 전체 프레임 진한 빨간색
- 떠 있는 카드 (
floatCard, 통계, 팁 또는 레이블용; 선택적kicker,width)- 종이
#FBF7F1카드, 너비 470px, 상단 y=200, 왼쪽 또는 오른쪽. ±3-4° 회전, 깊은 그림자. - 내용은 선택적 킥커 + 큰 Anton 숫자 + 세리프 레이블 + 작은 대문자 줄이거나 플래그 변형:
flag: "es"(킥커 + CSS 플래그 + 단어) 또는flag: "us-es"(킥커 "동일한 음성, 다른 언어" + 미국 플래그 → 스페인 플래그 + 단어). - 이모지 플래그는 CSS로 그려지므로 이모지 글꼴에 의존하지 않습니다.
- 종이
- 단계 목록 (
steps): 상단의 종이 카드(y 150)에 빨간색 킥커와 번호가 매겨진 행(DM Serif 54px). 각 항목에는 자체at시간이 있으며 화자가 말할 때 나타납니다. 현재 숫자는 빨간색이고 이전 행은 흐려집니다. 화자가 "세 단계", "첫째... 그 다음"이라고 말할 때 사용하십시오. - 이전 vs 새 분할 (
split): 상단에 두 개의 기울어진 창이 나란히, 어두운 "예전 방식"(취소선)과 빨간색 "새 방식". 새로운 창은...