플러그인 설치: 설정 또는 업데이트 명령 전에, 이 스킬이 HyperFrames 플러그인 내부에 있을 경우 플러그인 실행 규칙을 따르세요. 독립형 설치는 아래 업데이트 지침을 유지합니다.
첫째, 이 스킬을 최신 상태로 유지하세요 — 사용자에게 확인 후 실행:
npx hyperframes skills update talking-head-recut. 모든 것이 최신이면 빠르게 종료(no-op)되며, 그렇지 않으면 이 스킬과 의존하는 핵심 도메인 스킬을 업데이트합니다.
Talking Head Recut
Talking Head Recut은 로컬 영상을 전체 재생하면서 그 위에 시간에 맞춰 디자인된 그래픽 카드 (타이틀, 하단 서드, 데이터 콜아웃, 인용문, 사이드 패널, PiP)를 순차적으로 레이어링합니다. 카드는 말하는 내용에 동기화됩니다. 에이전트가 카드를 디자인(타이밍 + 내용)하고 각 카드의 HTML을 대화 내에서 직접 작성한 후, 단일 구성 HTML로 조합하여 hyperframes를 통해 MP4로 렌더링합니다. 고정된 아키타입 목록이나 미리 정해진 카드 구조는 없습니다. 오버레이는 실제 대본에 따라 결정됩니다.
진입점은
/hyperframes입니다. 이 스킬은 기존 토킹헤드 클립을 디자인된 그래픽 카드(타이틀, 하단 서드, 데이터 콜아웃, 인용문, 사이드 패널, PiP)로 패키징합니다. — 일반 자막(말을 텍스트로 표시)이 아닙니다. 클립은 그대로 재생됩니다. 다른 모든 의도 — 일반 자막, 독립형 그래픽, 처음부터 영상 제작 — 또는 불확실한 경우 → 먼저/hyperframes를 읽으세요: 의도 레이어가 모든 경로 결정을 담당합니다.
embedded-captions의 그래픽 패키징 대응 스킬. 자막은 _말하는 내용_을 읽을 수 있는 자막으로 추가하는 반면, 이 스킬은 재생 중인 영상 위에 _디자인된 그래픽_을 추가합니다. 일반 자막 →embedded-captions. 처음부터 영상 제작 → 제작 워크플로우(product-launch-video/faceless-explainer/ …).
/hyperframes를 통해 라우팅될 때, 의도 레이어는 입력(어떤 클립)만 확인하고 렌더링 전략 질문은 연기된 요청으로 알립니다 — 화면 비율, 레이아웃, 스타일 그룹, 카드 개수는 Step 7에서 처리되며, 프로브된 푸티지와 대본이 권장 사항의 근거가 됩니다. 레이어의 실행 형태(run-shape) 질문은 적용되지 않습니다. BRIEF.md가 있을 경우 확인된 입력과 사용자 노트를 포함하고 있습니다 — 먼저 읽으세요.
작업 디렉토리에서 검사 가능한 중간 파일:
metadata.json— 길이 / 너비 / 높이 / fpsaudio.mp3— 추출된 오디오transcript.json— 평평한 단어 배열[{ text, start, end }, …](Whisper;segments나words래퍼 없음)storyboard.json— 가벼운 카드 개요 (에이전트의 계획)public/cards/card-XX.html— 카드당 하나의 HTML 조각public/index.html— 최종 조합된 구성output.mp4— 렌더링된 영상
CLI 해결
# hyperframes — 전사(로컬 Whisper) + 조합된 HTML을 MP4로 렌더링
npx hyperframes --help
이 스킬은 hyperframes CLI와 시스템 ffmpeg / ffprobe에서만 실행됩니다. 전사는 로컬 Whisper를 통해 hyperframes transcribe 명령으로 수행됩니다 — 타사 서비스, API 키, 속도 제한 프록시가 필요 없습니다.
워크플로우
1. 환경 확인
npx hyperframes doctor # ffmpeg, 헤드리스 브라우저, 렌더링 종속성 확인
# 번들된 에셋 확인:
ls "<SKILL_DIR>/assets/fonts" "<SKILL_DIR>/assets/vendor/gsap.min.js"
필수:
ffmpeg/ffprobe(시스템)<SKILL_DIR>/assets/fonts/*.woff2,<SKILL_DIR>/assets/vendor/gsap.min.js(이 스킬 내부에 번들, Step 9에서 작업 디렉토리로 스테이징)
전사에는 키가 필요 없음 — hyperframes transcribe가 로컬 Whisper를 실행합니다(Step 4).
macOS에서 hyperframes render에 강력히 권장:
export PRODUCER_BROWSER_GPU_MODE=hardware
2. 작업 디렉토리 생성
모든 아티팩트는 videos/<project-name>/ 아래에 위치합니다 — 다른 영상 워크플로우(product-launch-video / faceless-explainer / pr-to-video)와 동일한 규칙입니다. 현재 작업 디렉토리는 워크스페이스 루트에 유지하고, 모든 항목은 이 하위 디렉토리 아래에 기록됩니다.
VIDEO_PATH="/절대/경로/input.mp4"
WORK_DIR="videos/$(basename "$VIDEO_PATH" | sed 's/\.[^.]*$//')"
mkdir -p "$WORK_DIR"
3. 오디오 및 메타데이터 추출
# 메타데이터 — 길이 / 너비 / 높이 / fps
ffprobe -v error -select_streams v:0 \
-show_entries stream=width,height,r_frame_rate \
-show_entries format=duration -of json "$VIDEO_PATH" > "$WORK_DIR/metadata.json"
# 오디오
ffmpeg -y -i "$VIDEO_PATH" -vn -acodec libmp3lame -q:a 2 "$WORK_DIR/audio.mp3"
출력: metadata.json (width/height/duration 읽기; fps = r_frame_rate 분수 계산값, 예: 30000/1001 → 29.97) + audio.mp3.
4. 전사
npx hyperframes transcribe "$WORK_DIR/audio.mp3" -d "$WORK_DIR" --json --model small.en
로컬 Whisper — API 키, 프록시, 속도 제한 없음. 작업 디렉토리에 단어 수준의 transcript.json을 기록합니다(단어 text + start / end 타임스탬프). 카드 타이밍(Step 6)을 위해 단어/문장 타이밍을 읽으세요; 문장 수준 청크가 필요하면 구두점/일시 정지에서 직접 단어를 문장으로 그룹화하세요.
미디어 길이로 클램프. Whisper는 마지막 단어의 end가 실제 클립 길이보다 약간 더 길게 반환할 수 있습니다 — 모든 카드 endSec과 composition.durationSeconds를 metadata.json의 길이로 클램프하지 않으면 렌더 시 영상 뒤에 검은 꼬리가 나타납니다.
5. 대본 교정
transcript.json은 단어 객체의 평평한 배열입니다 — [{ "text": "...", "start": s, "end": s }, …] (segments 배열, words 래퍼 없음; 단어당 키는 text). 읽고 명백한 ASR 오류를 수정하세요:
- 동음이의어, 제품명, 기술 용어, 구두점
- 단어의
text를 제자리에서 편집;start/end타임스탬프는 보존 - 사전 그룹화된
segments배열은 없음 — 카드 타이밍을 위한 문장 수준 청크가 필요하면 직접 단어를 문장으로 그룹화하세요 (종료 구두점/일시 정지에서 분할)
6. 가벼운 스토리보드 작성 (채팅에서)
CLI 미사용. transcript.json + metadata.json을 읽고 직접 카드를 디자인합니다. storyboard.json은 에이전트 내부 계획 아티팩트입니다 — 이를 소비하는 CLI 명령은 없습니다. 각 카드의 HTML을 작성하기 전에 타이밍과 내용을 명확히 생각하기 위해 존재합니다. 아래 예제와 일관된 형태를 유지하여 Step 9에서 작성할 구성을 동일한 개요로 구동할 수 있도록 합니다:
{
"schemaVersion": 3,
"composition": {
"fps": 30,
"width": 1080,
"height": 1920,
"durationSeconds": 121.2,
"layout": "portrait",
"themeId": "noir",
"seed": 42
},
"videoTrack": {
"sourcePath": "input-video.mp4",
"startSec": 0,
"endSec": 121.2,
"bounds": { "x": 0, "y": 0, "width": 1080, "height": 1920 }
},
"subtitles": { "enabled": false },
"cards": [
{
"id": "card-01",
"intent": "스피커의 불안한 자정 질문으로 시작",
"startSec": 0.5,
"endSec": 13.0,
"accentIndex": 0,
"zone": "fullscreen",
"contentHints": {
"kicker": "솔직한 질문",
"title": "오후 11시의 자기 성찰 질문",
"detail": "고객의 60초 음성 메시지: '위안화가 평가절상되면 내 USD 정책이 큰 손실이라는 뜻인가요?'"
}
}
]
}
필수 카드 필드:
| 필드 | 유형 | 목적 |
|---|---|---|
id | string | 카드 HTML 및 GSAP 선택자에서 사용되는 안정적인 ID |
intent | string | 자연어 설명; 카드 합성에 제공됨 |
startSec / endSec | number | 초 단위 시간 (endSec > startSec) |
accentIndex | 0 | 1 | 2 | 3 | 4 | 이 카드가 사용할 5가지 테마 강조 색상 중 하나 |
zone | 열거형 (아래 참조) | 캔버스에서 카드가 위치할 영역 |
contentHints | object | 자유 형식 가방; 에이전트가 kicker/title/detail/data/quote 등을 여기에 넣음 |
archetype (선택 사항) | string | 카드 패턴을 기억하기 위한 자유 형식 레이블; 없으면 자유 형식이 기본값 |
transition (선택 사항) | 열거형: cut | fade | slide | wipe | 카드 간 전환을 선언적으로 지정 |
다섯 가지 zone 값:
| zone | 해석된 범위 | 사용 시기 |
|---|---|---|
fullscreen | 캔버스 전체를 덮음 | 영웅적인 순간, 큰 숫자, 만트라 |
whiteboard-area | 40px 여백 삽입 (또는 세로형 높이의 45%) | 밀집된 데이터 / 주석 콘텐츠 |
lower-third | 하단 30% 밴드 | 보이는 영상 위 주석 |
side-panel | 오른쪽 42% (가로) 또는 하단 40% (세로) | 한쪽은 데이터, 다른 쪽은 영상 |
video-overlay | 전체 캔버스, 대부분 투명한 카드 예상 | 전체 화면 영상 위의 주석 오버레이 |
Step 9에서 구성을 조합할 때, 위 표에 따라 각 카드의 zone을 카드 호스트 래퍼의 픽셀 범위로 해석합니다. 영상 범위는 구성 수준에서 한 번 설정됩니다(videoTrack.bounds); 영상이 카드 사이에서 "이동"하는 것처럼 보이게 하려면 구성의 <script>에서 #video-wrap에 대한 GSAP 트윈을 작성하세요(Step 9 참조).
고정된 카드 역할, 고정된 서사 아크 없음. 카드는 영상이 실제로 말하는 내용에서 나타납니다 — 모두 인용문일 수도, 모두 데이터일 수도 있으며, 숫자로 시작할 수도, 이야기로 시작할 수도 있습니다. 대본이 리듬을 결정하게 하세요.
취할 요점 수는? — 길이 + 밀도에서 자동 추론. 고정된 상한선 없음. 영상 길이에서 기본 속도를 선택한 후, 정보 밀도로 조정하세요. 최소값만 고정: 최소 5개 카드 — 짧은 영상도 리듬을 갖도록.
Step 1 — 길이에 따른 기본 속도 (중간 밀도에서 자연스러운 초/카드):
| 영상 길이 | 기본 속도 (카드당 초) | 근거 |
|---|---|---|
| < 60초 (짧은 릴) | 6–8초 | 짧은 형식에서 빠른 컷을 기대함 |
| 60초 – 3분 | 8–12초 | 일반적인 소셜 속도 |
| 3 – 10분 | 12–20초 | 숨 쉴 공간 제공; 각 카드가 더 많이 전달 |
| 10 – 30분 | 20–35초 | 긴 형식 강의 / 인터뷰 리듬 |
| > 30분 | 30–60초 | 에피소드식, 챕터에 가까운 느낌 |
Step 2 — 밀도 승수 (기본 속도에 곱함):
| 대본 신호 | 승수 | 효과 |
|---|---|---|
| 고밀도 — 많은 숫자, 뚜렷한 주장, 단속적 속도, 목록형 열거, 1–2문장마다 새로운 아이디어 | × 0.7 | 더 빠른 컷, 더 많은 카드 |
| 중밀도 — 데이터와 서사가 혼합된 흐름 | × 1.0 | 기본 속도 |
| 저밀도 — 하나의 긴 이야기, 반복적인 재구성, 느린 반성적 속도, 단일 주장 전개 | × 1.5 | 더 느린 컷, 더 적은 카드 |
Step 3 — 계산:
초당카드 = 기본속도 × 밀도승수
카드수 = max(5, round(영상길이초 / 초당카드))
예시 (주의 — 상한 없음; 긴 영상은 자연스럽게 더 많은 카드를 생성):
- 30초 릴, 단일 결론(저밀도) → 7 × 1.5 = 10.5초/카드 → round(30/10.5)=3 → 최소 5 카드
- 60초 반성적 독백(저밀도) → 10 × 1.5 = 15초/카드 → 4 → 최소 5 카드
- 121초 토킹헤드, 풍부한 데이터(고밀도) → 10 × 0.7 = 7초/카드 → 17 카드
- 5분 인터뷰, 혼합 밀도 → 16 × 1.0 = 16초/카드 → 19 카드
- 10분 심층 분석, 고밀도 → 16 × 0.7 = 11초/카드 → 55 카드
- 30분 강의, 중밀도 → 28 × 1.0 = 28초/카드 → 64 카드
- 1시간 팟캐스트, 저밀도 → 45 × 1.5 = 67.5초/카드 → 53 카드
카드가 ~15초 이상 지속될 때는 더 풍부한 카드(데이터 블록, 다단계 공개, 지연 애니메이션으로 전개되는 여러 하위 포인트)를 계획하세요 — 정적 한 줄은 8초가 넘으면 지루해집니다. 많은 카드가 30초를 초과하는 긴 작품의 경우, 타임라인을 하위 구성으로 분할(각 챕터당 하나의 .html, data-composition-src로 마운트)하여 파일당 GSAP 타임라인을 관리 가능하게 유지하세요 — HyperFrames lint 경고 timeline_track_too_dense 참조.
content는 일반 문자열("제목: 연간 5.69%\n메모: ...")이거나 데이터를 캡처하는 모든 JSON 형태일 수 있습니다. 에이전트가 카드당 형태를 결정합니다.
선택적 아웃트로. 이 스킬에는 고정된 브랜드 아웃트로가 없습니다. 사용자가 마지막 카드를 원하면 직접 중립적인 카드를 디자인하고(워드마크 + 한 줄 태그라인, ~1.5-2초, 페이드 인 -> 짧게 유지 -> 페이드 아웃), cards[]에 추가하고, 그에 따라 composition.durationSeconds를 연장하세요.
7. 렌더링 전략 선택 (사용자와 함께, 상황 기반)
에이전트는 각 질문에 대해 기본 권장 사항을 제공하고 사용자가 재정의할 수 있도록 해야 합니다:
a. 화면 비율 (하나 선택):
- 세로(9:16) — 소셜 미디어 릴, 쇼츠, 틱톡, 릴스에 적합
- 가로(16:9) — 유튜브, 프레젠테이션, 웨비나, 팟캐스트에 적합
- 정사각형(4:5, 1:1) — 인스타그램 피드, 링크드인에 적합
b. 레이아웃 스타일 (하나 선택):
- 풀 스크린 — 카드가 전체 캔버스를 차지하고, 영상은 그 뒤나 축소된 PiP로 표시
- 사이드 패널 — 영상이 한쪽에 있고, 카드가 옆에 표시
- 하단 서드 — 영상은 전체 너비로 재생되고, 하단 30%가 주석에 사용
- 화이트보드 — 더 넓은 여백, 집중된 데이터 영역, 메모 작성 느낌
영상 해상도를 확인하고 종횡비와 일치하는 레이아웃을 권장하세요. 소셜 미디어 릴의 경우 기본적으로 세로(9:16)를 선택하세요.
c. 테마 (하나 선택) — 시청자가 다음 영상에서 이전 영상을 알아볼 수 있도록 시리즈 전체에서 일관성을 유지하세요:
| ID | 이름 | 설명 | 용도 |
|---|---|---|---|
noir | 느와르 | 선명한 대비, 단정한 산세리프, 세로형 정보 밀도에 최적화 | 심층 분석, 분석가, 데이터 중심 |
modern | 모던 | 깔끔한 회색/흰색 배경에 유일한 강조색; 선명한 1px 경계선과 미묘한 그림자로 카드를 구분 | 기업, 제품, 인터뷰 |
vibrant | 생생한 | 밝은 구배 배경, 두꺼운 타이포그래피, 대담한 강조 획 | 크리에이터, 밈, 라이프스타일 |
warm | 따뜻한 | 베이지/크림 배경, 세리프와 산세리프 혼합; 영상이 자주 등장인물 중심일 때 | 팟캐스트, 대화, 인간적인 이야기 |
frost | 프로스트 | 어두운 테마, 투명한 유리 효과 카드, 얇은 외곽선, 미묘한 블러 | 테크 리뷰, 게임, 미래지향적 콘텐츠 |
playful | 유쾌한 | 밝은 파스텔, 둥근 모서리, 불규칙한 레이아웃, 캐주얼한 손글씨체 | 교육, 키즈 콘텐츠, 라이프스타일 블로그 |
d. 카드 수 — 자동 계산 결과를 표시하고 사용자가 늘리거나 줄일 수 있도록 허용
e. 대체 카드 추가 — 선택 사항: storyboard.json에 자리 표시자 카드를 명시하여 사용자가 추가로 포함할 내용을 제안할 수 있습니다.
8. 각 카드의 HTML 작성 (Step 6에서 작성한 storyboard.json 사용)
CLI 미사용. 각 카드에 대해 public/cards/card-XX.html 안에 독립형 HTML 조각을 만듭니다. 독립형 조각은 #card-XX 루트 요소를 가지고 있으며, 미리보기나 외부 CSS 없이 바로 배치됩니다. 카드 간 전환은 composition.html의 GSAP 타임라인에서 수행됩니다.
<!-- public/cards/card-01.html -->
<div id="card-01" style="position:absolute;top:0;left:0;width:100%;height:100%;">
<div style="position:absolute; top:50%; left:50%; translate:-50% -50%; text-align:center; width:80%;">
<div class="kicker">솔직한 질문</div>
<div class="title">오후 11시의 자기 성찰 질문</div>
<div class="detail">고객의 60초 음성 메시지: '위안화가 평가절상되면 내 USD 정책이 큰 손실이라는 뜻인가요?'</div>
</div>
</div>
카드 HTML 규칙:
- 모든 카드의 HTML은 단일 파일이 아닌 별도 파일에 있어야 함
- 모든 카드는 공유
<style>블록 대신 인라인 스타일 또는 클래스 사용자 정의 속성을 사용해야 함 - 카드는 외부 CSS에 의존하지 않음 (카드별 독립형)
- 각 카드 HTML 파일에
<style>블록을 포함할 수 있으며,composition.html이 이를 결합함 - 카드의 부모 래퍼(
public/cards/card-XX.html)는position:absolute; top:0; left:0; width:100%; height:100%;를 가져야 함 - 내부 요소는 배치를 위해 인라인 스타일이나 사용자 정의 속성을 사용할 수 있음
9. 단일 composition.html로 조합
모든 카드가 작성되면 하나의 public/index.html로 조합합니다. 이 파일은 영상을 표시하고, 카드 조각을 포함하며, GSAP로 애니메이션을 실행합니다:
<!DOCTYPE html>
<html>
<head>
<style>
/* 공유 스타일 */
body { margin:0; overflow:hidden; background:#000; }
#video-wrap { position:absolute; }
.card-host { position:absolute; top:0; left:0; width:100%; height:100%; }
</style>
</head>
<body>
<div id="video-wrap">
<video id="video" muted playsinline>
<source src="../input-video.mp4" type="video/mp4">
</video>
</div>
<div id="card-layer" class="card-host">
<!-- 카드 조각 포함 -->
<div id="card-01">
<div style="...">...</div>
</div>
</div>
<script src="../../assets/vendor/gsap.min.js"></script>
<script src="../../assets/vendor/ScrollTrigger.min.js"></script>
<script>
// GSAP 타임라인
const tl = gsap.timeline({paused:true});
// 카드 01: 0.5초에 등장, 13초에 사라짐
tl.to('#card-01', { opacity:1, duration:0.3 }, 0.5);
tl.to('#card-01', { opacity:0, duration:0.3 }, 13.0);
// 영상 동기화
const video = document.getElementById('video');
function sync() {
tl.progress(video.currentTime / video.duration);
requestAnimationFrame(sync);
}
video.addEventListener('loadedmetadata', () => {
video.play();
sync();
});
</script>
</body>
</html>
조합 규칙:
#card-layer는 모든 카드의 부모로,position:absolute; top:0; left:0; width:100%; height:100%;를 가짐- 각 카드
div는public/cards/card-XX.html의 내용과 일치해야 함 - GSAP 타임라인은 모든 카드를 순서대로 애니메이션화하며, 전환에는
fade,slide,wipe를 사용 - 영상 시간과 타임라인이 정확히 동기화되도록 함
10. 렌더링
cd "$WORK_DIR"
npx hyperframes render public/index.html -o output.mp4 --width 1080 --height 1920 --fps 30
렌더링이 완료되면 사용자에게 프레젠테이션할 수 있도록 output.mp4 미리보기를 생성합니다.
최종 파일 구조
videos/<project-name>/
├── metadata.json # ffprobe 출력
├── audio.mp3 # 추출된 오디오
├── transcript.json # Whisper 전사 (단어 배열)
├── storyboard.json # 카드 개요 (선택 사항)
├── public/
│ ├── index.html # 조합된 구성 + GSAP 타임라인
│ └── cards/
│ ├── card-01.html # 각 카드의 HTML
│ ├── card-02.html
│ └── ...
└── output.mp4 # 최종 렌더링된 영상