Communitygithub.com

mhuot/프로모션-비디오-스킬

완전 오프라인 ~60초 내레이션 프로모션 비디오: Kokoro TTS + HyperFrames + FFmpeg + OpenMontage 거버넌스. 템플릿과 스킬이 스스로를 소개하는 데모 비디오 포함.

프로모션-비디오-스킬란 무엇인가요?

이 스킬은 AI 코딩 에이전트가 로컬 도구 체인만을 사용하여 완전 오프라인으로 약 60초 길이의 내레이션 프로모션 비디오를 제작할 수 있도록 설계된 에이전트 독립적인 런북(runbook)입니다. Claude Code, GitHub Copilot CLI / Microsoft Scout, Google Antigravity 등 다양한 플랫폼을 지원하며, Cursor, Codex, Windsurf 등에서도 일반 마크다운 문서로 사용할 수 있습니다. 핵심 원칙은 '스크립트를 먼저 확정하고, 모든 다운스트림 숫자는 측정된 내레이션 오디오로부터 도출하며, 추측하지 않는다'입니다. Kokoro(한국어 코드 'a' 지원)로 TTS 오디오를 생성하고, HyperFrames로 HTML/CSS/GSAP 기반의 모션 구성을 마친 후, FFmpeg로 최종 MP4를 인코딩합니다. OpenMontage는 파이프라인 거버넌스(단계 순서, 결정 로그, 게이트, 셀프 리뷰)를 담당합니다. 프로모션 비디오는 제품의 'WHY'(대상, 문제, 변화, 증거, 행동 촉구)를 판매하며, 작동 방식 설명은 최대 1비트로 제한됩니다(상세 메커니즘은 별도의 'explainer-video' 스킬에서 다룸).

지원 대상✓Claude Code✓Codex CLI✓Cursor✓Antigravity✓Windsurf
npx skills add mhuot/promo-video-skill

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

프로모션 비디오 제작 (로컬 도구 체인)

에이전트 독립적: 파일을 읽고 쉘 명령을 실행할 수 있는 모든 AI 코딩 에이전트를 위해 작성되었습니다. install.sh를 통해 Claude Code, GitHub Copilot CLI / Microsoft Scout, Google Antigravity에서 기본 지원되며, Cursor, Codex, Windsurf 등에서는 일반 마크다운 런북으로 사용할 수 있습니다.

이 도구 체인은 Idan Shimon(Microsoft, github.com/idanshimon)에 의해 처음 선보였습니다. 그의 58초짜리 개념 설명 비디오(로컬에서 AI 에이전트가 이 스택을 사용하여 $0 비용으로 제작)가 이 스킬의 모태가 되었습니다.

설치 위치를 가정하지 마십시오: SKILL.md가 포함된 디렉토리로 PROMO_VIDEO_SKILL_DIR을 설정하십시오. 디렉토리 내 scripts/에는 TTS 스크립트, 약어 발음 도우미, 고정된 TTS 의존성 파일이 있습니다. assets/에는 구성 스켈레톤, 공간 구성 요소 템플릿, 결정 로그 스키마가 있습니다. references/에는 머신당 한 번 실행하는 도구 체인 부트스트랩(install.md)이 있습니다.

핵심 원칙: 스크립트가 먼저 확정됩니다. 모든 다운스트림 숫자는 측정된 내레이션 오디오로부터 도출되며, 절대 추측하지 않습니다.

설명형이 아닌, 프로모션: 이 스킬은 WHY를 판매합니다. 대상, 문제, 변화, 증거, 하나의 행동 촉구입니다. 작동 방식('how it works')은 최대 하나의 비트만 허용되며, 사용자가 지시할 때만 사용합니다. 작동 방식을 가르쳐 달라는 요청은 동반되는 explainer-video 스킬의 몫입니다.

도구 프로필

도구위치검증된 버전라이선스역할호출 방식
OpenMontage~/OpenMontage2026-07 체크아웃AGPLv3 (도구 전용; 비디오에 포함되지 않음)파이프라인 거버넌스: 단계 순서, 결정 로그, 게이트, 렌더 후 셀프 리뷰 규율AGENT_GUIDE.md + pipeline_defs/animation.yaml을 읽을 것; 당신(에이전트)이 오케스트레이터이며, 데몬은 실행되지 않음
KokoroPyPIKokoro-82M (hexgrad), kokoro==0.9.4코드 Apache-2.0; 모델 가중치 Apache-2.0내레이션 TTS, 24kHz 모노 WAV (씬별)Python 3.12 venv; KPipeline(lang_code="a"), 음성 af_heart, speed 파라미터
HyperFrames~/hyperframes0.7.57, 소스에서 빌드Apache 2.0HTML/CSS/GSAP 구성 → 헤드리스 Chrome을 통한 결정적 MP4node ~/hyperframes/packages/cli/dist/cli.js <cmd>
FFmpeg~/FFmpeg 소스; 빌드 디렉토리의 바이너리git master (N-125608 시대)GPL 빌드 (libx264 활성화)음악 합성(aevalsrc), 인코딩, ffprobe QA, 음량, 플랫폼 패키징hyperframes 명령어보다 먼저 빌드 디렉토리를 PATH에 추가
bunnpm-global1.3.14—hyperframes 모노레포 빌드npm i -g bun (brew cask가 한 번 실패한 적 있음)
Node.jsnvm24.x (≥22 필요)—hyperframes CLI 실행—
Pythonuv 관리3.12—Kokoro 추론항상 venv (uv venv --python 3.12 .venv); black + pylint 검증 통과
espeak-ngHomebrew 또는 aptanyGPLKokoro G2P 폴백 (필수)macOS: brew install espeak-ng; Debian/Ubuntu: sudo apt install espeak-ng
gsapvendored 파일3.x gsap.min.jsGSAP 표준 라이선스구성 내 타임라인 애니메이션video/assets/에 복사 — 절대 CDN <script src> 사용 금지 (오프라인 결정성)

환경 확인 (머신당 한 번)

export FFMPEG_BUILD_DIR="${FFMPEG_BUILD_DIR:-$HOME/ffbuild}"
export HYPERFRAMES_DIR="${HYPERFRAMES_DIR:-$HOME/hyperframes}"
export PATH="$FFMPEG_BUILD_DIR:$PATH"
node "$HYPERFRAMES_DIR/packages/cli/dist/cli.js" doctor

FFmpeg, FFprobe, Node, Chrome 모두 프로덕션 전에 통과해야 합니다 (다른 doctor 행은 이 스킬이 사용하지 않는 선택적 구성 요소입니다). 이 네 가지 중 하나라도 실패하면 $PROMO_VIDEO_SKILL_DIR/references/install.md를 따르십시오. 머신당 한 번의 전체 부트스트랩: 시스템 패키지(macOS/Linux), 소스 도구 클론(OpenMontage 참조 체크아웃 포함), libx264를 포함한 FFmpeg 소스 빌드, HyperFrames CLI 빌드, 에이전트 권한 팁입니다. doctor가 이미 통과했을 때 이 파일을 로드하지 마십시오.

Chrome: CLI는 ~/.cache/puppeteer/ 아래에 캐시된 chrome-headless-shell을 자동으로 사용합니다 (없으면 한 번 다운로드). 첫 번째 TTS 실행도 마찬가지로 Python 패키지와 Kokoro-82M 가중치를 다운로드합니다. 이 일회성 다운로드 후, 합성, 검증, 렌더링, 패키징은 오프라인 경로를 사용합니다.

프로젝트 레이아웃 (비디오당 생성, 자체 git 저장소, 원자적 커밋)

<project>/
  .venv/                          # uv venv, python 3.12
  .gitignore                      # .venv/ __pycache__/ video/snapshots/ .DS_Store
  README.md                       # 제작 방법 + 재현 방법 (마지막에 작성)
  production/
    research/research-brief.md    # 출처 포함 사실 + 정직한 경쟁사 표
    proposal.md                   # 컨셉, 씬 목록, 전달 약속, 런타임 결정
    script/script.md              # 확정된 내레이션
    scene_plan/scene-plan.md      # 씬별 시각 자료 + 모션 노트
    checkpoints/decision-log.json # 추가 전용; (category, subject)가 키
    checkpoints/self-review.md    # 렌더 후 증거
    assets/audio/                 # kokoro WAV + durations.json
    renders/                      # 마스터 + 플랫폼 파생 파일
    youtube/                      # metadata.md + thumbnail.jpg
  tools/tts_generate.py           # 이 스킬에서 복사, SCENE_NARRATIONS 편집
  tools/tts_pronounce.py          # scripts/에서 복사, 약어 발음 (편집 금지)
  tools/pronunciation.local.json  # 선택적 프로젝트 사전 오버레이
  video/
    index.html                    # 구성 파일
    assets/gsap.min.js            # vendored
    assets/audio/                 # WAV 복사본 (구성 기준 상대 경로)

1단계 — 리서치 (오프라인 우선)

주제의 자체 저장소/README/문서를 조사하여 결과와 증거(숫자, 도입률, 전후 결과)를 찾고, 아키텍처는 찾지 마십시오. research-brief.md를 생성하십시오:

  • 포지셔닝 블록 (필수 — 스크립트는 이것 없이 확정될 수 없습니다). 각각 한 문장씩: 대상(누구를 위한 것인지), 문제(오늘날 그들이 느끼는 어려움), 변화(그들에게 어떤 변화가 일어나는지), 차별화 요소(이것을 선택해야 하는 하나의 이유). 이것이 메시지이며, 모든 후속 단계는 이 메시지를 따릅니다.
  • 제품 사실, 각각 출처에 대해 검증됨 — 혜택을 뒷받침하는 경우에만 유지합니다('그래서?' 테스트: 시청자가 얻는 것은 무엇인가?).
  • 경쟁사 표(약점 → 주제가 이를 어떻게 해결하는지). 정직성 규칙: 경쟁사의 실제 장점은 인정하십시오(경쟁사 열에 ✓ 표시는 당신의 신뢰도를 높여줍니다).
  • "스크립트에 사용 가능한 주장" 목록.

2단계 — 제안 + 결정

proposal.md를 작성하십시오: 포지셔닝 블록 재진술, 5~7 씬 컨셉, 목표 ≈60초, 전달 약속('모션 주도형, 슬라이드쇼 아님'), 도구 체인 표. decision-log.json에 기록하십시오 — $PROMO_VIDEO_SKILL_DIR/assets/decision-log.json의 빈 스키마에서 시작하십시오(필드: category, subject, selected, options_considered, rejected_because, confidence): pipeline_selection, render_runtime_selection (고려된 대안으로 Remotion 기록 — OpenMontage 하드 규칙), composition_mode (주요 작업에는 atelier), voice_selection, music_selection, output_profile, approval_gates, 그리고 cta_selection — 정확히 하나의 행동 촉구(저장소에 별표 / 설치 / 데모 보기 / 사이트 방문); 프로모션은 기능 목록으로 끝나면 실패합니다. 사용자의 브리핑이 선택을 고정했다면, approved_by: "user brief"를 표시하십시오. 나중에 결정을 변경했습니까? 동일한 (category, subject)로 새 항목을 추가하고 이전 항목은 절대 편집하지 마십시오.

3단계 — 스크립트 (확정 지점)

~150–155 단어 ≈ 60초 (kokoro af_heart 속도 1.1 기준). 프로모션 아크 (WHY 판매): stakes/pain 훅 → 공개(이름 + 약속하는 변화) → 시청자 세계에서의 혜택 → 증거(정직한 비교, 실제 결과) → 열망 → 결정 로그의 단일 CTA. 기능은 혜택에 대한 증거로만 나타납니다: 모든 문장은 '그래서?' 테스트(시청자가 얻는 것은 무엇인가?)를 통과해야 하며, 그렇지 않으면 다시 작성해야 합니다. 최대 하나의 how-it-works 비트만 허용되며, 사용자가 지시할 때만 사용합니다 — 메커니즘을 가르치는 것은 explainer-video 스킬의 역할입니다. 어조: 2인칭, 현재 시제, 짧고 강력한 문장("당신은 더 빠르게 배송합니다", "더 빠른 배송을 가능하게 합니다"가 아님). 약어는 스크립트와 화면 텍스트 모두에서 자연스럽게 작성하십시오("OID", "MCP", "AI"). 합성 시 tools/tts_pronounce.py는 자체 사전에서 구어체 형태(단어 vs 글자별)를 도출하며, 알 수 없는 약어는 글자별로 철자되고 보고됩니다. 선택적 tools/pronunciation.local.json에서 도메인 용어를 분류하십시오({"NASA": "word", "ECG": "letters", "NGINX": "engine X"}). 모두 대문자 강조는 피하십시오: 모두 대문자 단어는 약어로 처리됩니다. 씬당 단어 예산 ≈ 60초 중 해당 씬의 비중 × 2.55 단어/초.

4단계 — 내레이션 + 타이밍 도출 (핵심 트릭)

제공된 고정된 직접 의존성을 사용하여 프로젝트의 Python 3.12 환경을 만들고, 일반 템플릿을 복사한 후 SCENE_NARRATIONS만 편집하십시오:

uv venv --clear --python 3.12 .venv
uv pip install --python .venv/bin/python \
  -r "$PROMO_VIDEO_SKILL_DIR/scripts/tts-requirements.txt"
mkdir -p tools
cp "$PROMO_VIDEO_SKILL_DIR/scripts/tts_generate.py" tools/tts_generate.py
cp "$PROMO_VIDEO_SKILL_DIR/scripts/tts_pronounce.py" tools/tts_pronounce.py
PYTORCH_ENABLE_MPS_FALLBACK=1 .venv/bin/python tools/tts_generate.py
mkdir -p video/assets
curl -fL https://cdn.jsdelivr.net/npm/[email protected]/dist/gsap.min.js \
  -o video/assets/gsap.min.js

첫 번째 합성은 Kokoro-82M 가중치(~330MB)를 다운로드합니다. 이후 실행은 캐시를 사용하며 오프라인으로 가능합니다. 씬별 WAV + durations.json을 작성합니다. 실행에서 알 수 없는 약어 WARNING이 출력되면, 해당 토큰을 tools/pronunciation.local.json에 분류하고 타이밍을 도출하기 전에 다시 실행하십시오.

150–155 단어, 속도 1.1을 시작 추정치로 취급하고 보정값으로 사용하지 마십시오. 총 시간이 62초를 초과합니까? 속도를 올리거나 단어를 줄인 후 다시 측정하십시오.

타임라인 도출 (씬 사이 패드 ≈0.3–0.5초):

n_start[0] = 0.5                       # 도입부
scene_start[i] = n_start[i] - 0.15..0.4   # 시각 자료가 VO 바로 직전에 도착
n_start[i+1] = n_start[i] + dur[i] + 0.3..0.35
TOTAL = 마지막 n_end + 0.6..0.9 꼬리 (페이드 투 블랙)

이 숫자들은 일치해야 하는 세 곳에 입력됩니다: 씬 data-start/data-duration, <audio data-start> 값, JS const S1..Sn 타임라인 상수. WAV를 video/assets/audio/에 복사하십시오.

5단계 — 배경 음악 (다운로드 없음)

소스 빌드된 FFmpeg로 결정적 합성 패드를 생성하십시오. TOTAL_SECONDS를 도출된 구성 총 시간으로 설정하십시오. 외부 샘플이나 개인 참조는 필요하지 않습니다:

TOTAL_SECONDS=60.5
FADE_SECONDS=3.5
FFMPEG_BIN="${FFMPEG_BUILD_DIR:-$HOME/ffbuild}/ffmpeg"
FADE_OUT_START="$(awk -v total="$TOTAL_SECONDS" -v fade="$FADE_SECONDS" \
  'BEGIN { printf "%.3f", total - fade }')"
mkdir -p production/assets/audio
"$FFMPEG_BIN" -hide_banner -y \
  -f lavfi \
  -i "aevalsrc=0.07*(sin(2*PI*110*t)+0.65*sin(2*PI*110.7*t)+0.45*sin(2*PI*164.81*t)+0.30*sin(2*PI*220.9*t)):s=48000:d=${TOTAL_SECONDS}" \
  -af "highpass=f=55,lowpass=f=1200,afade=t=in:st=0:d=2,afade=t=out:st=${FADE_OUT_START}:d=${FADE_SECONDS},pan=stereo|c0=c0|c1=c0" \
  -c:a pcm_s16le production/assets/audio/music-bed.wav

희박하게 유지하십시오. data-volume="0.12..0.16"로 믹스하면 분위기로 읽힙니다. 프로모션 에너지를 위해 이 범위의 위쪽에 두되, 내레이션보다 높지 않게 하십시오. WAV를 video/assets/audio/에 복사하고 별도의 오디오 트랙을 사용하십시오.

6단계 — 구성 작성 (HyperFrames 계약)

$PROMO_VIDEO_SKILL_DIR/assets/composition-skeleton.html에서 시작하십시오(아래 모든 규칙을 구현합니다). HTML을 작성하기 전에 $HYPERFRAMES_DIR/skills/hyperframes-core/SKILL.md를 훑어보십시오. 구조: 독립형 index.html, 루트 <div data-composition-id="X" data-start="0" data-duration="TOTAL" data-width="1920" data-height="1080">, 씬은 <section class="clip" data-start data-duration data-track-index="1">, window.__timelines["X"]에 동기적으로 등록된 하나의 gsap.timeline({paused:true}), 트윈 위치 = S<i> + local_offset.

많은 디버깅 시간을 소모하는 규칙들 — 미리 준수하십시오:

  1. 모든 <video>/<audio>는 명시적이고 비어 있지 않은 id를 가져야 합니다. HyperFrames에서, id 없는 오디오는 브라우저 미리보기에서 재생될 수 있지만 SILENT로 렌더링됩니다(lint가 오류를 표시함; 무시하지 마십시오).
  2. GSAP 트윈 요소의 CSS에 초기 transform:을 절대 넣지 마십시오. 대신 tl.fromTo(el, {y:24, opacity:0}, {y:0, opacity:1, ...})를 사용하십시오; GSAP가 전체 transform을 소유합니다. CSS에서 opacity: 0만 있는 것은 .to() 전용 공개에 괜찮습니다.
  3. 배경 채움은 전체 블리드 CHILD(position:absolute; inset:0)에 넣고, 루트에는 절대 넣지 마십시오(루트 배경은 검은색으로 렌더링될 수 있습니다).
  4. 미디어 요소는 루트의 직접 자식이며, 별도의 오디오 트랙에 data-track-index를 사용합니다(예: 7=VO, 8=음악).
  5. 무한 반복 금지(repeat: -1 금지 — 유한 반복 사용, 예: 커서 깜빡임 repeat: 9, yoyo: true), Date.now/Math.random 금지, 네트워크 가져오기 금지, CDN 스크립트 금지.
  6. 모든 곳에 고유 id; transforms/opacity만 애니메이션(+ SVG 선 그리기를 위한 strokeDashoffset).
  7. 중간 씬에 나타나는 요소: 숨겨진 초기 상태 + S<i>+offset에서 트윈. fromTo는 immediateRender를 가지므로, 트윈 전 검색은 from 상태를 표시합니다 — 이것이 검색 안전을 보장합니다.
  8. :root CSS 변수의 디자인 토큰 = 테마; ground/ink/accent + 타입 스택을 교체하여 리스킨합니다. 렌더러가 번들로 제공하는 글꼴(JetBrains Mono)을 사용하십시오 — 시스템 글꼴은 어차피 대체됩니다(lint info가 매핑을 알려줍니다).
  9. 보조 텍스트는 ground 색상에 대해 WCAG AA 이상을 유지하십시오 — check는 대비에 실패하고 사용할 수 있는 접근성 색상을 출력합니다.
  10. 의도적인 오버랩/스크롤 언더: 발견 사항을 설명하지 않고 data-layout-allow-overflow/-overlap/-occlusion으로 표시하십시오.

씬 모티브 조언: OUTCOME 상태를 보여주십시오 — 시청자의 세계가 개선된 모습(전후 대비, 사라진 문제, 화면에 나타난 결과). 주제의 실제 UI/도메인(가짜 검색 팔레트, 터미널, 트리, 표)에서 뒷받침하는 모습을 혜택에 대한 증거로 가져오되, 메커니즘 투어는 피하십시오. 내러티브 아크는 템플릿을 따르지만, 모티브는 그래서는 안 됩니다. $PROMO_VIDEO_SKILL_DIR/assets/composition-skeleton.html 및 $PROMO_VIDEO_SKILL_DIR/assets/spatial-component-templates/ 아래에 있는 모티브 예제를 참조하십시오.

7단계 — 사전 렌더 검증

cd video
node "$HYPERFRAMES_DIR/packages/cli/dist/cli.js" check

모든 수정 사항을 적용하고 다시 확인하십시오. check는 lint 규칙을 실행하고 구성이 올바른지 확인합니다. 구성이 유효할 때까지 렌더링하지 마십시오.

8단계 — 렌더링

cd video
node "$HYPERFRAMES_DIR/packages/cli/dist/cli.js" render

마스터 MP4가 생성됩니다. production/renders/에 복사하십시오.

9단계 — 포스트 프로덕션 + 셀프 리뷰

checkpoints/self-review.md를 채우기 위해 OpenMontage AGENT_GUIDE.md에 있는 셀프 리뷰 규율을 따르십시오. FFprobe를 사용하여 품질, 음량, 지속 시간을 확인하십시오. 모든 것이 통과하면 YouTube 메타데이터와 썸네일을 준비하십시오.

10단계 — 최종 커밋 + README

모든 파일을 커밋하고 README.md에 제작 방법과 재현 방법을 기록하십시오. 이 프로세스는 완전히 재현 가능해야 하며, 모든 에이전트가 동일한 입력과 도구 체인을 사용하여 동일한 비디오를 생성할 수 있어야 합니다.

관련 스킬