Communitygithub.com

Visual Guide Video

영상(mp4)을 분석해 타임라인 파일(timeline.py)을 작성하면, AI 엔진이 코드로 모든 연출·배경음·효과음을 렌더링해 해설·하이라이트·광고 영상을 만듭니다. 외부 편집 툴 없이 텍스트로 영상을 편집하는 혁신적인 방식입니다.

Visual Guide Video 是什么?

Visual Guide Video는 AI 에이전트가 영상(mp4)을 분석하고, 타임라인 파이썬 스크립트(`timeline.py`)를 작성하여 자동으로 연출된 해설·하이라이트·광고 영상을 생성하는 전문 스킬입니다. 화면 녹화(줌인, 클릭 리플, 풍선 도움말, HUD), 게임 플레이(돋보기 확대, 타격감, 슬로모션, 정지 화면, 팝업 텍스트, HP 게이지 분석), 브이로그/애니메이션(대상 추적 말풍선, 스티커, 색보정, 배속), 광고/홍보/여행 필름(원본 글씨 지우기, 다국어 타이포그래피, 먹물 전환, 빛 번짐, 레터박스) 등 다양한 영상 유형에 맞춰 프로필을 적용합니다. 또한 신스로 합성한 배경음(pop, epic, chill, cute, zen 국악풍), 효과음, 원본 소리, 선택적 성우 내레이션(TTS)을 믹싱합니다. 지원하는 플랫폼은 Claude Code, Cursor, Codex 등이며, 파이썬 환경과 ffmpeg만 있으면 실행 가능합니다. 이 스킬의 핵심은 '텍스트로 영상을 편집'하는 것으로, 사용자는 분석 결과를 바탕으로 타임라인 파일의 핵심 순간(시각, 좌표, 문구)만 채우면 검증된 연출 구조가 자동 생성됩니다. 커스텀 훅을 통해 새로운 효과도 자유롭게 추가할 수 있어, 기존 영상 편집 워크플로우를 완전히 대체할 수 있습니다.

兼容平台✓Claude Code~Codex CLI~Cursor
npx skills add bitlife70/visual-guide-video

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Visual Guide Video 是做什么的?

영상을 분석해 타임라인 파일 하나(timeline.py) 를 작성하면, 엔진이 모든 연출·음악·효과음을 코드로 렌더링한다. 외부 편집 툴이나 음원 파일은 쓰지 않는다.

SKILL_DIR = 이 SKILL.md 가 있는 폴더. 스크립트는 python "$SKILL_DIR/scripts/<name>.py" 로 실행한다.

0. 준비

pip install -r "$SKILL_DIR/requirements.txt"   # opencv-python imageio-ffmpeg numpy scipy pillow edge-tts

ffmpeg 는 imageio-ffmpeg 번들을 쓴다. 한글·이모지 폰트는 OS 기본을 자동 탐색한다(VGUIDE_FONT_BOLD/REGULAR/EMOJI 로 지정 가능). 작업 폴더는 영상 옆에 둔다: project/timeline.py, 산출물 project/build/, project/output/.

1. 영상 유형 판별 → 프로필 선택

python "$SKILL_DIR/scripts/analyze.py" VIDEO --out build/analysis

콘솔의 유형 추정 과 build/analysis/sheets/*.jpg 를 Read 로 직접 보고 유형을 정한다. PROFILE 하나로 기본값이 바뀌고, timeline.py 에 적은 값이 항상 우선한다.

PROFILE대상기본값핵심 연출
screen화면녹화·튜토리얼·데모pop 음악, 원본 소리 끔, 진행 바SHOTS 줌, CLICKS, LINKS, HIGHLIGHTS, CARDS, HUD, FLOW
game게임 플레이·보스전·하이라이트epic 음악(작게), 원본 소리 켬, cinematic 색보정, 30fpsMAGNIFY, IMPACTS, SPEED/FREEZE, POPS, CALLOUTS(@트랙), 게이지 분석
vlog일상·여행·리뷰chill 음악, 원본 소리 켬, warm 색보정CALLOUTS, STICKERS, SPEED(배속 이동), 자막, GRADES
anim애니메이션·캐릭터 영상cute 음악, vivid 색보정POPS(funny), STICKERS, CALLOUTS, FREEZE
promo광고·홍보·여행·브랜드 필름epic 음악(크게), 원본 소리 끔, 30fpsTYPE(광고 타이포·낙관), CLEANUP(원본 글씨 지우기), INK 전환, GLOWS, LETTERBOX, 계절 파티클, zen 음악 arc

유형마다 무엇을 설명할지가 다르다:

  • screen: "지금 어디를 누르고 무엇이 바뀌는가" → 클릭 지점 줌, 바뀐 패널 화살표, 상태 카드.
  • game: "무슨 일이 벌어졌나(공격·방어·피격·회복·보스 패턴)" + 재미 → 타격감, 리액션 팝업, 멀리 있는 대상 돋보기, 결정적 순간 정지 해설, 지루한 이동 구간 빨리감기.
  • vlog: "어디서 무엇을 하는가" + 감정 → 설명보다 분위기. 행사(생일·여행·졸업)의 클라이맥스를 슬로모션·파티클로 키우고, 흔들리는 이동 구간은 빨리감기, 사진 찍는 순간은 정지 + 폴라로이드, 끝은 사진 콜라주 아웃트로.
  • anim: 캐릭터 리액션 강조 → 귀여운 팝업, 스티커, 결정적 표정 정지.
  • promo: "보는 사람이 가고 싶고, 사고 싶게" → 자막 대신 짧은 광고 카피(오프닝 2줄 → 히어로 타이틀 → 장면별 챕터 → 엔드 카드), 큰 장이 바뀔 때 먹물 번짐 같은 시그니처 전환, 음악 에너지 곡선(조용 → 고조 → 절정 → 여운 → 피날레). 원본에 다른 언어 글씨가 박혀 있으면 지우고 목표 언어로 교체(국제판).

공통 편집 원칙 (사용자가 가장 좋아한 부분): 불필요한 구간(이동·로딩·카메라가 흔들리는 구간)은 빨리감기, 중요한 순간은 정지(프리즈) 해서 설명이나 장식을 넣는다. 분석 단계에서 각 구간을 "핵심 / 연결 / 군더더기"로 분류하고 시작한다.

2. 분석 — 언제 어디서 무슨 일이

events.json 의 이벤트 종류:

  • 공통: cut(장면 전환), flash(번쩍임), loud(소리 피크 = 타격음·폭발), motion(움직임 피크)
  • screen: switch(클릭·탭 전환 후보), big-change, scroll
  • 게이지(--bar): bar-drop/bar-big-drop(피격), bar-low(위험), bar-empty(사망), bar-rise(회복)

게임은 HP 게이지를 반드시 측정한다. 피격·회복·사망 시점이 프레임 단위로 정확히 나온다.

python "$SKILL_DIR/scripts/crops.py" VIDEO --t 10,30 --box 200,940,500,100 --step 25 --out build/hp.jpg   # 게이지 좌표 측정
python "$SKILL_DIR/scripts/analyze.py" VIDEO --out build/analysis --bar player:337,982,626,988 --bar boss:1015,911,1590,915
  • 게이지 박스는 바 안쪽 한 줄(높이 4~8px) 로 잡는다. 흰 게이지는 기본 light, 색 게이지는 :any.
  • bar_<이름>.png(카이모그래프: 세로=시간)를 Read 로 보고 이벤트가 맞는지 확인한다. 피격 순간 게이지가 붉게 번쩍이거나 연출로 HUD 가 사라지면 오탐이 생기므로, graph.png 와 시트로 교차 확인한다.
  • 시트는 2초 간격이다. 싸움 구간은 0.3~0.6초 간격으로 프레임을 더 뽑아 무슨 동작인지(공격/구르기/피격/변신) 직접 해석한다.

정확한 좌표: 반드시 눈금 크롭으로 측정한다.

python "$SKILL_DIR/scripts/crops.py" VIDEO --t 7.4,13.5 --box 0,760,420,240 --out build/crops.jpg  # 영역, 50px 눈금
python "$SKILL_DIR/scripts/crops.py" VIDEO --t 12 --full --out build/grid.jpg                    # 전체, 100px 격자

3. timeline.py 작성

레시피에서 시작한다. 유형에 맞는 레시피를 timeline.py 로 복사하고 [1. 채울 값](핵심 순간의 시각·좌표·문구)만 채우면 검증된 연출 구조가 자동으로 만들어진다. 그다음 미리보기를 보며 영상에 맞게 항목을 더하거나 고친다.

레시피대상채울 값
recipes/screen_walkthrough.py화면녹화 튜토리얼·데모클릭(시각·좌표·문구·바뀐 곳·카드), 강조할 영역, 자막
recipes/game_boss_fight.py게임 전투 하이라이트HP 게이지 위치, 피격(시각·남은 HP), 내 공격, 보스 다운, 회복, 사망/처치, 이동 구간, 해설 자막
recipes/event_vlog.py생일·기념일·파티 브이로그클라이맥스 시각과 대상, 흔들리는 구간, 사진 카운트다운·정지 프레임, 손님 등장, 마지막 장면
recipes/promo_shorts.py30초 세로 쇼츠 (광고 몽타주)구간 목록(원본 구간·출력 길이), 장면별 패닝, 계절 단어·챕터 문구, 전환 종류
recipes/promo_film.py광고·홍보·여행 필름오프닝 카피, 히어로·엔드 카드, 장면(구간·배속·챕터 문구·낙관·카메라·파티클·에너지·배경 소리), 먹물 전환 시각, 빛나는 대상, 지울 글씨

레시피의 기본값은 실제 영상으로 검증한 값이라 그대로 두면 예시처럼 동작한다(다른 영상에서는 반드시 다시 측정). 레시피에 없는 항목은 templates/timeline_template.py 의 전체 스키마를 참고해 추가한다. 맞는 레시피가 없으면 템플릿에서 시작한다. 작업한 영상의 timeline.py 는 그 영상 폴더에 둔다. 스킬 저장소에는 특정 영상의 타임라인(사람 이름·개인 장면·작업 내용)을 넣지 않는다 — 일반화할 만한 패턴은 레시피와 이 문서로 옮긴다.

규칙: 시각은 항상 '원본 영상 시각', 좌표는 '원본 픽셀'. SPEED·FREEZE 로 출력 길이가 바뀌어도 엔진이 알아서 변환한다. 정지 구간 안의 시각은 (원본 시각, 출력 오프셋초) 로 쓴다: (49.45, 1.6) = 49.45초 정지가 시작되고 1.6초 뒤. 정지 중에 팝업·폴라로이드·아웃트로를 순서대로 띄울 때 쓴다.

범용 요소 (모든 프로필)

항목용도
TRIM, SPEED, FREEZE구간 자르기, 배속·슬로모션(라벨 배지, 라벨 None 이면 배지 없음), 정지 화면(look desat=해설용 / photo=셔터 플래시만). 빨리감기는 자동 모션블러(SPEED_BLEND)
TRACKS움직이는 대상 키프레임. auto=True(OpenCV 추적: 사람·동물) / auto="match"(템플릿 매칭: 케이크·간판 등 형태 고정 물체, until 까지 키 하나로 추적) / follow="부모"(부모 트랙에 붙은 대상, 예: 케이크 위 촛불). 다른 항목에서 "@이름", "@이름:top" 으로 가리킨다
PARTICLES파티클 confetti/hearts/sparkle/bokeh/notes/stars/snow/petals/leaves/fireflies(palette=[6] 처럼 색 지정). 트랙·좌표에서 burst(한 번에 펑) 또는 rate(계속), 화면 전체(at="screen")
PHOTOS원본의 한 프레임을 폴라로이드로 띄우기(캡션·각도·떨어지는 등장). 정지 화면·아웃트로 콜라주용
SHOTS카메라: 좌표 줌 / "full" / "fill"(레터박스 없이 꽉 채움) / "@트랙" 추적 줌
MAGNIFY돋보기 렌즈: 멀리 있는 대상을 원형으로 확대 + 연결선 + 라벨
CALLOUTS대상을 가리키는 말풍선(트랙을 따라 움직임)
POPS팝업 텍스트 스타일 impact/danger/cool/info/funny/small/party/sweet/count(카운트다운 숫자)
STICKERS이모지 스티커(bob/pulse)
IMPACTS타격감 hit/heavy/crit/damage/block/parry: 흔들림+플래시+줌 펀치+색수차(+효과음 자동)
SHAKE, FLASH수동 흔들림·번쩍임
GRADE, GRADES색보정 cinematic/warm/cool/vivid/mono/sepia/danger/dream/night (구간별 전환)
SFX, SFX_VOLUME효과음 라이브러리: hit boom clang pop ding scratch sad_trombone heartbeat shutter slowmo crash whoosh riser party_horn twinkle confetti / stamp temple_bell ink gliss gliss_down / 길이를 받는 배경 소리 "waves:8" "wind:6" "water:6" "birds:5"
SOURCE_AUDIO원본 소리(슬로모션 구간은 피치 하강, 정지 구간은 무음, 빨리감기 구간은 fast_gain 만큼 줄임)
MUSICstyle pop/epic/chill/cute/zen, arc(zen: 장면별 에너지), start(이 시각부터 음악), drop, end(+end_fx scratch/fade/cut), volume
MASTER_GAIN_DB최종 믹스 게인(리미터 전). 휴대폰 영상은 원본이 작아서 +3~5 dB
CUSTOM_LAYERS, CUSTOM_FRAME_FX, CUSTOM_SFX지시받은 새 효과를 timeline.py 안 함수로 추가 (아래)
OUTPUT_SIZE, FPS, QUALITY출력 해상도(예: 720p (1280, 720)), fps, CRF
CANVAS, BACKDROP디자인 캔버스. 세로 쇼츠는 CANVAS = (1080, 1920) + OUTPUT_SIZE = (1080, 1920). 가로 원본은 가운데 띠로 들어가고 여백은 BACKDROP("black", "blur", dict(kind="blur", tint=(r,g,b), amount=0.5)). 화면을 꽉 채우려면 SHOTS 배율 ≈ 3.16 (= 1920 / 607.5) 로 줌하고 x 로 패닝
SPEED_RAMP배속 구간을 빈틈없이 이어 붙일 때(쇼츠 몽타주): 구간 사이에서 1배로 돌아가지 않고 이 초만큼만 부드럽게 넘어간다

광고·홍보 요소 (scripts/promo.py, 모든 프로필에서 사용 가능)

항목용도
CLEANUP원본에 박힌 글씨·도장·로고 지우기 (t0, t1, (x0,y0,x1,y1), dict(plate=(ta, tb), ref=t)). plate = 같은 장면에서 글씨가 없는 프레임 → 배경을 그대로 복원(장면이 패닝·줌하면 위상 상관으로 자동 이동 보정). mask="box" 는 상자 전체 교체(정지 배경), plate 없으면 인페인트(NS + 종이 결), live=True 는 움직이는 글씨(예: 미끄러져 들어오는 라벨, ink="light")
TYPE광고 타이포. "line"(단어별로 떠오르는 카피), "hero"(자간이 모이며 등장하는 대형 타이틀 + 부제 + 낙관), "chapter"(낙관이 찍히고 키커·괘선·제목이 이어 등장, veil 로 뒤에 안개 베일). 좌표는 1920x1080 캔버스, 색 color·가독성 halo
GLOWS해·달·조명 빛 번짐 + 렌즈 플레어(스트릭·고스트) — 트랙을 따라간다
INK먹물 번짐 전환 (t, dict(dur, at)): t 에 화면을 가장 많이 덮었다가 가운데부터 걷힌다(효과음 자동)
TYPE "slam"쇼츠용: 큰 단어가 박자에 '쾅' — 먹물 위에 그려져 화면이 덮인 순간에도 보인다(over_ink). 낙관 seal
LETTERBOX시네마 레터박스 dict(ratio=2.39, range=(t0, t1)) — 들어오고 나갈 때 부드럽게. 파티클도 띠 밑으로 가려진다

새 효과를 지시받으면 — 커스텀 훅

엔진을 고치지 말고 timeline.py 에 함수를 쓴다. ctx 에는 t(출력 시각), ts(원본 시각), raw(원본 프레임), frame(현재 캔버스 BGR), view, cv(오버레이 캔버스), tl, gfx, fx, W, H, screen("@boss"), window(t0, t1)(원본 시각 구간 → (alpha, 진행도))가 있다.

def speed_lines(ctx):                           # CUSTOM_LAYERS: 오버레이 그리기 (반환 없음 또는 새 frame)
    w = ctx.window(57.2, 58.4)
    if w:
        x, y = ctx.screen("@boss")
        for k in range(12):
            a = k / 12 * 6.283
            ctx.fx.draw_line(ctx.cv, (x + 300 * math.cos(a), y + 300 * math.sin(a)),
                             (x + 700 * math.cos(a), y + 700 * math.sin(a)), (255, 255, 255), 3, w[0] * 0.6)
CUSTOM_LAYERS = [speed_lines]

def red_pulse(ctx):                             # CUSTOM_FRAME_FX: 프레임 변형 → 새 frame 반환
    return ctx.fx._tint(ctx.frame, (255, 0, 0), 0.15) if ctx.window(76, 78) else None
CUSTOM_FRAME_FX = [red_pulse]

def boss_roar(a):                               # CUSTOM_SFX: a = dict(buf, add, lib, tl, SR)
    a["add"](a["buf"], a["lib"]["boom"]() , a["tl"].out(14.4), 0.8)
CUSTOM_SFX = [boss_roar]

자주 쓰게 되는 효과는 나중에 fx.py 로 옮겨 정식 항목으로 만든다.

레이아웃 규칙 (실제로 겪은 문제에서 나온 것)

공통

  • 이모지는 컬러로 렌더링된다. 단 ▸ ✓ ✕ 같은 기호는 □ 로 깨지므로 이모지(✅ ✖️ 👉 ⏩ ⏸)나 • → · 를 쓴다.
  • 자막은 한 줄 40자 안팎. 핵심어는 [대괄호] 로 강조. 정지 화면 해설 자막은 (tf, tf, "...") 처럼 정지 시각을 시작=끝으로 적으면 정지 동안만 뜬다.
  • 같은 순간에 팝업·말풍선·스티커를 3개 이상 겹치지 않는다. 팝업은 0.8~1.2초면 충분하다.

screen

  • 카드와 하이라이트가 겹치지 않게 시간을 나눈다(카드 → 하이라이트). 카드는 다음 클릭 줌 전에 끝낸다.
  • 줌 상태에서 하이라이트가 화면 밖으로 나가면 잘린다 → 배율 1.15~1.3.
  • 라벨 배치 "right"(화살표), "above-right"(표의 행), "below"(상단 요소). HUD 는 줌 1.12배 이상에서 미니 모드(좌측 100px).

game

  • 울트라와이드(21:9)는 16:9 캔버스에 레터박스로 들어간다. 위아래 띠에 배속 배지·자막이 들어가 액션을 가리지 않는다. 꽉 채우려면 SHOTS 에 "fill".
  • 게이지 하이라이트는 "above|nodim" — 화면을 어둡게 하면 액션이 안 보인다.
  • 줌은 1.3~1.5배까지만. 액션이 빨라서 과하면 대상이 화면 밖으로 나간다. 확대가 필요하면 MAGNIFY 를 쓴다.
  • 정지(FREEZE)는 12초, 한 영상에 34번이면 충분하다. 정지 중에는 CALLOUTS 로 "누가 무엇을" 짚는다.
  • 이동·로딩 구간은 SPEED 23배로 줄인다. 슬로모션 0.30.4배는 피격·결정타 0.5~1초에만.
  • 트랙 키프레임은 대상이 크게 움직일 때마다 찍고, 장면이 바뀌는 곳(컷)에서는 같은 값을 두 번(직전·직후) 적어 보간이 튀지 않게 한다. python "$SKILL_DIR/scripts/tracks.py" timeline.py 로 시트를 만들어 확인한다.
  • HP 이벤트로 피격 시점을 잡고 IMPACTS 를 프레임 정확도로 맞춘다. 피격 = damage/crit, 내 공격 적중 = hit/heavy.
  • 원본 게임 소리를 살리고 BGM 은 작게(volume 0.3~0.45). 사망 시점에 MUSIC["end"] + end_fx="scratch" 로 음악을 끊고 sad_trombone 같은 효과음으로 웃음 포인트를 만든다.

promo (광고·홍보·국제판)

  • 원본 글씨 지우기: 글씨가 나타나기 0.4초 이상 전/사라진 뒤의 프레임을 plate 로 고른다. 페이드 중인 프레임엔 희미한 글씨가 남아 있다 → 대비를 키운 크롭(배경 블러를 빼고 ×4)으로 확인. 지운 뒤엔 --preview 원본 해상도 크롭으로 잔상·이음새를 본다.
  • 안개·물보라처럼 형태가 계속 바뀌는 배경은 plate 가 맞지 않는다(회색 얼룩) → plate 없이 인페인트하고, 그 자리에 챕터 타이포를 veil 과 함께 얹는다.
  • 붉은 도장 감지는 진한 빨강만 잡는다(노을·주홍 하늘은 제외). 하늘이 주홍이면 상자 전체가 바뀌어 색 띠가 생기지 않는지 확인.
  • 카피는 짧게: 오프닝 24단어 × 2줄, 챕터 제목 25단어, 엔드 카드 브랜드 + 한 줄. 실제 기관·브랜드의 공식 슬로건은 쓰지 않는다.
  • 타이포는 레터박스 안쪽(위 140px·아래 140px 제외)에. 원본 글씨가 있던 자리가 대개 '비워 둔 하늘'이라 챕터를 놓기 좋다.
  • 음악: zen 은 arc 로 장면별 에너지를 정한다. 먹물 전환 시각이 마디 경계(80 BPM = 3초)에 떨어지게 장면 배속을 조정하면 전환·북·낙관이 박자에 맞는다(tl.load 로 out 시각 출력 → 배속 수정). 단계별 음량은 calm −20 / peak −12 dB 정도로 차이가 커야 절정이 산다.
  • 결정적 장면(전개되는 병풍·일출)은 0.751배, 느린 풍경은 1.52.4배. 큰 장(계절·지역) 전환에만 먹물을 쓰고 같은 장 안에서는 원본 전환을 살린다.
  • 세로 쇼츠(30초) (recipes/promo_shorts.py): 96 BPM(한 마디 2.5초)에 장면 하나씩. SEGMENTS = [(원본 시작, 끝, 출력 길이)] 로 이어 붙이고 Remap 으로 배속을 역산하면 전환이 정확히 마디에 떨어진다. 원본 전환(크로스페이드)은 0.2초로 압축해 먹물·플래시 밑에 숨긴다.
    • 첫 1초가 훅: 카피 한 줄 → 마디 1에 브랜드 타이틀 + 음악 타격. 오프닝·피날레는 띠 레이아웃(가운데 원본 + 위아래 타이포), 본편은 꽉 찬 세로 크롭 + 피사체 쪽 패닝(해·폭포·달은 가운데, 넓은 풍경은 좌→우).
    • 빨리감기 구간에선 원본 초가 짧아지므로 타이포 시각은 (TRIM[0], 출력초) 처럼 출력 기준으로 쓴다. 챕터는 pace=0.55 로 빨리 등장.
    • 파티클은 clip=True 로 컷과 함께 끊는다(꽃잎이 다음 계절로 넘어가지 않게). 쇼츠 UI 를 피해 타이포는 위 260px·아래 420px 안쪽에.

vlog (가족·행사 영상)

  • 휴대폰 영상은 흔들림이 많다. 흔들리는 이동 구간은 3~4배 빨리감기(모션블러가 자동으로 들어가 부드럽다), 원본 소리는 자동으로 줄어든다.
  • 클라이맥스(촛불 끄기·건배·골인)는 0.4배 슬로모션 + 플래시 + confetti burst + party_horn. 음악은 그 순간 시작(MUSIC["start"]) — 그 전엔 원본 소리(생일 노래·대화)를 살린다.
  • 사진 찍는 장면은 셔터가 눌린 직후의 흔들리지 않은 프레임에서 정지(look="photo")하고 폴라로이드를 띄운다. 정지 프레임은 미리보기로 선명한지 꼭 확인한다(카메라가 움직이는 프레임은 흐릿하다).
  • 스티커·팝업·하트를 얼굴 위에 두지 않는다. 얼굴 좌표를 측정해 옆이나 위 빈 공간에 둔다. 표정(메롱·윙크)을 가리키려면 스티커 대신 CALLOUTS(ring=False)로 옆에서 가리킨다.
  • 카운트다운이 화면에 보이면(휴대폰 타이머) count 팝업 3·2·1 을 그 시각에 맞추고 pop 효과음을 단다.
  • 아웃트로는 정지 화면 위에 폴라로이드 2~3장 콜라주 + 짧은 축하 문구(OUTRO 의 top 으로 위로 올리고 stats=[]).
  • 자막·성우 없이도 이야기가 보이게: 인트로 제목 + 장면마다 짧은 팝업 한 줄이면 충분하다.

4. 미리보기 반복

python "$SKILL_DIR/scripts/build.py" timeline.py --preview 3.5,7.4,26        # 원본 시각
python "$SKILL_DIR/scripts/build.py" timeline.py --preview-out 16.6,36.2     # 출력 시각 (정지·슬로모션 중간 확인)

build/preview/sheet*.jpg 를 Read 로 보고 겹침·잘림·가림·좌표 오차·글자 깨짐을 고친다. 라벨 src ↔ out 으로 시간 변환도 확인된다. 정지 구간은 원본 시각으로는 확인할 수 없으니 --preview-out 을 쓴다.

5. 오디오

  • 배경음 MUSIC["style"]: pop(126BPM 일렉트로 팝), epic(96BPM 타이코·스타카토 현·브라스·합창), chill(82BPM 로파이), cute(132BPM 마림바·피치카토), zen(80BPM 가야금·대금·장구·북·합창, MUSIC["arc"] = [(원본 시각, "calm|flow|pulse|build|peak|hush|finale")]). zen 외에는 모두 intro → A → B → build → drop → outro 구조이며 drop 초에 하이라이트가 터진다.
  • 원본 소리: game/vlog/anim 기본 켬. 성우가 말하면 함께 덕킹된다(SOURCE_AUDIO["duck"]).
  • 레벨 점검: 게임은 원본 소리가 주인공이다. 구간별 RMS 를 재서 음악이 원본보다 3~5dB 작게, 효과음은 타격 순간에만 들리게 맞춘다.
    import tl, music, build; t = tl.load("timeline.py"); m = music.build_music(t)[0] * t.music["volume"]; s = build.source_audio(t, m.shape[1])
    
  • 성우(선택) NARRATION = [(t, "문장")] (없으면 자막을 읽음). --voice edge(Microsoft 신경망, 온라인 — 문장이 Microsoft 로 전송됨을 알린다) / --voice sapi(Windows 오프라인). build/voice_report.json 에서 rate 가 +15% 를 넘거나 overflow 면 문장을 줄인다(한국어 ≈ 7음절/초).

6. 최종 렌더링과 검증

python "$SKILL_DIR/scripts/build.py" timeline.py [--voice edge] [--workers 8]

프레임을 나눠 여러 프로세스로 병렬 렌더링한 뒤 이어 붙인다(1분 1080p ≈ 2~3분, 8 workers). 백그라운드로 실행한다.

완료 전 확인 사항

  • 마지막 줄 [done] ... Ns (expected Ns), N MB 에서 길이가 일치하는지, 로그에 Traceback 이 없는지 본다.
  • 출력에서 프레임 몇 장을 뽑아 확인한다: ffmpeg -ss T -i out.mp4 -frames:v 1 f.png
  • 음악·효과음은 직접 들을 수 없으므로 구간 RMS 로 확인하고, 사용자에게 직접 들어 보라고 말한다.

파일 구성

파일역할
scripts/analyze.py메타·유형 추정·장면 전환·소리 피크·게이지 이벤트·그래프·시트
scripts/crops.py원본 좌표 눈금 크롭
scripts/tracks.py대상 추적(키프레임 보간·OpenCV), 검증 시트
scripts/remap.py시간 리매핑(TRIM·SPEED·FREEZE)
scripts/build.py미리보기 / 오디오 믹스(원본 소리 리매핑·리미터) / 병렬 렌더 / SRT
scripts/tl.pytimeline.py 로더, 프로필 기본값, 좌표·시각 변환
scripts/render.py카메라(추적·흔들림)·화면녹화 레이어·커스텀 훅
scripts/fx.py범용 효과: 색보정, 타격감, 돋보기, 말풍선, 팝업, 스티커, 배지, …

相关技能