세로 릴 비디오 스튜디오 (프로)
엔드 투 엔드: (첫 실행: 사용자에게 핸들/워터마크/CTA/음성 요청) → 주제 → 조사 → 초안 → 승인 → 음성 해설 → 타이밍 → Remotion 장면 → 렌더링 → 릴 내보내기 → QA → 커버 + 캡션 → 전달.
이것은 vertical-reels-video-studio (기본)의 더 완전한 버전입니다. 브랜드 설정은 brand.config.json에 저장되며 (src/brand.ts에서 읽고 composition에 brand prop으로 전달).
0a. 첫 실행: 사용자에게 그들의 설정 요청 (기본값 사용 금지)
첫 번째 비디오 전, brand.config.json이 없거나 "configured": false이거나 여전히 @yourhandle을 포함하는 경우,
사용자에게 (한 번에 한 질문씩) 물어보고 답변을 brand.config.json에 저장합니다:
- 소셜 핸들: Instagram, Threads, TikTok, X (사용하는 모든 플랫폼).
- 워터마크 텍스트 (표시될 정확한 텍스트, 예:
@yourhandle또는@ig / @x) 및 위치 (bottom-center,bottom-left,top-left,top-right). - CTA 텍스트와 언급하는 핸들.
- 음성: 사용자의 ElevenLabs 음성 ID + 모델 + 언어, 또는 "직접 녹음하겠습니다". API 키는
ELEVENLABS_API_KEY시크릿으로만 요청합니다. - 언어와 톤; 음성이 사용자의 이름/핸들을 어떻게 발음해야 하는지.
그런 다음 "configured": true로 설정합니다. 핸들을 절대 임의로 만들지 말고, 다른 사람의 핸들(이 키트 작성자 포함)을 재사용하지 말며, 여전히 @yourhandle이라고 표시된 워터마크를 렌더링하지 마십시오.
0b. 브랜드 설정 (brand.config.json, 사용자 답변으로 채워짐)
| 키 | 플레이스홀더 | 비고 |
|---|---|---|
| 핸들 | {{IG_HANDLE}}, {{THREADS_HANDLE}}, {{TIKTOK_HANDLE}}, {{X_HANDLE}} | handles.*, 사용자 자신의 것 |
| 워터마크 | {{WATERMARK}} + 위치 | watermark.text / watermark.position, 사용자가 제공한 정확한 텍스트; 장면에 하드코딩 금지 |
| 언어 / 톤 | {{LANGUAGE}}, {{TONE}} | 예: 캐주얼 인도네시아어 gua/lu, 이모지 최소화 |
| 발음 이름 | {{SPOKEN_NAME}} | 음성이 핸들을 발음하는 방식 (예: @janedoe_에 대해 "Jane Doe"). 캡션은 실제 핸들을 표시합니다 |
| 고지 사항 | {{DISCLAIMER}} | 금융 주제의 경우, 예: "교육 목적, 재정적 조언 아님" |
| 음성 | {{VOICE_ID}}, {{TTS_MODEL}}, {{LANGUAGE_CODE}} | voice.*, 사용자의 선택 (또는 직접 녹음) |
| API 키 | env ELEVENLABS_API_KEY | 절대 인쇄, 로그, 커밋 금지 |
| CTA | {{CTA}}, {{CTA_HANDLE}} | cta.text / cta.handle, 사용자에게 질문함 (예: "더 보려면 {{CTA_HANDLE}} 팔로우", "TUTORIAL 댓글") |
| 하드 규칙 | {{HARD_RULES}} | 조롱하지 않을 브랜드, 흐리게 할 이름, 절대 말하지 않을 단어 |
| 렌더 장치 | {{RENDER_DEVICE}} | GPU 머신 또는 CPU. 실제로 사용된 장치를 항상 보고 |
1. 조사 및 초안 (오디오 없음, 렌더링 없음)
- 모든 주장을 1차 출처(공식 문서/보도자료, 작성자 본인의 게시물, 레지스트리, 날짜가 있는 스크린샷)로 사실 확인합니다. 임원 게시물은 공식 성명으로 간주합니다. 추정치는 (
ESTIMATE · not official)로, 주장은 (ALLEGED)로 표시합니다. 확인할 수 없는 것은 부드럽게 표현하는 대신 삭제합니다. - 비디오당 하나의 스토리, 일상적인 단어, 느린 속도. 제품명은 화면에 표시하고, 음성 해설에는 넣지 않습니다.
- 2~4개의 후크 옵션(H1, H2, …) 제공: 이유/방법 질문 또는 대담한 대비. 사용자가 선택하도록 합니다.
- 시간 표:
time | on-screen | VO. 목표 45~65초, 최대 90초 (수정에도 여유 있도록 ≤ 88초 목표). factcheck.md(주장 → 출처 → 상태) 및sources.md작성.- 초안을 보내고 승인을 기다립니다. 사용자의 "렌더링하지 마"는 사용자가 시작을 허가할 때까지 최종 결정입니다.
2. 음성 해설 (ElevenLabs)
- 두 스크립트:
script-display.txt(캡션 표시용) 및script-tts.txt(음성용 철자 표기). display↔TTS 매핑 유지. - 발음 (
docs/VOICEOVER.md참조): 영어 발음을 위해 점이 있는A.I.; 비영어 VO에서는 티커를 문자별로 (ETH →E, T, H); 숫자는 단어로; 영어 용어는 일반 영어 철자로 (하이픈 재철자 없음); 모음 앞 최종 /t/ 뒤에 쉼표; 브랜드 이름은 테스트에서 도움이 된다고 입증된 경우에만 재철자. - 사후 처리
atempo1.05 (빠른 콘텐츠의 경우 1.1). 음량 -14 LUFS 통합, ≤ -1 dBTP. - 중복 라인 없음. 라인이 후크 또는 이전 비트를 반복하면 잘라내거나 다시 표현합니다.
- 먼저 문자 할당량을 확인합니다. 실패한 라인만 다시 음성 적용 (연속성을 위해
previous_text전달).
3. 타이밍
- TTS 정렬의 단어 타임스탬프 (템포 팩터로 나누기) 또는 faster-whisper →
timing.json{duration, phrases:[{s,e,words:[{w,s,e}]}], scenes:[{id,start}]}(scripts/build-timing.py). - 재철자된 토큰을 표시 단어로 다시 병합 (
A.I.→AI,E, T, H→ETH). 그렇지 않으면 캡션이 늦게 시작됩니다. - 장면은 음성 단어에 키 지정:
wt(scene, word)→ 해당 단어가 시작하는 프레임.
4. 모션 스타일 (Remotion, 1080x1920, 30fps)
룩: 베이스 #0A1016, 크림 #EFE6D2, 앰버 #FFB000, 레드 #E2553F, 그린 #7BD88F. @remotion/google-fonts를 통한 폰트: Big Shoulders 800 (헤드라인), Plus Jakarta Sans (본문/캡션), JetBrains Mono (칩/코드).
레이아웃: 중요한 콘텐츠 y 200~1500. 푸터 클러스터: 가라오케 캡션 y 13101353, 워터마크 (사용자가 하단을 선택한 경우) y 14271446, 진행률 ~y 1474, 모두 x 960 왼쪽 (Reels는 오른쪽에 버튼을 그림).
빈 프레임 없음: 후크가 프레임 0에서 읽을 수 있어야 함; 시작과 끝은 중간만큼 가득 차야 함 (히어로 이미지, 프리젠터, 칩), 절대 빈 배경에 외로운 라인이 아니어야 함.
이징 헬퍼 (src/motion/ease.ts):
const clamp01=(x:number)=>Math.max(0,Math.min(1,x));
const P=(t:number,a:number,b:number)=>clamp01((t-a)/(b-a));
const eOut=(x:number)=>1-Math.pow(1-x,3);
const eIn=(x:number)=>x*x*x;
const backOut=(x:number,s=1.70158)=>1+(s+1)*Math.pow(x-1,3)+s*Math.pow(x-1,2);
const sec=(f:number,at:number)=>(f-at)/30;
const ap=(f:number,at:number,d=0.3)=>eOut(P(sec(f,at),0,d));
const pop=(f:number,at:number)=>Math.max(0,backOut(P(sec(f,at),0,0.35),2.2));
const punch=(f:number,at:number)=>{const t=sec(f,at);if(t<0)return 1;return 1+0.12*eOut(P(t,0,0.2))-0.06*eOut(P(t,0.2,2.5));};
const shake=(f:number,at:number)=>{const t=sec(f,at);return t<0||t>0.4?0:14*Math.exp(-t*10)*Math.sin(t*70);};
무브: 키네틱 타입 (단어가 VO 시간에 맞춰 착지, scale(0.6+0.4*pop), 0.25초에 걸쳐 ±4° 안정화, 강세 단어는 더 크게 + 앰버/레드), 주요 이미지에 줌 펀치, 원형 마스크 공개, 줌-스루 전환 (스케일 1→4.2 약 9프레임에 걸쳐, 다음 장면 1.3→1), 회전 스탬프 및 모노 칩, 스크린샷의 빨간색 강조 상자, 단계 카운터, 가라오케 캡션 (현재 단어 앰버 + 1.08×), 흔들림이 있는 CTA 팝, VO 아래의 whoosh/pop SFX. 약 1.5~3초마다 한 비트.
비디오 클립: 각 <OffthreadVideo>를 <Sequence from={at}>로 감싸고 startFrom을 상대적으로 설정합니다. 그렇지 않으면 클립이 마지막 프레임에 고정되어 얼어붙은 것처럼 보입니다. 긴 비트를 위해 짧은 클립을 반복합니다. 클립은 첫 번째 사용 가능한 프레임에서 시작합니다.
오디오 전환: 오프닝이 나레이션 전에 라이브 오디오(노래, 클립)를 사용하는 경우, 사일런스로 페이드 아웃하고 첫 번째 VO 단어 전에 약 0.3~0.5초(플래시/후시 전환)를 남겨두어 마스킹되지 않도록 합니다.
선택적 프리젠터(마스코트) 립싱크 포함
- 모든 비디오에서 일관된 캐릭터 정체성. 별도 레이어: 몸통 (입 닫은 상태 페인트 제거), 코트 가장자리 아래 어깨 피벗의 팔, 정적 어깨 캡, 입 스프라이트
closed/half/open/wide/round. - 루프가 아닌 VO wav로 입을 구동:
scripts/build-mouth-track.py→ 프레임별 상태 (침묵 및 끝 유지에서 닫힘, 최소 2프레임 유지). 팔을 리그 범위로 고정; 전체 이미지 바운스만으로는 충분하지 않습니다. - 화면에 있는 동안에만 프리젠터를 장착; 커버는 정적 닫힘 입 몸통을 사용합니다.
5. 렌더링
- 사용 가능한 경우 GPU 머신 선호 (Remotion
--hardware-acceleration,encodingBufferSize/encodingMaxRate없는 설정, 이들은 필요한 NVENC를 깨뜨림); 허용된 경우에만 CPU로 폴백. 항상 어떤 장치가 렌더링했는지 말합니다. - 원시 렌더링:
remotion.config.ts에서yuv420p+bt709, 그런 다음 Reels 패스.
6. Reels 안전 내보내기 (scripts/reels-export.sh, docs/REELS_SAFE_EXPORT.md에 자세히)
1080x1920 SAR 1, H.264 High level 4.1, yuv420p TV 범위, BT.709 태그, CFR 30, GOP 60 닫힘, 10 Mbps (최소 8, 최대 12), 투패스 loudnorm -14 LUFS / -1.5 dBTP, AAC 192k 48 kHz 스테레오, +faststart, < 90초. 또한 40MB 미만의 작은 미리보기 (scripts/make-preview.sh).
7. QA (필수, 전달 전)
- Whisper로 최종 MP4 확인 (
scripts/whisper-check.py): 잘못된 발음, 말더듬, 잡음, 중복 라인, 모든 장면의 첫 단어 들리는지. - 모든 장면 경계에서 연락처 시트 생성 (
scripts/contact-sheet.sh): 글리치, 겹침, 잘린 텍스트, 안전 영역, 고정된 클립, 빈 시작/끝, 워터마크 존재,brand.config.json과 일치하고 정확히 철자 확인. scripts/qa-check.sh: 코덱/프로파일/레벨, pix_fmt, 범위, 색상 태그, CFR, AAC 48k, moov가 mdat 앞에, 지속 시간 < 90초, -14 LUFS 확인.- 수정 및 재렌더링. 수정 시 이전 버전 유지.
8. 항상 비디오와 함께 전달
- IG (후크, 본문, CTA, 가벼운 해시태그), Threads (더 짧고 해시태그 없음), TikTok용 캡션, 그리고
.srt파일. - 네 가지 커버 A–D: 1080x1920 + 1080x1350 그리드, 중앙 1080x1080 내부에 주요 텍스트; 후크 하나, 주요 사진 하나, 최대 2~3개 숫자 카드; 연락처 시트 + 사용자 선택.
- 출처 크레딧 및 사실 확인 파일.
videos-log.md의 한 줄: 제목, 파일, 지속 시간, 음량, 장치, 출처, 상태 "게시되지 않음".
규칙
- 절대 게시, DM, 업로드 또는 구매하지 않음. 파일 전달.
- 조작된 사실, 스타, 가격 또는 결과 없음. 오픈소스 작성자 화면에 크레딧.
- 실제 사진, 로고 및 클립만; 실제 사람의 AI 생성 얼굴 없음. 목업은
illustration표시. - 권한 있는 미디어만 사용; 음악이나 클립이 저작권이 있는 경우 사용자에게 알림 (음소거/클레임 위험).
- 파일에 비밀 없음. 마지막에, 자체 메시지로 질문.