mkt-hyperframe-talking-head-video
Pipeline đóng gói: từ MP4 quay sẵn (talking head 9:16) tới HyperFrames preview project hoàn chỉnh có captions, SFX, zoom hooks, b-roll toàn cảnh có hiệu ứng rich, và CTA finale.
Khi nào sử dụng
- Người dùng đã quay xong 1 video face-cam 9:16 (TikTok/Reels/Shorts) và muốn thêm captions + visual hooks + SFX
- Người dùng có thêm 1 số ảnh hoặc video b-roll muốn chèn vào (kèm mục đích sử dụng)
- Người dùng muốn output preview Studio để duyệt visual trước khi render MP4
Đừng dùng skill này nếu:
- Người dùng chưa quay video — dùng
mkt-create-script-short-videođể viết script trước, hoặc skill khác để tạo voiceover + avatar AI - Người dùng đã có HyperFrames project và chỉ muốn chỉnh tweaks nhỏ — sửa trực tiếp file thay vì re-scaffold
- Người dùng muốn render MP4 từ project đã có — chạy
npx hyperframes renderthẳng
Tổng quan pipeline
MP4 9:16 talking-head + (optional) b-roll files
│
▼
1. Kiểm tra MP4 ───────── ffprobe → duration, resolution, FPS
│
▼
2. Lên cấu trúc ────── auto-detect lesson markers từ user input HOẶC từ transcript
│
▼
3. Phiên âm ────────── npx hyperframes transcribe --model medium --language vi
│
▼
4. Làm sạch transcript ──── apply VN Whisper error dict (alphabit→Alphabet, v.v.)
│
▼
5. Nhóm captions ────── 3-5 words/group, break on >0.45s gap, preserve timing
│
▼
6. Map b-roll ────────── hỏi người dùng mục đích → assign to lesson scenes
│
▼
7. Tạo dự án ──────── workspace/video-projects/<slug>/
├── index.html (root)
├── source.mp4
├── transcript.json + caption-groups.json
├── compositions/
│ ├── captions.html
│ ├── fs-lesson-N.html (một cho mỗi bài học, hiệu ứng đa dạng)
│ ├── recap-card.html (nếu có)
│ └── fs-cta.html
└── sfx/ (6 sound effects)
│
▼
8. Lint ──────────────── npx hyperframes lint → sửa lỗi
│
▼
9. Mở preview ──────── npx hyperframes preview (background) → URL Studio
│
▼
10. Bàn giao cho người dùng ─── KHÔNG auto-render MP4
Quy tắc preview-first (bất di bất dịch): Skill kết thúc ở Bước 9 với URL Studio. Render MP4 chỉ chạy khi người dùng xác nhận rõ ràng sau preview.
Bước 1: Xác minh đầu vào + kế hoạch
Người dùng sẽ cung cấp:
| Đầu vào | Bắt buộc | Định dạng |
|---|---|---|
| MP4 face-cam 9:16 | Có | Đường dẫn file |
| Slug / tên project | Không | Tự động suy từ tên file nếu thiếu |
| Danh sách b-roll | Không | [{path: "screenshot.png", purpose: "Bài học 1 — minh họa thử nghiệm"}, ...] |
| Cấu trúc video | Không | "3 bài học + intro + CTA" / "5 tips" / v.v. — auto-detect nếu thiếu |
Kiểm tra MP4 trước khi làm gì:
ffprobe -v error -show_entries format=duration:stream=codec_type,width,height,r_frame_rate \
-of json "<mp4_path>"
Xác minh:
- Resolution là 9:16 (ví dụ: 1080x1920, 1440x2560) — nếu landscape, cảnh báo nhưng vẫn proceed (object-fit:cover sẽ crop)
- Duration < 180s lý tưởng; > 180s vẫn được nhưng warn user TikTok thuật toán thích ≤90s
- FPS 24/25/30/60 đều OK — output sẽ default 30fps
Slug: suy từ tên file, lowercase, dấu Việt → ASCII, space → dash. VD "3 bài học .mp4" → 3-bai-hoc. Người dùng có thể ghi đè.
Thư mục output: workspace/video-projects/<slug>/
Bước 2: Phiên âm + làm sạch
cd workspace/video-projects/<slug>/
cp <user_mp4> source.mp4
npx hyperframes transcribe source.mp4 --model medium --language vi
KHÔNG bao giờ dùng --model medium.en hay small.en cho audio Việt — .en model DỊCH sang English thay vì phiên âm. Luôn dùng --language vi cho audio Vietnamese.
Sau khi xong, làm sạch transcript:
python3 .claude/skills/mkt-hyperframe-talking-head-video/scripts/clean_transcript.py \
transcript.json
# writes: transcript.json (in-place clean) + caption-groups.json (auto-grouped)
Script đã apply VN Whisper error replacements (alphabit→Alphabet, Cod→Code, dụng/dùng context-aware, đ��ng→đắc, v.v.) và auto-group thành 3-5 word caption phrases với break on >0.45s gap.
Quy tắc đồng bộ caption quan trọng: Timing PHẢI giữ nguyên từ word-level transcript. KHÔNG hand-edit timing. Nếu cần sửa text, sửa text only — script clean_transcript.py đã handle. Bug điển hình: hand-edit text rồi vô tình sửa timing → captions lệch 5s ở giữa video.
Bước 3: Phát hiện cấu trúc cảnh
python3 .claude/skills/mkt-hyperframe-talking-head-video/scripts/detect_scenes.py \
transcript.json
# outputs: scenes.json
Script tìm trong transcript các marker:
- "Bài học đầu tiên / thứ 2 / thứ 3 / thứ N" → lesson scenes
- "Tips số 1 / Tip 1 / Số 1" → tip scenes
- "Tổng kết lại / Recap / Kết luận" → recap moment
- "Comment / Đăng ký / Like / Theo dõi" → CTA moment
Output scenes.json:
{
"type": "lessons",
"scenes": [
{ "kind": "lesson", "num": 1, "start": 9.4, "end": 13.0, "kicker": "Bài học #1", "heading": "..." },
{ "kind": "lesson", "num": 2, "start": 34.5, "end": 38.0, ... },
{ "kind": "lesson", "num": 3, "start": 61.5, "end": 65.5, ... },
{ "kind": "recap", "start": 84.9, "end": 99.0 },
{ "kind": "cta", "start": 99.0, "end": 106.94 }
]
}
Nếu auto-detect không tìm ra structure rõ ràng (vd vlog free-form), hiển thị kết quả cho user và xin confirm. Người dùng có thể ghi đè timestamps.
Bước 4: Map b-roll
Nếu người dùng cung cấp b-roll files với mục đích:
[
{ path: "alphabet-screenshot.png", purpose: "Bài học 1 — Alphabet ship beta" },
{ path: "clock-icon.mp4", purpose: "Bài học 2 — minh họa 24h" },
{ path: "team-meeting.png", purpose: "Bài học 3 — bỏ rào cản team" }
]
Logic mapping:
- Mỗi b-roll match với 1 scene dựa trên text "Bài học N" trong purpose
- Image → dùng làm full-screen background của scene đó (replace text-only generated scene)
- Video → dùng làm full-screen scene background HOẶC picture-in-picture overlay (mặc định: full-screen)
- Default scene effects (pulse rings, corner marks, v.v.) vẫn được layer LÊN TRÊN b-roll image/video
Nếu người dùng không cung cấp b-roll, dùng text-only scenes (như reference project 3-bai-hoc/) — generated text card với title + giant number + sub.
Bước 5: Tạo file dự án (phong cách infographic — MẶC ĐỊNH)
Sử dụng infographic v2 generator cho content-driven mockup b-rolls (phong cách Hostinger: dark glassmorphic + neon glow + UI mockups + floating data badges):
python3 .claude/skills/mkt-hyperframe-talking-head-video/scripts/scaffold_infographic_v2.py \
--output workspace/content/YYYY-MM-DD/<slug>/compositions/ \
--scenes scenes.json
scenes.json schema (per scene, bao gồm mockup_variant + content):
{
"scenes": [
{
"kind": "lesson",
"num": 1,
"start": 12.71,
"end": 26.40,
"kicker": "Tư vấn AI",
"heading": "Tư vấn AI cho 1 ngành",
"accent_words": [2],
"mockup_variant": "post-stack",
"content": { "posts": [...] },
"badges": [
{ "pos": "tr", "color": "orange", "icon": "📅", "num": "30", "label": "Ngày" }
]
},
{ "kind": "recap", "mockup_variant": "team-grid", "content": {...} },
{ "kind": "cta", "mockup_variant": "comment-box", "content": {...} }
]
}
7 biến thể mockup — chọn cái phù hợp với ngữ nghĩa scene:
| Loại scene | Biến thể | Sử dụng cho |
|---|---|---|
| Personal branding / posting | post-stack | Stack 3 social cards, top highlighted với engagement |
| AI search / GEO | ai-window | Cửa sổ phong cách ChatGPT với rec card highlighted |
| Voice / phone / call | phone-call | iPhone mockup với waveform + agent bubble + slot grid |
| Analytics / dashboards | dashboard | Glass card với stats + creative grid + chart line |
| Product / SaaS launch | app-card | App card với icon + stats + optional metaphor row |
| Recap before-after | team-grid | 40-dot grid morph với animated count-down + multiplier |
| CTA "comment X" | comment-box | Comment box mockup + 2 gift cards + CTA pill |
Full content schemas + design tokens: xem references/infographic-design-system.md.
Các phần tử shell chung (tự động áp dụng cho mọi scene): nền radial gradient + cyan grid lines + 10 SVG particles (drift loop) + vignette + topic pill (orange glow) + brand title 110px (slam-in word-by-word, accent gradient).
Floating badges (tùy chọn 1-4 mỗi scene): huy hiệu tròn 130px xung quanh hero mockup với icon + number + label, color-coded (cyan/purple/orange/green) với matching glow, animate từ off-screen + bob loop.
Legacy generator (không được khuyến khích)
scaffold_project.py (rings/corners/light-sweep abstract decorative) — giữ lại để tương thích ngược nhưng không được khuyến khích. Dùng scaffold_infographic_v2.py cho video mới.
Mỗi scene có:
- Punch-zoom entrance trên
.scene-content(zo11-in 1.12 / zoom-out 0.92 xen kẽ) - Element entrances: eyebrow → num → title (word-by-word slam) → sub
- Ambient effects trong suốt scene (pulse rings, breath, drift, v.v.)
- KHÔNG có exit animation — clip ends, framework ẩn
Quy tắc sub-composition: internal timeline RELATIVE 0 → data-duration, không phải absolute. Mount trong root với data-composition-src="compositions/<name>.html" data-start = scene.start.
Bước 6: Copy SFX
mkdir -p workspace/video-projects/<slug>/sfx
SFX_SRC="$(git rev-parse --show-toplevel)/.claude/skills/mkt-hyperframe-talking-head-video/assets/sfx"
cp "$SFX_SRC"/{camera-flash.mp3,"búng tay.mp3","Whoosh sound effect (1).mp3",Laser.mp3,ting.mp3,"Discord Notification - Sound Effect.mp3"} workspace/video-projects/<slug>/sfx/
6 SFX ánh xạ tiêu chuẩn:
| Thời gian | File | Âm lượng | Thời điểm |
|---|---|---|---|
| 0.0s | camera-flash.mp3 | 0.32 | Hook mở đầu — đồng bộ với punch zoom source video @0s |
| Bắt đầu Bài học 1 − 0.05s | búng tay.mp3 (búng tay) | 0.30 | Hiển thị Bài học 1 |
| Bắt đầu Bài học 2 − 0.05s | Whoosh sound effect (1).mp3 | 0.22 | Chuyển tiếp Bài học 2 |
| Bắt đầu Bài học 3 − 0.05s | Laser.mp3 | 0.28 | Điểm nhấn Bài học 3 |
| Bắt đầu Recap − 0.05s | ting.mp3 | 0.20 | Hiển thị Recap |
| Bắt đầu CTA | Discord Notification - Sound Effect.mp3 | 0.28 | Cảm giác thông báo CTA |
Quy tắc âm lượng SFX (theo references/sfx-library.md): hook 0.25-0.35, transition 0.15-0.2, CTA 0.25. Tối đa 5-6 SFX, cách nhau ≥1.5s.
Bước 7: Lint + mở preview
cd workspace/content/YYYY-MM-DD/<slug>/
npx hyperframes lint
Chấp nhận cảnh báo:
composition_file_too_large— chỉ mang tính thông tin, OK để bỏ qua trên rootcomposition_self_attribute_selector— info-only, infographic mockups sử dụng bộ chọn có phạm vi[data-composition-id="..."]
Từ chối lỗi:
gsap_animates_clip_element— KHÔNG animate visibility/display trên clip — chỉ animate opacityroot_composition_missing_data_start— sub-comps phải códata-start="0"trên inner divmedia_missing_data_start—<audio>SFX phải có thuộc tínhdata-start(lập lịch native HF, không dùng JS trigger)- Vấn đề đồng bộ caption — chạy lại script clean_transcript.py
Quan trọng: z-order của Caption
Sub-comp captions PHẢI mount với data-track-index cao nhất để hiển thị phía trên sub-comps bài học (có nền tối toàn màn hình). Nếu không, captions bị ẩn phía sau b-roll.
<!-- Lesson/recap/cta mounts: track-index 40-47 -->
<div class="clip split-mount" data-composition-src="compositions/fs-lesson-1.html" data-start="..." data-track-index="40"></div>
<!-- ... -->
<!-- Captions CUỐI CÙNG với track 60 + inline z-index -->
<div class="clip captions-mount"
data-composition-src="compositions/captions.html"
data-start="0" data-duration="..." data-track-index="60"
style="z-index: 100;"></div>
Bước 7.5: Bố cục split-screen + full-face breath (ĐƯỢC KHUYẾN KHÍCH cho talking-head + b-roll)
Sử dụng cho bất kỳ video nào cần khuôn mặt nói + b-roll mockups cùng hiển thị — thay vì b-roll toàn màn hình che mặt.
Kiến trúc:
- Video khuôn mặt mặc định toàn màn hình trong intro
- Khi b-roll xuất hiện: mặt thu nhỏ xuống nửa dưới (1080x960), b-roll hiển thị ở nửa trên (tỷ lệ 0.5)
- Kết thúc mỗi b-roll (1.5s trước scene tiếp theo): mặt mở rộng trở lại toàn màn hình (khoảnh khắc "thở") → bắt những câu nói cảm xúc
- Captions tự động di chuyển giữa giữa (chế độ split) và dưới (chế độ full-face)
Tạo root index.html với split-screen được cài sẵn:
python3 .claude/skills/mkt-hyperframe-talking-head-video/scripts/generate_root_index.py \
--output workspace/content/YYYY-MM-DD/<slug>/index.html \
--scenes scenes.json \
--total-duration 108.92 \
--header-label "6 AI BUSINESS 2026" \
--footer-handle "@tranvanhoang.com"
scenes.json phải bao gồm brollEnd + hasBreath cho mỗi scene. Xem references/split-screen-pacing.md để biết các quy tắc biên tập (khi nào full vs split), CSS...