{"id":"9d0b721b-636f-49ae-a36e-080f05263100","entityType":"agent","slug":"clawhub-heygen-com-talking-head-recut","name":"talking-head-recut","canonicalUrl":"https://www.xpersona.co/agent/clawhub-heygen-com-talking-head-recut","canonicalPath":"/agent/clawhub-heygen-com-talking-head-recut","generatedAt":"2026-10-10T08:10:23.620Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-09T22:03:15.058Z","emptyReason":null},"description":"Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, side panels, picture-in-picture — synced to the transcript, on a 16:9 / 9:16 / 4:5 canvas of your choice; the clip plays untouched underneath. Trigger on \"graphic overlays\", \"on-screen graphics\", \"package / dress up my video\". Not plain subtitles (/embedded-captions). Unclear → /hyperframes. Skill: talking-head-recut Owner: heygen-com Summary: Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, side panels, picture-in-picture — synced to the transcript, on a 16:9 / 9:16 / 4:5 canvas of your choice; the clip plays untouched underneath. Trigger on \"graphic overlays\", \"on-screen graphics\", \"package / d","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.9K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s17fpgb0p797dzkbtbrxw5x1hh89qs64:talking-head-recut","sourceUrl":"https://clawhub.ai/heygen-com/talking-head-recut","homepage":"https://clawhub.ai/heygen-com/skills/talking-head-recut","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/heygen-com/talking-head-recut","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/heygen-com/skills/talking-head-recut","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":66,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, s"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T22:03:15.058Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T22:03:15.058Z","emptyReason":null},"stars":null,"forks":null,"downloads":1948,"packageName":null,"latestVersion":"1.0.16","tractionLabel":"1.9K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T22:03:15.058Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T22:03:15.058Z","lastCrawledAt":"2026-10-09T22:03:15.058Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T22:03:15.058Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.16","createdAt":"2026-10-04T19:33:54.907Z","changelog":"Synced from 0c3e244 (main)","fileCount":24,"zipByteSize":92040},{"version":"1.0.15","createdAt":"2026-10-04T19:20:39.279Z","changelog":"Synced from 173103d (main)","fileCount":24,"zipByteSize":92253},{"version":"1.0.14","createdAt":"2026-10-02T13:03:29.755Z","changelog":"Synced from 6f799aa (main)","fileCount":24,"zipByteSize":92191},{"version":"1.0.13","createdAt":"2026-10-02T00:13:23.624Z","changelog":"Synced from 37f30b1 (main)","fileCount":24,"zipByteSize":92221},{"version":"1.0.12","createdAt":"2026-09-27T21:24:12.809Z","changelog":"Synced from ff6e210 (main)","fileCount":24,"zipByteSize":92571},{"version":"1.0.11","createdAt":"2026-09-14T01:27:32.799Z","changelog":"Synced from 95bea16 (main)","fileCount":24,"zipByteSize":92747},{"version":"1.0.10","createdAt":"2026-09-10T03:26:43.928Z","changelog":"Synced from 0f8eb89 (main)","fileCount":24,"zipByteSize":92915},{"version":"1.0.9","createdAt":"2026-08-21T03:11:11.850Z","changelog":"Synced from efc2e19 (main)","fileCount":24,"zipByteSize":92321}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17fpgb0p797dzkbtbrxw5x1hh89qs64:talking-head-recut","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-talking-head-recut/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-talking-head-recut/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-talking-head-recut/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-talking-head-recut/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-talking-head-recut/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-talking-head-recut/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T08:10:23.617Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-talking-head-recut/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-talking-head-recut/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-talking-head-recut/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-talking-head-recut/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-09T22:03:15.058Z","emptyReason":null},"readme":"Skill: talking-head-recut\n\nOwner: heygen-com\n\nSummary: Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, side panels, picture-in-picture — synced to the transcript, on a 16:9 / 9:16 / 4:5 canvas of your choice; the clip plays untouched underneath. Trigger on \"graphic overlays\", \"on-screen graphics\", \"package / dress up my video\". Not plain subtitles (/embedded-captions). Unclear → /hyperframes.\n\nTags: latest:1.0.16\n\nVersion history:\n\nv1.0.16 | 2026-10-04T19:33:54.907Z | user\n\nSynced from 0c3e244 (main)\n\nv1.0.15 | 2026-10-04T19:20:39.279Z | user\n\nSynced from 173103d (main)\n\nv1.0.14 | 2026-10-02T13:03:29.755Z | user\n\nSynced from 6f799aa (main)\n\nv1.0.13 | 2026-10-02T00:13:23.624Z | user\n\nSynced from 37f30b1 (main)\n\nv1.0.12 | 2026-09-27T21:24:12.809Z | user\n\nSynced from ff6e210 (main)\n\nv1.0.11 | 2026-09-14T01:27:32.799Z | user\n\nSynced from 95bea16 (main)\n\nv1.0.10 | 2026-09-10T03:26:43.928Z | user\n\nSynced from 0f8eb89 (main)\n\nv1.0.9 | 2026-08-21T03:11:11.850Z | user\n\nSynced from efc2e19 (main)\n\nv1.0.8 | 2026-08-20T22:39:52.246Z | user\n\nSynced from 2be5a03 (main)\n\nv1.0.7 | 2026-08-19T21:04:38.594Z | user\n\nSynced from 9da422f (main)\n\nv1.0.6 | 2026-07-21T16:46:24.996Z | user\n\nSynced from 696cbdb (main)\n\nv1.0.5 | 2026-07-16T15:31:30.593Z | user\n\nSynced from 335e748 (main)\n\nv1.0.4 | 2026-07-15T13:25:42.391Z | user\n\nSynced from b9be0b2 (main)\n\nv1.0.3 | 2026-07-08T18:02:07.840Z | user\n\nSynced from 17b8527 (main)\n\nv1.0.2 | 2026-07-08T17:33:57.093Z | user\n\nSynced from 81884a7 (main)\n\nv1.0.1 | 2026-07-07T19:53:05.639Z | user\n\nSynced from 306a291 (main)\n\nv1.0.0 | 2026-07-01T12:06:58.931Z | user\n\nOfficial HyperFrames skills from heygen-com/hyperframes\n\nArchive index:\n\nArchive v1.0.16: 24 files, 92040 bytes\n\nFiles: assets/vendor/gsap.min.js (72925b), media-contract.test.mjs (912b), NOTICE.md (1826b), references/DESIGN_INDEX.md (10171b), references/frames/clean.html (2626b), references/frames/hairline.html (5921b), references/frames/polaroid.html (5349b), references/layouts/overlay.html (5463b), references/layouts/pip.html (4650b), references/layouts/split.html (3805b), references/layouts/stack.html (3458b), references/styles/academic.html (6043b), references/styles/audit.html (6182b), references/styles/editorial.html (6586b), references/styles/geom.html (5776b), references/styles/minimal.html (4142b), references/styles/spotlight.html (4941b), references/styles/swiss.html (6053b), references/styles/terminal.html (6957b), references/styles/whiteboard.html (5829b), references/styles/xhs.html (7210b), skill-card.md (1776b), SKILL.md (65485b), _meta.json (138b)\n\nFile v1.0.16:SKILL.md\n\n---\nname: talking-head-recut\ndescription: Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, side panels, picture-in-picture — synced to the transcript, on a 16:9 / 9:16 / 4:5 canvas of your choice; the clip plays untouched underneath. Trigger on \"graphic overlays\", \"on-screen graphics\", \"package / dress up my video\". Not plain subtitles (/embedded-captions). Unclear → /hyperframes.\n---\n\n**Plugin installs:** Before setup or freshness commands, follow [plugin execution rules](../hyperframes/references/plugin-installation.md) when this skill is inside a HyperFrames plugin. Standalone installs keep the update instructions below.\n\n> **First, keep this skill fresh — confirm with the user before running:** `npx hyperframes skills update talking-head-recut`. A fast no-op when everything is current; otherwise it refreshes this skill plus the core domain skills it depends on before you rely on them.\n\n# Talking Head Recut\n\nTalking Head Recut takes a local video that **plays in full** and layers a sequence of\ntimed, designed **graphic cards** onto it — titles, lower-thirds, data callouts,\nquotes, side panels, picture-in-picture — synced to what's being said. The agent\ndesigns the cards (timing + content) and **writes each card's HTML directly in the\nconversation**, then assembles a single composition HTML and renders it to MP4 via\n`hyperframes`. There is no fixed archetype list and no prescribed card structure —\nthe overlays emerge from what the transcript actually says.\n\n> **The front door is `/hyperframes`.** This skill packages an **existing talking-head clip** with **designed graphic cards** (titles, lower-thirds, data callouts, quotes, side panels, PiP) — not plain captions (the spoken words as text). **The clip plays untouched.** Any other intent — plain subtitles, a standalone graphic, a from-scratch video — or any uncertainty → read `/hyperframes` first: the intent layer owns every route decision.\n\n> **Graphic-packaging sibling of `embedded-captions`.** Captions add the _spoken words_\n> as a readable subtitle; this adds _designed graphics_ on top of the playing video.\n> Plain subtitles → `embedded-captions`. Build a video from scratch → the creation\n> workflows (`product-launch-video` / `faceless-explainer` / …).\n\nRouted through `/hyperframes`, the intent layer confirms only the input (which clip) and **announces** the render-strategy questions as deferred asks — aspect, layout, style group, and card count stay at Step 7, where the probed footage and transcript ground the recommendations; the layer's run-shape questions don't apply. A `BRIEF.md`, when present, carries the confirmed input and any user notes — read it first.\n\nInspectable intermediate files in the work directory:\n\n- `metadata.json` — duration / width / height / fps\n- `audio.mp3` — extracted audio\n- `transcript.json` — a flat **word array** `[{ text, start, end }, …]` (Whisper; no `segments`, no `words` wrapper)\n- `storyboard.json` — lightweight card outline (the agent's plan)\n- `public/cards/card-XX.html` — one HTML fragment per card\n- `public/index.html` — final assembled composition\n- `output.mp4` — rendered video\n\n## CLI Resolution\n\n```bash\n# hyperframes — transcription (local Whisper) + rendering the assembled HTML to MP4\nnpx hyperframes --help\n```\n\nThis skill runs entirely on the **hyperframes** CLI plus system `ffmpeg` / `ffprobe`.\nTranscription is local **Whisper** via `hyperframes transcribe` — no third-party\nservice, API key, or rate-limited proxy.\n\n## Workflow\n\n### 1. Check Environment\n\n```bash\nnpx hyperframes doctor          # ffmpeg, headless browser, render deps\n# confirm bundled assets:\nls \"<SKILL_DIR>/assets/fonts\" \"<SKILL_DIR>/assets/vendor/gsap.min.js\"\n```\n\nRequired:\n\n- `ffmpeg` / `ffprobe` (system)\n- `<SKILL_DIR>/assets/fonts/*.woff2`, `<SKILL_DIR>/assets/vendor/gsap.min.js` (bundled inside this skill, staged to work dir in Step 9)\n\nTranscription needs no key — `hyperframes transcribe` runs Whisper locally (Step 4).\n\nStrongly recommended on macOS for `hyperframes render`:\n\n```bash\nexport PRODUCER_BROWSER_GPU_MODE=hardware\n```\n\n### 2. Create a Work Directory\n\nAll artifacts live under `videos/<project-name>/` — the same convention as the other\nvideo workflows (`product-launch-video` / `faceless-explainer` / `pr-to-video`). Keep\nthe cwd at the workspace root; everything below writes under this one subdirectory.\n\n```bash\nVIDEO_PATH=\"/absolute/path/input.mp4\"\nWORK_DIR=\"videos/$(basename \"$VIDEO_PATH\" | sed 's/\\.[^.]*$//')\"\nmkdir -p \"$WORK_DIR\"\n```\n\n### 3. Extract Audio and Metadata\n\n```bash\n# metadata — duration / width / height / fps\nffprobe -v error -select_streams v:0 \\\n  -show_entries stream=width,height,r_frame_rate \\\n  -show_entries format=duration -of json \"$VIDEO_PATH\" > \"$WORK_DIR/metadata.json\"\n# audio\nffmpeg -y -i \"$VIDEO_PATH\" -vn -acodec libmp3lame -q:a 2 \"$WORK_DIR/audio.mp3\"\n```\n\nOutputs: `metadata.json` (read `width`/`height`/`duration`; fps = the `r_frame_rate`\nfraction evaluated, e.g. `30000/1001 → 29.97`) + `audio.mp3`.\n\n### 4. Transcribe\n\n```bash\nnpx hyperframes transcribe \"$WORK_DIR/audio.mp3\" -d \"$WORK_DIR\" --json --model small.en\n```\n\nLocal **Whisper** — no API key, no proxy, no rate limit. Writes a word-level\n`transcript.json` into the work dir (word `text` + `start` / `end` timestamps).\nRead it for the word / sentence timings that drive card timing in Step 6; group\nwords into sentences yourself at punctuation / pauses if you need segment-level\nchunks.\n\n**Clamp to media duration.** Whisper can return the final word's `end` a hair past the\nactual clip length — clamp every card `endSec` and `composition.durationSeconds` to the\n`metadata.json` duration, or the render will show a black tail past the video.\n\n### 5. Correct Transcript\n\n`transcript.json` is a **flat array of word objects** — `[{ \"text\": \"...\", \"start\": s, \"end\": s }, …]` (no `segments` array, no `words` wrapper; the per-word key is **`text`**). Read it and fix obvious ASR errors:\n\n- Homophones, product names, technical terms, punctuation\n- Edit a word's `text` in place; **preserve its `start` / `end`** timestamps\n- There is no pre-grouped `segments` array — **group words into sentences yourself** (split at terminal punctuation / pauses) when you need segment-level chunks for card timing\n\n### 6. Draft a Lightweight Storyboard (in chat)\n\n**No CLI involved.** Read `transcript.json` + `metadata.json` and design\ncards directly. `storyboard.json` is an agent-internal planning artifact\n— no CLI command consumes it; it exists so you can think clearly\nabout timing and content before writing each card's HTML. Keep the\nshape consistent with the example below so the same outline can drive\nthe composition you author in Step 9:\n\n```json\n{\n  \"schemaVersion\": 3,\n  \"composition\": {\n    \"fps\": 30,\n    \"width\": 1080,\n    \"height\": 1920,\n    \"durationSeconds\": 121.2,\n    \"layout\": \"portrait\",\n    \"themeId\": \"noir\",\n    \"seed\": 42\n  },\n  \"videoTrack\": {\n    \"sourcePath\": \"input-video.mp4\",\n    \"startSec\": 0,\n    \"endSec\": 121.2,\n    \"bounds\": { \"x\": 0, \"y\": 0, \"width\": 1080, \"height\": 1920 }\n  },\n  \"subtitles\": { \"enabled\": false },\n  \"cards\": [\n    {\n      \"id\": \"card-01\",\n      \"intent\": \"Hook with the speaker's anxious midnight question\",\n      \"startSec\": 0.5,\n      \"endSec\": 13.0,\n      \"accentIndex\": 0,\n      \"zone\": \"fullscreen\",\n      \"contentHints\": {\n        \"kicker\": \"AN HONEST QUESTION\",\n        \"title\": \"The soul-searching question at 11 PM\",\n        \"detail\": \"Client's 60-second voice message: 'If the RMB appreciates, does that mean my USD policy is a terrible loss?'\"\n      }\n    }\n  ]\n}\n```\n\n**Required Card fields:**\n\n| field                   | type                                       | purpose                                                                                               |\n| ----------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------- |\n| `id`                    | string                                     | stable id used in card HTML & GSAP selectors                                                          |\n| `intent`                | string                                     | natural-language description; fed to card synthesis                                                   |\n| `startSec` / `endSec`   | number                                     | times in seconds (endSec > startSec)                                                                  |\n| `accentIndex`           | 0 \\| 1 \\| 2 \\| 3 \\| 4                      | which of the 5 theme accent colors this card pulls                                                    |\n| `zone`                  | enum (see below)                           | where on the canvas the card lives                                                                    |\n| `contentHints`          | object                                     | free-form bag; agent puts kicker/title/detail/data/quote here                                         |\n| `archetype` (optional)  | string                                     | free-form label you may attach to remember a card's pattern; absent = free-form, which is the default |\n| `transition` (optional) | enum: `cut` \\| `fade` \\| `slide` \\| `wipe` | declarative card-to-card transition                                                                   |\n\n**Five `zone` values:**\n\n| zone              | resolved bounds                                | when to use                             |\n| ----------------- | ---------------------------------------------- | --------------------------------------- |\n| `fullscreen`      | covers whole canvas                            | hero moments, big numbers, mantras      |\n| `whiteboard-area` | inset 40px margin (or 45% of portrait height)  | dense data / annotated content          |\n| `lower-third`     | bottom 30% band                                | annotation over visible video           |\n| `side-panel`      | right 42% (landscape) or bottom 40% (portrait) | data side, video other side             |\n| `video-overlay`   | full canvas, expects mostly-transparent card   | annotation overlays on full-bleed video |\n\nWhen you assemble the composition in Step 9, resolve each card's `zone`\ninto pixel bounds on the card-host wrapper following the table above.\nVideo bounds are set **once** at composition level (`videoTrack.bounds`);\nto make video appear to \"move between cards\", author GSAP tweens against\n`#video-wrap` in the composition's `<script>` (see Step 9).\n\n**No prescribed card roles, no prescribed narrative arc.** Cards emerge\nfrom what the video actually says — could be all quotes or all data,\ncould open with a number or with a story. Let the transcript drive the\nrhythm.\n\n**How many takeaways? — auto-infer from duration + density.** No fixed\nupper limit. Pick a **base pace** from the video duration, then adjust\nby **information density**. Only **floor is fixed: minimum 5 cards** so\neven short videos have rhythm.\n\n**Step 1 — base pace by duration** (the natural sec/card for medium density):\n\n| video duration     | base pace (sec per card) | rationale                                   |\n| ------------------ | ------------------------ | ------------------------------------------- |\n| < 60s (short reel) | **6–8s**                 | viewers expect fast cuts in short-form      |\n| 60s – 3 min        | **8–12s**                | normal social pace                          |\n| 3 – 10 min         | **12–20s**               | give breathing room; each card carries more |\n| 10 – 30 min        | **20–35s**               | long-form lecture / interview rhythm        |\n| > 30 min           | **30–60s**               | episodic, near-chapter feel                 |\n\n**Step 2 — density multiplier** (multiplies the base pace):\n\n| signal in the transcript                                                                                                    | multiplier | effect                   |\n| --------------------------------------------------------------------------------------------------------------------------- | ---------- | ------------------------ |\n| **High density** — many numbers, distinct claims, staccato pacing, list-like enumeration, every 1–2 sentences is a new idea | **× 0.7**  | cuts faster, more cards  |\n| **Medium density** — mixed flow with both data and narrative                                                                | **× 1.0**  | base pace                |\n| **Low density** — one extended story, repeated reframing, slow reflective pacing, single argument unfolding                 | **× 1.5**  | cuts slower, fewer cards |\n\n**Step 3 — compute:**\n\n```\nsecPerCard = basePace × densityMultiplier\ncardCount  = max(5, round(videoDurationSec / secPerCard))\n```\n\nExamples (notice — **no upper clamp**; long videos naturally produce more cards):\n\n- **30s reel, single punchline (low density)** → 7 × 1.5 = 10.5s/card → round(30/10.5)=3 → floor to **5** cards\n- **60s reflective monologue (low density)** → 10 × 1.5 = 15s/card → **4** → floor to **5** cards\n- **121s talking-head with rich data (high density)** → 10 × 0.7 = 7s/card → **17** cards\n- **5 min interview, mixed density** → 16 × 1.0 = 16s/card → **19** cards\n- **10 min deep-dive, high density** → 16 × 0.7 = 11s/card → **55** cards\n- **30 min lecture, medium density** → 28 × 1.0 = 28s/card → **64** cards\n- **1 hr podcast, low density** → 45 × 1.5 = 67.5s/card → **53** cards\n\nWhen a card holds longer than ~15s, plan for a richer card (data block,\nmulti-step reveal, several sub-points unfolding with staggered\nanimations) — a static one-liner gets boring past 8s. For long pieces\nwhere many cards exceed 30s, consider **chunking the timeline into\nsub-compositions** (one .html per chapter, mounted with\n`data-composition-src`) so the GSAP timeline per file stays manageable\n— see the `timeline_track_too_dense` HyperFrames lint warning.\n\n`contentHints` is a free-form object; its keys and nesting can take whatever\nshape captures the data. The agent decides the shape per card.\n\n**Optional outro.** This skill ships **no fixed brand outro**. If the user wants a closing card, design a neutral one yourself (wordmark + one-line tagline, ~1.5-2s, fade in -> short hold -> fade out), append it to `cards[]`, and extend `composition.durationSeconds` to its `endSec`. Otherwise end on the last content card.\n\n### 7. Decide Render Strategy\n\n#### Confirm Visual Direction with User (DO THIS FIRST)\n\nBefore you start designing cards or deciding bounds, **ask the user to\npick the output ratio, the layout, the style, and the card-density\npreset**. Frames are auto-selected from the chosen layout × style\ncombination (see \"Auto-pick frame\" table below). Before sending the\nquestion, **precompute two things**:\n\n1. **`recommendedRatio`** from the source video's aspect ratio\n   (`metadata.json` width / height):\n   - `sourceAspect = width / height`\n   - `sourceAspect ≥ 1.5` (≥ ~3:2 wide) → recommend **`16:9`**\n   - `sourceAspect ≤ 0.7` (≤ ~9:13 tall) → recommend **`9:16`**\n   - `0.7 < sourceAspect < 1.5` (near-square) → recommend **`4:5`**\n\n   Mark the recommended option's label with \" (recommended · matches source video X:Y)\"\n   so the user sees why it's recommended.\n\n2. **`autoCount`** from Step 6 (`max(5, round(videoSec / (basePace ×\ndensityMultiplier)))`) so the \"auto\" option's label can show the\n   concrete number.\n\n**Environment compatibility — pick the best available question channel.**\nNot every runtime exposes the same structured-question tool. Apply this\norder:\n\n1. **Native clarification tool** — use the structured 4-question call below.\n2. **Other native clarification tool** (e.g. `ask_question`,\n   `request_user_input`, IDE-specific prompt) — use that tool with the\n   same 4 question texts and option lists. Preserve the recommendation\n   markers and the precomputed values.\n3. **No native tool** (Codex CLI, plain text-only runtimes) — **ask\n   directly in normal conversation**. Use the plain-text template at the\n   end of this section. Keep it to **one message, 4 numbered questions**\n   (the global cap is 2–5 questions per round; we stay inside it).\n\nRules that apply to every channel:\n\n- Ask **at most 2–5 questions per round**. Our 4 here fits.\n- Even if missing info doesn't block rendering, **ask once to confirm\n  the parameters that materially affect the final output** (ratio,\n  layout, style, cardCount).\n- If the user has already pre-approved defaults (\"just use defaults\",\n  \"no need to ask\", \"auto-pick everything\"), asked you not to ask, or the\n  run carries an ongoing autonomous signal (\"surprise me\" / \"decide for me\" —\n  `../hyperframes/references/brief-contract.md` § 1) — **skip\n  the question entirely** and use: `recommendedRatio`, `layout=\"stack\"`\n  (safest cross-ratio default), `style` chosen from transcript tone in\n  the most neutral group (editorial/data), `autoCount`. Tell the user\n  what you picked in one sentence and continue.\n\n**Channel A — native `AskUserQuestion`:**\n\n```\n// Precompute before the call:\n//   recommendedRatio = \"16:9\" | \"9:16\" | \"4:5\"\n//   autoCount        = integer (from Step 6)\n\nAskUserQuestion({\n  questions: [\n    {\n      question: \"Output video aspect ratio (canvas):\",\n      header: \"Aspect ratio\",\n      multiSelect: false,\n      // Reorder so the recommended option appears FIRST (per AskUserQuestion convention).\n      // Append \" (recommended · matches source video W×H)\" to the recommended option's label.\n      options: [\n        { label: \"16:9 (1920×1080) landscape\", description: \"TV / YouTube / desktop playback. Most natural when the source video is already landscape; widest canvas.\" },\n        { label: \"9:16 (1080×1920) portrait\", description: \"TikTok / Reels / short-form mobile. Most natural for portrait source; native mobile experience.\" },\n        { label: \"4:5 (1080×1350) near-portrait\", description: \"Instagram feed / WeChat Moments. Best when source is near-square or you want to cover both platforms.\" }\n      ]\n    },\n    {\n      question: \"Choose the overall layout: how should the video and cards coexist on the canvas?\",\n      header: \"Layout\",\n      multiSelect: false,\n      options: [\n        { label: \"side-by-side (split)\",  description: \"Video and card each take half the canvas. Most stable for interview / data side-by-side; clear visual separation.\" },\n        { label: \"top-bottom (stack)\",    description: \"Video on top (~52%), card below. Classic combo of speaker face + summary card; works well in portrait too.\" },\n        { label: \"picture-in-picture (pip)\", description: \"Card fills the canvas, video shrinks to a rounded corner window. Use when content is primary and speaker is secondary.\" },\n        { label: \"full-screen overlay (overlay)\", description: \"Video plays full-bleed, card floats as a glass layer on top. Strong cinematic / emotional feel.\" }\n      ]\n    },\n    {\n      question: \"Choose the card visual style (style):\",\n      header: \"Style group\",\n      multiSelect: false,\n      // NOTE: these 3 groups intentionally match the frame auto-pick matrix\n      // rows below, so picking a group resolves both `style` group AND the\n      // frame matrix column in one step. Memberships are mutually exclusive.\n      options: [\n        { label: \"warm paper (warm-paper)\", description: \"academic notebook · editorial big-type · whiteboard hand-drawn · xhs social. Best for interview reflections, product launches, lifestyle, emotional stories.\" },\n        { label: \"clinical / cold (clinical)\",   description: \"audit magazine · swiss grid · terminal CLI · minimal modern. Best for financial analysis, investigative reports, technical tutorials, serious presentations.\" },\n        { label: \"experimental / avant-garde (experimental)\", description: \"geom color-clash geometry · spotlight dark-background. Best for short-form highlights, product launches, strong emotion, cinematic feel.\" }\n      ]\n    },\n    {\n      question: \"Card count (takeaway pacing): how many cards to cut?\",\n      header: \"Card count\",\n      multiSelect: false,\n      options: [\n        { label: \"Auto (recommended) · approx N cards\", description: \"Inferred automatically from video duration and information density (see Step 6 rules). This run estimates approx N cards. Substitute the real N (your autoCount) into the label.\" },\n        { label: \"Fewer · approx round(N × 0.6) cards\", description: \"Sparser cuts, each card holds longer — suits reflective / slow-paced content.\" },\n        { label: \"More · approx round(N × 1.5) cards\", description: \"Tighter cuts, faster rhythm — suits staccato / data-dense / short-form highlight content.\" }\n      ]\n    }\n  ]\n})\n```\n\n**About \"Other\"** — `AskUserQuestion` automatically adds an \"Other\" option to the card count question. The user can type a number directly (e.g. \"8\", \"20\") as the cardCount target. Parse the input as an integer: if parsing succeeds → use that value (minimum 5 as a floor); if parsing fails → fall back to \"auto\".\n\n**Channel B — plain-text fallback** (Codex CLI, runtimes without a\nnative question tool). Post this as one normal message, then wait for\nthe reply. Bullet-style 1/2/3/4 keeps the reply parseable:\n\n```\nI need to confirm four visual decisions with you before I start cutting cards:\n\n1) Output aspect ratio (canvas):\n   A. 16:9 landscape (1920×1080) — TV / YouTube / desktop playback\n   B. 9:16 portrait (1080×1920) — TikTok / Reels / short-form mobile\n   C. 4:5 near-portrait (1080×1350) — Instagram feed / works for both platforms\n   ▸ My recommendation:  <recommendedRatio>  (matches source video W×H = <sourceW>×<sourceH>)\n\n2) Overall layout (how video & card coexist):\n   A. split   side-by-side (50/50)\n   B. stack   top-bottom (video top, card bottom)\n   C. pip     picture-in-picture (card full canvas, video rounded corner window)\n   D. overlay full-screen glass overlay (video full-bleed, card glass layer)\n\n3) Card style group (maps to frame auto-pick matrix, pick 1 of 3):\n   A. warm paper (warm-paper)      (academic / editorial / whiteboard / xhs)\n   B. clinical / cold (clinical)   (audit / swiss / terminal / minimal)\n   C. experimental (experimental)  (geom / spotlight)\n\n4) Card count (takeaway pacing):\n   A. Auto (recommended) — approx <autoCount> cards\n   B. Fewer — approx round(<autoCount> × 0.6) cards\n   C. More — approx round(<autoCount> × 1.5) cards\n   D. Give me a specific number (e.g. \"8\", \"20\")\n\nReply format: \"1A 2C 3B 4A\" or natural language is fine.\nIf you want all recommended defaults, reply \"default\" / \"auto\" / \"use all recommendations\".\n```\n\nParsing the plain-text reply:\n\n- Accept loose formats: `\"1A 2C 3B 4A\"`, `\"A C B A\"`, `\"16:9 / pip /\ndata / auto\"`, full sentences, or `default`.\n- If any answer is ambiguous → re-ask only the ambiguous ones (still\n  inside the 2–5 cap).\n- If the user says \"default / auto / use all recommendations\" → skip without re-asking.\n\nAfter the user answers (any channel):\n\n1. **Resolve the output canvas** from the ratio answer — these are the\n   exact `storyboard.composition.width / height` values to write:\n\n   | user choice | composition.width × height | storyboard.layout field                                       |\n   | ----------- | -------------------------- | ------------------------------------------------------------- |\n   | `16:9`      | **1920 × 1080**            | `\"landscape\"`                                                 |\n   | `9:16`      | **1080 × 1920**            | `\"portrait\"`                                                  |\n   | `4:5`       | **1080 × 1350**            | `\"portrait\"` (schema treats 4:5 as portrait — height > width) |\n\n   For **4:5 bounds inside `references/layouts/*.html`** — those files\n   only document landscape (1920×1080) and portrait (1080×1920). For\n   4:5 (1080×1350) derive bounds by **proportional scaling from\n   portrait**: keep horizontal values, scale vertical values by\n   `1350/1920 ≈ 0.703`. Example: `overlay` portrait card =\n   `{ x: 24, y: 1280, w: 1032, h: 564 }` → 4:5 card =\n   `{ x: 24, y: round(1280 × 0.703), w: 1032, h: round(564 × 0.703) }`\n   = `{ x: 24, y: 900, w: 1032, h: 397 }`.\n\n2. **Map the style group to a specific style** by looking at the\n   transcript tone — pick the one that best fits, but stay inside the\n   user's chosen group. If you're unsure between two specific styles\n   inside the group, send a second `AskUserQuestion` with those 2–4\n   specific style options.\n\n3. **Resolve final cardCount** from the density answer:\n\n   | user choice             | final cardCount                           |\n   | ----------------------- | ----------------------------------------- |\n   | Auto (recommended)      | the `autoCount` you already computed      |\n   | Fewer                   | `max(5, round(autoCount × 0.6))`          |\n   | More                    | `round(autoCount × 1.5)` (no upper clamp) |\n   | Other = \"<n>\" (integer) | `max(5, parseInt(n))`                     |\n   | Other = anything else   | fall back to `autoCount`                  |\n\n4. **Auto-pick the video frame** from this table (frames don't ask the\n   user — they follow from layout × style):\n\n   | layout    | warm-paper styles (academic / whiteboard / editorial / xhs) | clinical styles (audit / swiss / terminal / minimal) | experimental styles (geom / spotlight) |\n   | --------- | ----------------------------------------------------------- | ---------------------------------------------------- | -------------------------------------- |\n   | `split`   | `polaroid`                                                  | `hairline`                                           | `clean`                                |\n   | `stack`   | `polaroid`                                                  | `hairline`                                           | `clean`                                |\n   | `pip`     | `clean` (pip pill already has chrome)                       | `clean`                                              | `clean`                                |\n   | `overlay` | `clean` (full-bleed forbids deco frames)                    | `clean`                                              | `clean`                                |\n\n5. **Tell the user what you chose** in one sentence — ratio (+ canvas\n   size), layout, specific style, frame, and final cardCount — then\n   proceed with the rest of Step 7 (per-card layouts, motion patterns).\n6. Record the five values (ratio / layout / style / frame / cardCount)\n   in working memory (no schema field needed); you'll reference them\n   while writing each card's HTML in Step 8 and while reading the\n   matching `references/<dim>/<key>.html` for tokens and structure.\n\nIf the user picks an answer via \"Other\" with a free-text style name not\nin the 10-style library, treat it as a hint to design a fresh card\nvisual yourself, but still anchor on the chosen layout's bounds.\n\n#### Render Strategy Inputs\n\nWith ratio / layout / style / cardCount / frame locked from Step 7.0,\nthe remaining per-card decisions are:\n\n- **Source-video fit inside the GSAP target**: video element has\n  `object-fit: cover` and is clipped to `#video-wrap`'s tween bounds.\n  If you want NO cropping (e.g. portrait source on landscape canvas\n  shouldn't get its top/bottom chopped), aim the tween at a rect that\n  matches the source's aspect ratio and let surrounding canvas show\n  through (or fill with the card / a backdrop).\n- **`card.zone` per card**: derive from your chosen composition layout\n  (split → side-panel, stack → lower-third, pip → fullscreen, overlay\n  → video-overlay), OR pick a different zone for one-off variants\n  (fullscreen for hero / quote, whiteboard-area for dense data).\n- **`accentIndex` per card**: each card pulls one of the 5 theme accent\n  colors. Vary across cards for rhythm; reuse the same index when two\n  cards belong to the same narrative beat.\n- **Motion vocabulary**: pick 2–3 repeatable patterns from\n  `data-anim` kinds (see the table later) and stick to them so the\n  composition feels coherent.\n\nPick from these `themeId` palettes (use them as `--accent-N` /\n`--bg` / `--text` CSS variables in your composition `<style>` block):\n\n| themeId | accent palette (5 colors)                 | board bg          | text      |\n| ------- | ----------------------------------------- | ----------------- | --------- |\n| classic | `#1971c2 #e03131 #2f9e44 #e8590c #9c36b5` | `#FFF9E3` (paper) | `#1e1e1e` |\n| noir    | `#4cc9f0 #f72585 #4ade80 #fb923c #a78bfa` | `#1a1a1a`         | `#f1f1f1` |\n| mint    | `#0077b6 #d62828 #2d6a4f #e76f51 #7209b7` | `#e8faf0`         | `#1b4332` |\n| craft   | `#bf5700 #d62728 #6c757d #e9b54a #3d5a80` | `#f6efe1`         | `#2d2d2d` |\n| slate   | `#0ea5e9 #ef4444 #22c55e #f97316 #a855f7` | `#1e293b`         | `#f1f5f9` |\n| mono    | `#000 #555 #888 #aaa #ccc`                | `#fff`            | `#000`    |\n\nAvailable fonts (woff2 in `<SKILL_DIR>/assets/fonts/`, staged to work dir in Step 9): `Caveat` (handwriting),\n`LXGW WenKai TC` (Chinese hand-script), `Inter` (modern sans), `Virgil`\n(geometric hand). Reference via `@font-face` or `font-family` directly.\n\nFor inspiration on visual patterns, `<SKILL_DIR>/references/styles/`\nships 10 self-contained reference cards (academic / editorial / minimal\n/ spotlight / geom / whiteboard / audit / terminal / swiss / xhs) that\nyou can copy as starting points — but **do not feel constrained to\nmatch any of these**. Each card is your own design.\n\n#### Visual Design Library (<SKILL_DIR>/references/)\n\nBeyond the composition-level `themeId`, the skill ships a richer **reference\nlibrary** at `<SKILL_DIR>/references/` covering three **orthogonal**\nvisual dimensions you can freely mix:\n\n```\nStyle  ×  Layout  ×  VideoFrame\n (10)      (4)         (3)\n```\n\n| dimension  | keys                                                                                              | what it decides                                                          |\n| ---------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |\n| **style**  | `academic` `editorial` `minimal` `spotlight` `geom` `whiteboard` `audit` `terminal` `swiss` `xhs` | the card's visual language — fonts, colors, ornament, layout-within-card |\n| **layout** | `split` `stack` `pip` `overlay`                                                                   | how the source video and the card share the canvas                       |\n| **frame**  | `clean` `hairline` `polaroid`                                                                     | the decorative chrome around the video element                           |\n\nRead `<SKILL_DIR>/references/DESIGN_INDEX.md`\nfor the full matrix and a loose decision guide (interview / product launch / data analysis /\nsocial clip / technical tutorial / emotional story …). When you decide to use a specific\nstyle / layout / frame, Read the corresponding file:\n\n- `references/styles/<key>.html` — self-contained card fragment with that\n  style's CSS tokens (colors, fonts, padding, ornament) and a placeholder\n  takeaway. Copy the `.card[data-card-id=\"ref-<key>\"]` style block, rename\n  the data-card-id to your card's id, swap the placeholder content for the\n  real takeaway, and you're done.\n- `references/layouts/<key>.html` — exact `videoBounds` + `cardBounds` for\n  both landscape and portrait. The storyboard records only `card.zone`.\n- `references/frames/<key>.html` — decorative HTML to add as a sibling of\n  `#video-wrap`, plus placement instructions for the composition CSS.\n\nWithin the user's chosen style group you may vary the style per card, and\npick `layout × frame` per card, as long as the transitions read smoothly.\n\nThe 10 styles are skill-side design tokens, **not composition-level themes** —\nthey don't need to be declared in `storyboard.composition`; they live\ninside each card's HTML. The `themeId` field can still pick a\ncomposition-level palette (table above) that controls page-body background\nand video border chrome.\n\n#### Layout Compositions (Card + Video)\n\nTwo coordinated decisions per card define how it shares the canvas with\nthe source video:\n\n- **`card.zone`** (declared in `storyboard.json`) — one of the 5 schema\n  values; resolve it into pixel bounds (per the table in Step 6) when\n  you write the card-host wrapper's inline `style` in Step 9.\n- **`#video-wrap` bounds at this card's time window** (declared\n  imperatively in the composition's GSAP timeline) — the agent tweens\n  `#video-wrap` to a target rect for each layout transition.\n\nSchema does NOT store per-card video bounds. `videoTrack.bounds` is\n**one-time** at composition level (defaults to full canvas). Video\n\"moving\" between cards is purely a GSAP animation authored in\n`index.html`. There is no `card.layout` field; the schema only has `card.zone`.\n\n**4 composition layouts** (from `references/layouts/`) — each is a\nrecipe pairing a `zone` with a `#video-wrap` tween target:\n\n| composition layout | recommended `card.zone` | GSAP target for `#video-wrap` (landscape 1920×1080)                       | GSAP target for `#video-wrap` (portrait 1080×1920)                | when to use                                     |\n| ------------------ | ----------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------------- |\n| `split`            | `side-panel`            | `{ left: 960, top: 0, width: 960, height: 1080 }`                         | `{ left: 0, top: 960, width: 1080, height: 960 }` (bottom half)   | speaker + data side-by-side / 50:50 weight      |\n| `stack`            | `lower-third`           | `{ left: 14, top: 14, width: 1892, height: 548 }` (top 52%)               | `{ left: 0, top: 0, width: 1080, height: 844 }` (top 44%)         | speaker on top + summary card below             |\n| `pip`              | `fullscreen`            | `{ left: 1480, top: 760, width: 400, height: 300 }` + add `.framed` class | `{ left: 690, top: 28, width: 360, height: 203 }` + add `.framed` | content-heavy card + corner pip                 |\n| `overlay`          | `video-overlay`         | `{ left: 0, top: 0, width: 1920, height: 1080 }` (full-bleed)             | `{ left: 0, top: 0, width: 1080, height: 1920 }`                  | cinematic / dramatic / glass card on full video |\n\nFor 4:5 (1080×1350), scale portrait y/h values by `1350/1920 ≈ 0.703`\n(see Step 7.0 Channel A / Channel B `recommendedRatio` resolution\ntable).\n\n**Other zone values for one-off variants** (still uses `card.zone`; no\nfake \"layout\" field):\n\n| `zone`            | resolved bounds                                        | common use                            |\n| ----------------- | ------------------------------------------------------ | ------------------------------------- |\n| `fullscreen`      | covers whole canvas                                    | hero card, video tweens to hidden/pip |\n| `whiteboard-area` | inset 40px margin (landscape) or bottom 45% (portrait) | dense data card, free margins         |\n| `lower-third`     | bottom 30% band                                        | talking-head annotation               |\n| `side-panel`      | right 42% (landscape) or bottom 40% (portrait)         | sidebar / \"split\" recipe              |\n| `video-overlay`   | full canvas; expect transparent card root              | glass overlay on full-bleed video     |\n\nYou can mix recipes per card — choose `card.zone` based on what suits\nthe moment, then write the GSAP tween for `#video-wrap` between cards.\n\n#### Storyboard Render Contract\n\n`storyboard.json` is an agent-internal planning artifact — no CLI\ncommand parses it. It exists to keep your timing and content decisions\nexplicit before you write each card's HTML. Stick to the v3-style\nshape below so the same outline drives the composition you assemble in\nStep 9.\n\nRequired structure (see Step 6 for the full example):\n\n- `schemaVersion: 3`\n- `composition: { fps, width, height, durationSeconds, layout, themeId, seed }` — note `durationSeconds`/`fps`/`themeId`/`layout` live **inside** `composition`, NOT at top level\n- `videoTrack: { sourcePath, startSec, endSec, bounds? }` — video bounds default to full canvas\n- `subtitles: { enabled, ... }`\n- `cards[]` — each card has the 6 required fields: `id`, `intent`, `startSec`, `endSec`, `accentIndex`, `zone`, `contentHints`\n\nRules:\n\n- Card times stay inside `composition.durationSeconds` and should not overlap unless intentional (use `data-track-index` to control z-order when they do).\n- Visual details live in card HTML fragments (Step 8), NOT in `contentHints`. `contentHints` is your own structured prompt for designing the card; the rendered look is the HTML.\n- Keep the storyboard shape stable — even though nothing parses it, you read it back while authoring Step 8/9, and consistency keeps card IDs and timing in sync.\n- Agent-side decisions like \"I picked overlay × geom × clean\" do NOT belong in `storyboard.json` — keep them in working memory and use them when authoring card HTML + GSAP tweens.\n\n**Transparent card backgrounds for cards that share canvas with video.**\nWhen the GSAP tween leaves video visible behind/beside the card (overlay\nrecipe, pip recipe, or any `card.zone = 'lower-third' | 'video-overlay'`\nmoment), the card's `.root` MUST NOT paint a full opaque background —\notherwise it occludes the video. Two patterns:\n\n```css\n/* Pattern A: transparent root, page body provides the cream backdrop */\nhtml,\nbody {\n  background: var(--bg);\n}\n.card[data-card-id=\"card-X\"] .root {\n  background: transparent;\n}\n\n/* Pattern B: explicit per-card background ONLY for fullscreen cards */\n.card[data-card-id=\"card-hero\"] .root {\n  background: var(--bg);\n}\n.card[data-card-id=\"card-overlay\"] .root {\n  background: transparent;\n}\n```\n\nFor `side-panel`-zone cards (split recipe), the card-host is already\nonly half the canvas, so an opaque card bg is fine — it only covers its\nhalf.\n\n### 8. Write Each Card's HTML\n\nCreate `$WORK_DIR/public/cards/{card-id}.html` for each card. Each file\ncontains a single rooted HTML fragment that follows this contract:\n\n#### Card HTML Contract\n\n```html\n<div class=\"card\" data-card-id=\"{cardId}\">\n  <style>\n    /* MUST: every rule starts with .card[data-card-id=\"{cardId}\"] */\n    .card[data-card-id=\"card-01\"] .root {\n      width: 100%; height: 100%;\n      display: flex; ...;\n      font-family: 'Caveat', 'LXGW WenKai TC', serif;\n      color: var(--text);\n      background: var(--bg);\n    }\n    .card[data-card-id=\"card-01\"] .title { font-size: 84px; ... }\n  </style>\n\n  <div class=\"root\">\n    <h1\n      id=\"card-01-title\"\n      data-anim=\"kinetic-chars\"\n      data-anim-at=\"0.3\"\n      data-anim-duration=\"0.5\"\n      data-anim-stagger=\"0.04\"\n      data-anim-pattern=\"pop\"\n    >\n      <span class=\"char\">S</span>\n      <span class=\"char\">u</span>\n    </h1>\n    <div\n      id=\"card-01-line\"\n      data-anim=\"grow-x\"\n      data-anim-at=\"0.65\"\n      data-anim-duration=\"0.5\"\n      data-anim-target-w=\"420\"\n      style=\"width:0;height:8px;background:var(--accent-0);border-radius:4px;\"\n    ></div>\n  </div>\n</div>\n```\n\n**Hard rules** (`hyperframes` lint will reject violations):\n\n- Single root `<div class=\"card\" data-card-id=\"{cardId}\">`\n- Inline `<style>` rules MUST be prefixed with the scope selector above\n- **No `<script>` tags**\n- **No external URLs** in `src=` / `href=` (no CDN, no remote fonts)\n- **No inline event handlers** (`onclick=` etc.)\n- All assets via relative paths into the same `public/` directory\n- Colors via `var(--accent-N)` etc. for portability across themes\n\n**Animations are declared, not coded.** Use `data-anim-*` attributes\nonly; never write `<script>` to animate. You compile every `data-anim-*`\ndeclaration into the single master GSAP timeline in Step 9.\n\n#### Card Sizing — Mobile-First in Portrait\n\nThe 10 `references/styles/*.html` are sized for a **1920×1080 landscape**\npreview. When `storyboard.layout = \"portrait\"` (1080×1920, the dominant\ncase for social / mobile), **scale every visual size up** — phones hold\nthe screen close, and the same pixel count reads smaller than on a\nlandscape TV-style canvas.\n\n| token                     | landscape baseline | **portrait target** | scale         |\n| ------------------------- | ------------------ | ------------------- | ------------- |\n| title (h1/h2 hero)        | 64–96px            | **88–132px**        | ×1.35         |\n| detail / body             | 24–30px            | **30–40px**         | ×1.30         |\n| kicker / chip label       | 14–16px            | **18–22px**         | ×1.30         |\n| timecode / meta           | 12–14px            | **16–18px**         | ×1.30         |\n| data block primary number | 48–60px            | **64–88px**         | ×1.40         |\n| line-height multiplier    | 1.05–1.5           | same                | (don't scale) |\n\n**Rule of thumb:** `portraitPx = round(landscapePx × 1.3)`, then floor\nto a nearby 4px multiple for visual rhythm. Hero headlines may go up to\n×1.4; small meta text stays at ×1.2 to avoid crowding.\n\nPadding **shrinks slightly** in portrait — the card is narrower so big\nlandscape padding (40–64px) eats too much width. Use 24–36px horizontal\npadding in portrait.\n\nIf you're producing a single card that must work in **both** layouts,\nprefer a `@container` query on the card root over hard-coding sizes:\n\n```css\n.card[data-card-id=\"X\"] .root {\n  container-type: inline-size;\n}\n.card[data-card-id=\"X\"] .title {\n  font-size: clamp(64px, 8.5cqi, 132px);\n}\n.card[data-card-id=\"X\"] .detail {\n  font-size: clamp(24px, 3.2cqi, 40px);\n}\n```\n\nBut for most cards, a single layout choice is fine — just pick the size\ntable column that matches the storyboard's `layout` field.\n\n#### Available `data-anim` Kinds\n\nThis list is closed, and deliberately so: a card is an HTML fragment whose motion this\nskill compiles into the shared overlay timeline in Step 9 (see the GSAP mapping table\nthere). That is why this workflow does not search the HyperFrames component registry the\nway the composition workflows do — `npx hyperframes catalog` returns standalone\ncompositions that carry their own timeline, and a card has no place to mount one. Reach a\nlook the kinds below cannot express with plain CSS inside the card's scoped `<style>`.\n\n| kind            | use for             | key params                                                                                      |\n| --------------- | ------------------- | ----------------------------------------------------------------------------------------------- |\n| `fade-in`       | enter               | `at`, `duration`, `ease?`                                                                       |\n| `fade-out`      | exit                | `at`, `duration`, `ease?`                                                                       |\n| `slide-in`      | slide enter         | `at`, `duration`, `from=left\\|right\\|top\\|bottom`, `distance`                                   |\n| `kinetic-chars` | per-char pop        | `at`, `duration`, `stagger`, `pattern=pop\\|fade` — element needs `<span class=\"char\">` children |\n| `typewriter`    | per-char fade       | same as kinetic-chars but slower default stagger                                                |\n| `count-up`      | animate number      | `at`, `duration`, `from`, `to`, `format=.0f\\|.1f\\|.2f\\|,d`                                      |\n| `draw-path`     | SVG path reveal     | `at`, `duration` — element should be a `<path>`                                                 |\n| `grow-y`        | bar height          | `at`, `duration`, `target-h` (px) — element starts `height:0`                                   |\n| `grow-x`        | bar width           | `at`, `duration`, `target-w` (px) — element starts `width:0`                                    |\n| `scale-pop`     | pop entrance        | `at`, `duration`                                                                                |\n| `blur-in`       | unfocused → focused | `at`, `duration`                                                                                |\n| `mask-reveal`   | clip reveal         | `at`, `duration`, `direction=left\\|right\\|top\\|bottom`                                          |\n| `morph-to`      | tween any CSS       | `at`, `duration`, `props='{...JSON...}'`                                                        |\n\n`data-anim-at` is **seconds relative to the card's startSec** — when you\ncompile each declaration into the GSAP timeline in Step 9, add the\ncard's `startSec` to get the absolute time and quantize to 1/fps.\n\n### 9. Assemble the Composition HTML\n\nStage the assets and write `$WORK_DIR/public/index.html`:\n\n```bash\n# SKILL_DIR is injected by the host (\"Base directory for this skill: …\")\nSKILL_DIR=\"<SKILL_DIR>\"\n\nmkdir -p \"$WORK_DIR/public/fonts\" \"$WORK_DIR/public/vendor\" \"$WORK_DIR/public/cards\"\ncp -n \"$SKILL_DIR/assets/fonts/\"*            \"$WORK_DIR/public/fonts/\"\ncp -n \"$SKILL_DIR/assets/vendor/gsap.min.js\" \"$WORK_DIR/public/vendor/\"\n# stage the input video — RE-ENCODE with dense keyframes. Sources with a sparse GOP\n# (keyframe interval > ~1s) freeze on seek in the renderer (a frozen frame under the\n# overlays); -g / -keyint_min set to your composition fps make every frame seekable.\n# (Set both to your fps — 30 shown; use 24/25/60 to match.)\nffmpeg -y -i \"$VIDEO_PATH\" -c:v libx264 -crf 18 -g 30 -keyint_min 30 \\\n  -pix_fmt yuv420p -movflags +faststart -c:a aac \"$WORK_DIR/public/input-video.mp4\"\n```\n\n#### Composition Template\n\n```html\n<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <style>\n      @font-face {\n        font-family: \"Caveat\";\n        src: url(\"fonts/Caveat-400-latin.woff2\") format(\"woff2\");\n        font-weight: 400;\n        font-display: block;\n      }\n      @font-face {\n        font-family: \"Caveat\";\n        src: url(\"fonts/Caveat-700-latin.woff2\") format(\"woff2\");\n        font-weight: 700;\n        font-display: block;\n      }\n      @font-face {\n        font-family: \"LXGW WenKai TC\";\n        src: url(\"fonts/LXGWWenKaiTC-400-latin.woff2\") format(\"woff2\");\n        font-weight: 400;\n        font-display: block;\n      }\n      @font-face {\n        font-family: \"Inter\";\n        src: url(\"fonts/Inter-400-latin.woff2\") format(\"woff2\");\n        font-weight: 400;\n        font-display: block;\n      }\n      @font-face {\n        font-family: \"Inter\";\n        src: url(\"fonts/Inter-700-latin.woff2\") format(\"woff2\");\n        font-weight: 700;\n        font-display: block;\n      }\n      @font-face {\n        font-family: \"Virgil\";\n        src: url(\"fonts/Virgil.woff2\") format(\"woff2\");\n        font-display: block;\n      }\n\n      :root {\n        /* Pick from the themeId palette table in Step 7 — example: classic */\n        --bg: #fff9e3;\n        --text: #1e1e1e;\n        --accent-0: #1971c2;\n        --accent-1: #e03131;\n        --accent-2: #2f9e44;\n        --accent-3: #e8590c;\n        --accent-4: #9c36b5;\n        --font-family: \"Caveat\", \"LXGW WenKai TC\", serif;\n      }\n      * {\n        box-sizing: border-box;\n      }\n      /* Body font-family MUST list concrete font names (not just var(--font-family)) —\n   the HyperFrames renderer's static analyzer doesn't expand CSS variables when\n   resolving fonts, so a var-only chain triggers `font_family_without_font_face`\n   lint and falls back to a generic. Use the concrete chain here; cards that\n   want the theme font can still reference var(--font-family) internally. */\n      html,\n      body {\n        margin: 0;\n        padding: 0;\n        width: 100%;\n        height: 100%;\n        overflow: hidden;\n        background: #000;\n        font-family: \"Inter\", \"Caveat\", \"LXGW WenKai TC\", ui-sans-serif, system-ui, sans-serif;\n      }\n      #stage {\n        position: relative;\n        width: 100%;\n        height: 100%;\n        overflow: hidden;\n      }\n\n      /* video-wrapper holds the source video. Its position / size are animated\n   over time by the master timeline (one tween per layout transition). */\n      .video-wrapper {\n        position: absolute;\n        left: 0;\n        top: 0;\n        width: 1920px;\n        height: 1080px;\n        overflow: hidden;\n        border-radius: 0;\n        box-shadow: none;\n      }\n      .video-wrapper video {\n        width: 100%;\n        height: 100%;\n        object-fit: cover;\n      }\n\n      .card-host {\n        position: absolute;\n        pointer-events: none;\n        overflow: hidden;\n      }\n      .card-host .card {\n        position: relative;\n        width: 100%;\n        height: 100%;\n        overflow: hidden;\n      }\n      .card-host .char {\n        display: inline-block;\n        visibility: visible;\n      }\n\n      /* Subtle drop shadow + rounded corners for non-fullscreen video framings */\n      .video-wrapper.framed {\n        border-radius: 16px;\n        box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);\n      }\n    </style>\n  </head>\n  <body>\n    <div\n      id=\"stage\"\n      data-composition-id=\"talking-head-recut\"\n      data-start=\"0\"\n      data-duration=\"121.2\"\n      data-fps=\"30\"\n      data-width=\"1920\"\n      data-height=\"1080\"\n    >\n      <!-- Layer 1: source video — initial position matches card-01's layout -->\n      <div class=\"video-wrapper\" id=\"video-wrap\">\n        <video\n          id=\"bg-video\"\n          src=\"input-video.mp4\"\n          playsinline\n          data-has-audio=\"true\"\n          data-start=\"0\"\n          data-duration=\"121.2\"\n          data-track-index=\"1\"\n        ></video>\n      </div>\n\n      <!-- Layer 2: each card-host sits at the bounds dictated by its layout. -->\n      <!-- IMPORTANT: every card-host MUST carry BOTH \"card-host\" and \"clip\" classes. -->\n      <!--   - \"card-host\"  → our positioning + pointer-events styles                 -->\n      <!--   - \"clip\"       → the \n\nFile v1.0.16:_meta.json\n\n{\n  \"ownerId\": \"kn77d06grj6xqp3dqwkk4bavhn89pegt\",\n  \"slug\": \"talking-head-recut\",\n  \"version\": \"1.0.16\",\n  \"publishedAt\": 1791142434907\n}\n\nFile v1.0.16:references/DESIGN_INDEX.md\n\n# V—Take Visual Design Library\n\nThis directory is a **reference library** for the talking-head-recut skill. Style, layout,\nand video frame are three **orthogonal** dimensions you can freely mix when\ndesigning a takeaway video.\n\n```\nStyle  ×  Layout  ×  VideoFrame\n (10)      (4)         (3)        = 120 possible combinations\n```\n\nRead a reference file when you decide to use that dimension. Each file is a\nself-contained HTML fragment that follows the talking-head-recut card-HTML contract\n(scoped `<style>`, no `<script>`, no external URLs, animations only via\n`data-anim-*`).\n\n## Layouts — how video and card share the canvas\n\n| key       | file                                         | what it does                                            | best for                                |\n| --------- | -------------------------------------------- | ------------------------------------------------------- | --------------------------------------- |\n| `split`   | [layouts/split.html](layouts/split.html)     | 50/50 side-by-side (landscape) or top/bottom (portrait) | speaker + data equal weight             |\n| `stack`   | [layouts/stack.html](layouts/stack.html)     | video on top (~52%), card below                         | talking-head with summary card          |\n| `pip`     | [layouts/pip.html](layouts/pip.html)         | card fills canvas, video rounded PiP in corner          | content-heavy moment, speaker secondary |\n| `overlay` | [layouts/overlay.html](layouts/overlay.html) | video full-bleed, glass card floats on bottom           | cinematic / dramatic moments            |\n\nA layout is a **two-part recipe**: pick a `card.zone` value to put in\n`storyboard.json` AND author a GSAP tween for `#video-wrap` to its\ntarget rect in the composition's `<script>`. Open the layout file's\nheader for the recommended `zone` + the GSAP statement to paste.\n(Earlier docs referenced a `card.layout` field — that field does NOT\nexist in the real schema; the strict v3 schema only has `card.zone`.)\n\n## Styles — the card's visual language\n\n| key          | file                                             | character                                            | accent    | suggested font      |\n| ------------ | ------------------------------------------------ | ---------------------------------------------------- | --------- | ------------------- |\n| `academic`   | [styles/academic.html](styles/academic.html)     | warm paper · grid · serif · blue highlight           | `#2557a7` | serif               |\n| `editorial`  | [styles/editorial.html](styles/editorial.html)   | cream · coral block · big italic quote               | `#ff3a2d` | Playfair-like serif |\n| `minimal`    | [styles/minimal.html](styles/minimal.html)       | pure black/white · huge type · generous space        | `#000`    | Inter               |\n| `spotlight`  | [styles/spotlight.html](styles/spotlight.html)   | dark purple gradient · glow · dramatic               | `#a78bfa` | sans                |\n| `geom`       | [styles/geom.html](styles/geom.html)             | chartreuse + hot pink + black collision              | `#d4ff00` | Inter bold          |\n| `whiteboard` | [styles/whiteboard.html](styles/whiteboard.html) | paper · Caveat handwriting · sketched borders        | `#ff6b35` | Caveat              |\n| `audit`      | [styles/audit.html](styles/audit.html)           | manila paper · justified serif · APPROVED stamp      | `#8b1d1d` | serif               |\n| `terminal`   | [styles/terminal.html](styles/terminal.html)     | dark · monospace · ASCII border · prompt cursor      | `#4ade80` | mono                |\n| `swiss`      | [styles/swiss.html](styles/swiss.html)           | white · Helvetica · strict double rules · red accent | `#e8190f` | Helvetica/Inter     |\n| `xhs`        | [styles/xhs.html](styles/xhs.html)               | cream + hot pink · chips · #hashtags · ❤️💬 row      | `#ff2e63` | sans                |\n\nChoose by content tone, not by content type — `academic` works for finance\ntoo if the tone is reflective; `terminal` works for non-tech if the tone is\n\"engineering rigor\".\n\n## Video Frames — decoration around the video element\n\n| key        | file                                         | character                                                    | when to skip                                     |\n| ---------- | -------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------ |\n| `clean`    | [frames/clean.html](frames/clean.html)       | no decoration; raw video                                     | default; safest                                  |\n| `hairline` | [frames/hairline.html](frames/hairline.html) | double-stroke + four-corner viewfinder ticks                 | over `overlay` layout (clashes with full-bleed)  |\n| `polaroid` | [frames/polaroid.html](frames/polaroid.html) | white photo frame + Caveat label + blue washi tape (no tilt) | over `overlay` layout; portrait PiP gets cramped |\n\nA frame is a decorative div that sits **next to** the `#video-wrap` inside\nthe composition's `#stage`. It is one-time HTML (not animated), but you can\nfade it in/out across cards. See each frame file for the placement snippet\nand the inline `<style>` it needs.\n\n## Decision guide (loose, not prescriptive)\n\n| video content                    | suggested combos                                         |\n| -------------------------------- | -------------------------------------------------------- |\n| interview / dialogue             | `academic` × `stack`, `audit` × `split`                  |\n| product launch / announcement    | `editorial` × `overlay`, `geom` × `pip`                  |\n| data analysis / financial report | `audit` × `split`, `swiss` × `stack`, `terminal` × `pip` |\n| social clip (9:16)               | `xhs` × `overlay`, `editorial` × `stack`                 |\n| technical tutorial               | `terminal` × `split`, `whiteboard` × `pip`               |\n| emotional story / narration      | `spotlight` × `overlay`, `whiteboard` × `overlay`        |\n| minimalist presentation          | `minimal` × `split`, `swiss` × `overlay`                 |\n\nThese are starting points only. Look at the transcript, pick the tone, then\npick the visual.\n\n## Portrait sizing — bigger type for mobile\n\nEvery `references/styles/*.html` is sized for a **1920×1080 landscape**\npreview. When the final composition is **portrait (1080×1920)** — the\ndefault for social / mobile — scale every visual size up so it reads on a\nphone held close.\n\n| token                 | landscape | **portrait** | scale |\n| --------------------- | --------- | ------------ | ----- |\n| hero title (h1/h2)    | 64–96px   | **88–132px** | ×1.35 |\n| detail / body         | 24–30px   | **30–40px**  | ×1.30 |\n| kicker / chip / meta  | 14–18px   | **18–22px**  | ×1.25 |\n| primary number / stat | 48–60px   | **64–88px**  | ×1.40 |\n| horizontal padding    | 40–64px   | **24–36px**  | ÷1.5  |\n\n`portraitPx ≈ round(landscapePx × 1.3)`. Hero headlines can go ×1.4;\nsmall meta stays at ×1.2. Padding **shrinks** in portrait since the card\nis narrower.\n\nFor a card that must work in both, use a container query on the card\nroot: `container-type: inline-size` + `font-size: clamp(64px, 8.5cqi, 132px)`.\n\n## Source aspect ratio independence\n\nOutput canvas is independent of source video aspect. Three supported\noutput ratios (selected by the user in Step 7.0 of SKILL.md):\n\n| ratio  | canvas    | `storyboard.layout`                                    | best for                                                   |\n| ------ | --------- | ------------------------------------------------------ | ---------------------------------------------------------- |\n| `16:9` | 1920×1080 | `\"landscape\"`                                          | YouTube / TV / desktop playback                            |\n| `9:16` | 1080×1920 | `\"portrait\"`                                           | TikTok / Reels / short-form mobile                         |\n| `4:5`  | 1080×1350 | `\"portrait\"` (schema treats 4:5 as portrait since h>w) | Instagram feed / WeChat Moments / works for both platforms |\n\nThe layout reference files in `layouts/` document **landscape** and\n**portrait** bounds only. For **4:5** derive bounds by proportional\nvertical scaling from portrait: `4:5 y/h = round(portrait y/h × 0.703)`,\nkeep `x/w` identical. The composer doesn't care about the named layout\nvalue; it just uses `composition.width × height`.\n\n- Landscape video on landscape canvas → `videoBounds` matches video aspect, no letterbox\n- Portrait video on landscape canvas → `videoBounds` is a narrower box (e.g. `pip` becomes 248×440); empty side filled by card or background\n- Landscape video on portrait canvas → `videoBounds` becomes a wide-but-short band; `stack` and `overlay` work best\n- Portrait video on portrait canvas → most natural; any layout\n\nThe layout reference files show landscape values; for portrait you usually\nflip the long axis: `split` becomes top/bottom, `pip` video bubble shrinks\n~20%, `overlay` card slot widens to full width.\n\n## Constraints you must obey when copying from these references\n\n1. **No `<script>`** — animations only via `data-anim-*` attributes\n2. **No external URLs** — no Google Fonts CDN, no remote images; the\n   skill provides Caveat / LXGW WenKai TC / Inter / Virgil locally\n3. **All `<style>` rules must be prefixed with `.card[data-card-id=\"...\"]`** —\n   the hyperframes sanitizer auto-scopes them, but write them already-scoped to\n   stay readable\n4. **No `on*=` inline handlers**\n5. **CSS variables for colors** when you want a card to switch theme cleanly;\n   inline hex when you want this specific style's signature look\n\nIf a reference uses a font you don't have, fall back:\n\n- Playfair Display / Noto Serif SC → `ui-serif, \"Songti SC\", \"Times New Roman\", serif`\n- Noto Sans SC → `ui-sans-serif, system-ui, sans-serif`\n- JetBrains Mono → `ui-monospace, \"SF Mono\", Menlo, monospace`\n- Kalam → `'Caveat', cursive`\n\nFile v1.0.16:NOTICE.md\n\n# Attribution\n\nThe `talking-head-recut` skill (its card-based design system — styles, layouts, frames,\nfonts, and the GSAP-driven composition workflow) is **adapted from** the open-source\n**vtake-skills** project (`vtake-cut`):\n\n> https://github.com/notedit/vtake-skills\n\nAdaptations for this repo: renamed to `talking-head-recut`; transcription repointed to\nlocal Whisper via `hyperframes transcribe` (dropping the third-party `@notedit/vtake`\nCLI and the `vtake.app` proxy); audio/metadata extraction inlined with `ffmpeg`/`ffprobe`;\nthe fixed third-party brand outro removed in favour of an optional, neutral outro;\nartifacts aligned to the `videos/<project>/` convention.\n\nThe original is MIT-licensed; its notice is retained below as required.\n\n```\nMIT License\n\nCopyright (c) 2026 leeoxiang\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n\nFile v1.0.16:skill-card.md\n\n## Description:\n\nAdds transcript-timed graphic overlays to an existing talking-head video while preserving the underlying clip.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[heygen-com](https://clawhub.ai/user/heygen-com)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nVideo editors and creators use this skill to add designed titles, quotes, data callouts, and other timed graphics to an existing interview, podcast, or talking-head clip.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Running or updating an unpinned external HyperFrames CLI can change the code the agent executes.\n\nMitigation: Review or pin the HyperFrames version before use, and confirm skill updates before running them.\n\nRisk: Extracted audio and transcripts may remain in the project work directory.\n\nMitigation: Avoid sensitive videos unless local storage of their audio and transcripts is acceptable.\n\n## Reference(s):\n\n- [Talking Head Recut on ClawHub](https://clawhub.ai/heygen-com/skills/talking-head-recut)\n- [Visual design reference library](references/DESIGN_INDEX.md)\n\n## Skill Output:\n\n**Output Type(s):** [Code, Shell commands, Guidance]\n\n**Output Format:** [Markdown guidance with HTML and JSON files, plus a rendered MP4 video]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces a storyboard, transcript, graphic-card HTML, a composition, and a rendered video.]\n\n## Skill Version(s):\n\n1.0.16 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.15: 24 files, 92253 bytes\n\nFiles: assets/vendor/gsap.min.js (72925b), media-contract.test.mjs (912b), NOTICE.md (1826b), references/DESIGN_INDEX.md (10171b), references/frames/clean.html (2626b), references/frames/hairline.html (5921b), references/frames/polaroid.html (5349b), references/layouts/overlay.html (5463b), references/layouts/pip.html (4650b), references/layouts/split.html (3805b), references/layouts/stack.html (3458b), references/styles/academic.html (6043b), references/styles/audit.html (6182b), references/styles/editorial.html (6586b), references/styles/geom.html (5776b), references/styles/minimal.html (4142b), references/styles/spotlight.html (4941b), references/styles/swiss.html (6053b), references/styles/terminal.html (6957b), references/styles/whiteboard.html (5829b), references/styles/xhs.html (7210b), skill-card.md (1818b), SKILL.md (65725b), _meta.json (138b)\n\nFile v1.0.15:SKILL.md\n\n---\nname: talking-head-recut\ndescription: Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, side panels, picture-in-picture — synced to the transcript, on a 16:9 / 9:16 / 4:5 canvas of your choice; the clip plays untouched underneath. Trigger on \"graphic overlays\", \"on-screen graphics\", \"package / dress up my video\". Not plain subtitles (/embedded-captions). Unclear → /hyperframes.\n---\n\n**Plugin installs:** Before setup or freshness commands, follow [plugin execution rules](../hyperframes/references/plugin-installation.md) when this skill is inside a HyperFrames plugin. Standalone installs keep the update instructions below.\n\n> **First, keep this skill fresh — confirm with the user before running:** `npx hyperframes skills update talking-head-recut`. A fast no-op when everything is current; otherwise it refreshes this skill plus the core domain skills it depends on before you rely on them.\n\n# Talking Head Recut\n\nTalking Head Recut takes a local video that **plays in full** and layers a sequence of\ntimed, designed **graphic cards** onto it — titles, lower-thirds, data callouts,\nquotes, side panels, picture-in-picture — synced to what's being said. The agent\ndesigns the cards (timing + content) and **writes each card's HTML directly in the\nconversation**, then assembles a single composition HTML and renders it to MP4 via\n`hyperframes`. There is no fixed archetype list and no prescribed card structure —\nthe overlays emerge from what the transcript actually says.\n\n> **The front door is `/hyperframes`.** This skill packages an **existing talking-head clip** with **designed graphic cards** (titles, lower-thirds, data callouts, quotes, side panels, PiP) — not plain captions (the spoken words as text). **The clip plays untouched.** Any other intent — plain subtitles, a standalone graphic, a from-scratch video — or any uncertainty → read `/hyperframes` first: the intent layer owns every route decision.\n\n> **Graphic-packaging sibling of `embedded-captions`.** Captions add the _spoken words_\n> as a readable subtitle; this adds _designed graphics_ on top of the playing video.\n> Plain subtitles → `embedded-captions`. Build a video from scratch → the creation\n> workflows (`product-launch-video` / `faceless-explainer` / …).\n\nRouted through `/hyperframes`, the intent layer confirms only the input (which clip) and **announces** the render-strategy questions as deferred asks — aspect, layout, style group, and card count stay at Step 7, where the probed footage and transcript ground the recommendations; the layer's run-shape questions don't apply. A `BRIEF.md`, when present, carries the confirmed input and any user notes — read it first.\n\nInspectable intermediate files in the work directory:\n\n- `metadata.json` — duration / width / height / fps\n- `audio.mp3` — extracted audio\n- `transcript.json` — a flat **word array** `[{ text, start, end }, …]` (Whisper; no `segments`, no `words` wrapper)\n- `storyboard.json` — lightweight card outline (the agent's plan)\n- `public/cards/card-XX.html` — one HTML fragment per card\n- `public/index.html` — final assembled composition\n- `output.mp4` — rendered video\n\n## CLI Resolution\n\n```bash\n# hyperframes — transcription (local Whisper) + rendering the assembled HTML to MP4\nnpx hyperframes --help\n```\n\nThis skill runs entirely on the **hyperframes** CLI plus system `ffmpeg` / `ffprobe`.\nTranscription is local **Whisper** via `hyperframes transcribe` — no third-party\nservice, API key, or rate-limited proxy.\n\n## Workflow\n\n### 1. Check Environment\n\n```bash\nnpx hyperframes doctor          # ffmpeg, headless browser, render deps\n# confirm bundled assets:\nls \"<SKILL_DIR>/assets/fonts\" \"<SKILL_DIR>/assets/vendor/gsap.min.js\"\n```\n\nRequired:\n\n- `ffmpeg` / `ffprobe` (system)\n- `<SKILL_DIR>/assets/fonts/*.woff2`, `<SKILL_DIR>/assets/vendor/gsap.min.js` (bundled inside this skill, staged to work dir in Step 9)\n\nTranscription needs no key — `hyperframes transcribe` runs Whisper locally (Step 4).\n\nStrongly recommended on macOS for `hyperframes render`:\n\n```bash\nexport PRODUCER_BROWSER_GPU_MODE=hardware\n```\n\n### 2. Create a Work Directory\n\nAll artifacts live under `videos/<project-name>/` — the same convention as the other\nvideo workflows (`product-launch-video` / `faceless-explainer` / `pr-to-video`). Keep\nthe cwd at the workspace root; everything below writes under this one subdirectory.\n\n```bash\nVIDEO_PATH=\"/absolute/path/input.mp4\"\nWORK_DIR=\"videos/$(basename \"$VIDEO_PATH\" | sed 's/\\.[^.]*$//')\"\nmkdir -p \"$WORK_DIR\"\n```\n\n### 3. Extract Audio and Metadata\n\n```bash\n# metadata — duration / width / height / fps\nffprobe -v error -select_streams v:0 \\\n  -show_entries stream=width,height,r_frame_rate \\\n  -show_entries format=duration -of json \"$VIDEO_PATH\" > \"$WORK_DIR/metadata.json\"\n# audio\nffmpeg -y -i \"$VIDEO_PATH\" -vn -acodec libmp3lame -q:a 2 \"$WORK_DIR/audio.mp3\"\n```\n\nOutputs: `metadata.json` (read `width`/`height`/`duration`; fps = the `r_frame_rate`\nfraction evaluated, e.g. `30000/1001 → 29.97`) + `audio.mp3`.\n\n### 4. Transcribe\n\n```bash\nnpx hyperframes transcribe \"$WORK_DIR/audio.mp3\" -d \"$WORK_DIR\" --json --model small.en\n```\n\nLocal **Whisper** — no API key, no proxy, no rate limit. Writes a word-level\n`transcript.json` into the work dir (word `text` + `start` / `end` timestamps).\nRead it for the word / sentence timings that drive card timing in Step 6; group\nwords into sentences yourself at punctuation / pauses if you need segment-level\nchunks.\n\n**Clamp to media duration.** Whisper can return the final word's `end` a hair past the\nactual clip length — clamp every card `endSec` and `composition.durationSeconds` to the\n`metadata.json` duration, or the render will show a black tail past the video.\n\n### 5. Correct Transcript\n\n`transcript.json` is a **flat array of word objects** — `[{ \"text\": \"...\", \"start\": s, \"end\": s }, …]` (no `segments` array, no `words` wrapper; the per-word key is **`text`**). Read it and fix obvious ASR errors:\n\n- Homophones, product names, technical terms, punctuation\n- Edit a word's `text` in place; **preserve its `start` / `end`** timestamps\n- There is no pre-grouped `segments` array — **group words into sentences yourself** (split at terminal punctuation / pauses) when you need segment-level chunks for card timing\n\n### 6. Draft a Lightweight Storyboard (in chat)\n\n**No CLI involved.** Read `transcript.json` + `metadata.json` and design\ncards directly. `storyboard.json` is an agent-internal planning artifact\n— no CLI command consumes it; it exists so you can think clearly\nabout timing and content before writing each card's HTML. Keep the\nshape consistent with the example below so the same outline can drive\nthe composition you author in Step 9:\n\n```json\n{\n  \"schemaVersion\": 3,\n  \"composition\": {\n    \"fps\": 30,\n    \"width\": 1080,\n    \"height\": 1920,\n    \"durationSeconds\": 121.2,\n    \"layout\": \"portrait\",\n    \"themeId\": \"noir\",\n    \"seed\": 42\n  },\n  \"videoTrack\": {\n    \"sourcePath\": \"input-video.mp4\",\n    \"startSec\": 0,\n    \"endSec\": 121.2,\n    \"bounds\": { \"x\": 0, \"y\": 0, \"width\": 1080, \"height\": 1920 }\n  },\n  \"subtitles\": { \"enabled\": false },\n  \"cards\": [\n    {\n      \"id\": \"card-01\",\n      \"intent\": \"Hook with the speaker's anxious midnight question\",\n      \"startSec\": 0.5,\n      \"endSec\": 13.0,\n      \"accentIndex\": 0,\n      \"zone\": \"fullscreen\",\n      \"contentHints\": {\n        \"kicker\": \"AN HONEST QUESTION\",\n        \"title\": \"The soul-searching question at 11 PM\",\n        \"detail\": \"Client's 60-second voice message: 'If the RMB appreciates, does that mean my USD policy is a terrible loss?'\"\n      }\n    }\n  ]\n}\n```\n\n**Required Card fields:**\n\n| field                   | type                                       | purpose                                                                                               |\n| ----------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------- |\n| `id`                    | string                                     | stable id used in card HTML & GSAP selectors                                                          |\n| `intent`                | string                                     | natural-language description; fed to card synthesis                                                   |\n| `startSec` / `endSec`   | number                                     | times in seconds (endSec > startSec)                                                                  |\n| `accentIndex`           | 0 \\| 1 \\| 2 \\| 3 \\| 4                      | which of the 5 theme accent colors this card pulls                                                    |\n| `zone`                  | enum (see below)                           | where on the canvas the card lives                                                                    |\n| `contentHints`          | object                                     | free-form bag; agent puts kicker/title/detail/data/quote here                                         |\n| `archetype` (optional)  | string                                     | free-form label you may attach to remember a card's pattern; absent = free-form, which is the default |\n| `transition` (optional) | enum: `cut` \\| `fade` \\| `slide` \\| `wipe` | declarative card-to-card transition                                                                   |\n\n**Five `zone` values:**\n\n| zone              | resolved bounds                                | when to use                             |\n| ----------------- | ---------------------------------------------- | --------------------------------------- |\n| `fullscreen`      | covers whole canvas                            | hero moments, big numbers, mantras      |\n| `whiteboard-area` | inset 40px margin (or 45% of portrait height)  | dense data / annotated content          |\n| `lower-third`     | bottom 30% band                                | annotation over visible video           |\n| `side-panel`      | right 42% (landscape) or bottom 40% (portrait) | data side, video other side             |\n| `video-overlay`   | full canvas, expects mostly-transparent card   | annotation overlays on full-bleed video |\n\nWhen you assemble the composition in Step 9, resolve each card's `zone`\ninto pixel bounds on the card-host wrapper following the table above.\nVideo bounds are set **once** at composition level (`videoTrack.bounds`);\nto make video appear to \"move between cards\", author GSAP tweens against\n`#video-wrap` in the composition's `<script>` (see Step 9).\n\n**No prescribed card roles, no prescribed narrative arc.** Cards emerge\nfrom what the video actually says — could be all quotes or all data,\ncould open with a number or with a story. Let the transcript drive the\nrhythm.\n\n**How many takeaways? — auto-infer from duration + density.** No fixed\nupper limit. Pick a **base pace** from the video duration, then adjust\nby **information density**. Only **floor is fixed: minimum 5 cards** so\neven short videos have rhythm.\n\n**Step 1 — base pace by duration** (the natural sec/card for medium density):\n\n| video duration     | base pace (sec per card) | rationale                                   |\n| ------------------ | ------------------------ | ------------------------------------------- |\n| < 60s (short reel) | **6–8s**                 | viewers expect fast cuts in short-form      |\n| 60s – 3 min        | **8–12s**                | normal social pace                          |\n| 3 – 10 min         | **12–20s**               | give breathing room; each card carries more |\n| 10 – 30 min        | **20–35s**               | long-form lecture / interview rhythm        |\n| > 30 min           | **30–60s**               | episodic, near-chapter feel                 |\n\n**Step 2 — density multiplier** (multiplies the base pace):\n\n| signal in the transcript                                                                                                    | multiplier | effect                   |\n| --------------------------------------------------------------------------------------------------------------------------- | ---------- | ------------------------ |\n| **High density** — many numbers, distinct claims, staccato pacing, list-like enumeration, every 1–2 sentences is a new idea | **× 0.7**  | cuts faster, more cards  |\n| **Medium density** — mixed flow with both data and narrative                                                                | **× 1.0**  | base pace                |\n| **Low density** — one extended story, repeated reframing, slow reflective pacing, single argument unfolding                 | **× 1.5**  | cuts slower, fewer cards |\n\n**Step 3 — compute:**\n\n```\nsecPerCard = basePace × densityMultiplier\ncardCount  = max(5, round(videoDurationSec / secPerCard))\n```\n\nExamples (notice — **no upper clamp**; long videos naturally produce more cards):\n\n- **30s reel, single punchline (low density)** → 7 × 1.5 = 10.5s/card → round(30/10.5)=3 → floor to **5** cards\n- **60s reflective monologue (low density)** → 10 × 1.5 = 15s/card → **4** → floor to **5** cards\n- **121s talking-head with rich data (high density)** → 10 × 0.7 = 7s/card → **17** cards\n- **5 min interview, mixed density** → 16 × 1.0 = 16s/card → **19** cards\n- **10 min deep-dive, high density** → 16 × 0.7 = 11s/card → **55** cards\n- **30 min lecture, medium density** → 28 × 1.0 = 28s/card → **64** cards\n- **1 hr podcast, low density** → 45 × 1.5 = 67.5s/card → **53** cards\n\nWhen a card holds longer than ~15s, plan for a richer card (data block,\nmulti-step reveal, several sub-points unfolding with staggered\nanimations) — a static one-liner gets boring past 8s. For long pieces\nwhere many cards exceed 30s, consider **chunking the timeline into\nsub-compositions** (one .html per chapter, mounted with\n`data-composition-src`) so the GSAP timeline per file stays manageable\n— see the `timeline_track_too_dense` HyperFrames lint warning.\n\n`content` can be a plain string (\"Title: annualized 5.69%\\nNotes: ...\") or any JSON\nshape that captures the data. The agent decides the shape per card.\n\n**Optional outro.** This skill ships **no fixed brand outro**. If the user wants a closing card, design a neutral one yourself (wordmark + one-line tagline, ~1.5-2s, fade in -> short hold -> fade out), append it to `cards[]`, and extend `composition.durationSeconds` to its `endSec`. Otherwise end on the last content card.\n\n### 7. Decide Render Strategy\n\n#### Confirm Visual Direction with User (DO THIS FIRST)\n\nBefore you start designing cards or deciding bounds, **ask the user to\npick the output ratio, the layout, the style, and the card-density\npreset**. Frames are auto-selected from the chosen layout × style\ncombination (see \"Auto-pick frame\" table below). Before sending the\nquestion, **precompute two things**:\n\n1. **`recommendedRatio`** from the source video's aspect ratio\n   (`metadata.json` width / height):\n   - `sourceAspect = width / height`\n   - `sourceAspect ≥ 1.5` (≥ ~3:2 wide) → recommend **`16:9`**\n   - `sourceAspect ≤ 0.7` (≤ ~9:13 tall) → recommend **`9:16`**\n   - `0.7 < sourceAspect < 1.5` (near-square) → recommend **`4:5`**\n\n   Mark the recommended option's label with \" (recommended · matches source video X:Y)\"\n   so the user sees why it's recommended.\n\n2. **`autoCount`** from Step 6 (`max(5, round(videoSec / (basePace ×\ndensityMultiplier)))`) so the \"auto\" option's label can show the\n   concrete number.\n\n**Environment compatibility — pick the best available question channel.**\nNot every runtime exposes the same structured-question tool. Apply this\norder:\n\n1. **Native clarification tool** — use the structured 4-question call below.\n2. **Other native clarification tool** (e.g. `ask_question`,\n   `request_user_input`, IDE-specific prompt) — use that tool with the\n   same 4 question texts and option lists. Preserve the recommendation\n   markers and the precomputed values.\n3. **No native tool** (Codex CLI, plain text-only runtimes) — **ask\n   directly in normal conversation**. Use the plain-text template at the\n   end of this section. Keep it to **one message, 4 numbered questions**\n   (the global cap is 2–5 questions per round; we stay inside it).\n\nRules that apply to every channel:\n\n- Ask **at most 2–5 questions per round**. Our 4 here fits.\n- Even if missing info doesn't block rendering, **ask once to confirm\n  the parameters that materially affect the final output** (ratio,\n  layout, style, cardCount).\n- If the user has already pre-approved defaults (\"just use defaults\",\n  \"no need to ask\", \"auto-pick everything\"), asked you not to ask, or the\n  run carries an ongoing autonomous signal (\"surprise me\" / \"decide for me\" —\n  `../hyperframes/references/brief-contract.md` § 1) — **skip\n  the question entirely** and use: `recommendedRatio`, `layout=\"stack\"`\n  (safest cross-ratio default), `style` chosen from transcript tone in\n  the most neutral group (editorial/data), `autoCount`. Tell the user\n  what you picked in one sentence and continue.\n\n**Channel A — native `AskUserQuestion`:**\n\n```\n// Precompute before the call:\n//   recommendedRatio = \"16:9\" | \"9:16\" | \"4:5\"\n//   autoCount        = integer (from Step 6)\n\nAskUserQuestion({\n  questions: [\n    {\n      question: \"Output video aspect ratio (canvas):\",\n      header: \"Aspect ratio\",\n      multiSelect: false,\n      // Reorder so the recommended option appears FIRST (per AskUserQuestion convention).\n      // Append \" (recommended · matches source video W×H)\" to the recommended option's label.\n      options: [\n        { label: \"16:9 (1920×1080) landscape\", description: \"TV / YouTube / desktop playback. Most natural when the source video is already landscape; widest canvas.\" },\n        { label: \"9:16 (1080×1920) portrait\", description: \"TikTok / Reels / short-form mobile. Most natural for portrait source; native mobile experience.\" },\n        { label: \"4:5 (1080×1350) near-portrait\", description: \"Instagram feed / WeChat Moments. Best when source is near-square or you want to cover both platforms.\" }\n      ]\n    },\n    {\n      question: \"Choose the overall layout: how should the video and cards coexist on the canvas?\",\n      header: \"Layout\",\n      multiSelect: false,\n      options: [\n        { label: \"side-by-side (split)\",  description: \"Video and card each take half the canvas. Most stable for interview / data side-by-side; clear visual separation.\" },\n        { label: \"top-bottom (stack)\",    description: \"Video on top (~52%), card below. Classic combo of speaker face + summary card; works well in portrait too.\" },\n        { label: \"picture-in-picture (pip)\", description: \"Card fills the canvas, video shrinks to a rounded corner window. Use when content is primary and speaker is secondary.\" },\n        { label: \"full-screen overlay (overlay)\", description: \"Video plays full-bleed, card floats as a glass layer on top. Strong cinematic / emotional feel.\" }\n      ]\n    },\n    {\n      question: \"Choose the card visual style (style):\",\n      header: \"Style group\",\n      multiSelect: false,\n      // NOTE: these 3 groups intentionally match the frame auto-pick matrix\n      // rows below, so picking a group resolves both `style` group AND the\n      // frame matrix column in one step. Memberships are mutually exclusive.\n      options: [\n        { label: \"warm paper (warm-paper)\", description: \"academic notebook · editorial big-type · whiteboard hand-drawn · xhs social. Best for interview reflections, product launches, lifestyle, emotional stories.\" },\n        { label: \"clinical / cold (clinical)\",   description: \"audit magazine · swiss grid · terminal CLI · minimal modern. Best for financial analysis, investigative reports, technical tutorials, serious presentations.\" },\n        { label: \"experimental / avant-garde (experimental)\", description: \"geom color-clash geometry · spotlight dark-background. Best for short-form highlights, product launches, strong emotion, cinematic feel.\" }\n      ]\n    },\n    {\n      question: \"Card count (takeaway pacing): how many cards to cut?\",\n      header: \"Card count\",\n      multiSelect: false,\n      options: [\n        { label: \"Auto (recommended) · approx N cards\", description: \"Inferred automatically from video duration and information density (see Step 6 rules). This run estimates approx N cards. Substitute the real N (your autoCount) into the label.\" },\n        { label: \"Fewer · approx round(N × 0.6) cards\", description: \"Sparser cuts, each card holds longer — suits reflective / slow-paced content.\" },\n        { label: \"More · approx round(N × 1.5) cards\", description: \"Tighter cuts, faster rhythm — suits staccato / data-dense / short-form highlight content.\" }\n      ]\n    }\n  ]\n})\n```\n\n**About \"Other\"** — `AskUserQuestion` automatically adds an \"Other\" option to the card count question. The user can type a number directly (e.g. \"8\", \"20\") as the cardCount target. Parse the input as an integer: if parsing succeeds → use that value (minimum 5 as a floor); if parsing fails → fall back to \"auto\".\n\n**Channel B — plain-text fallback** (Codex CLI, runtimes without a\nnative question tool). Post this as one normal message, then wait for\nthe reply. Bullet-style 1/2/3/4 keeps the reply parseable:\n\n```\nI need to confirm four visual decisions with you before I start cutting cards:\n\n1) Output aspect ratio (canvas):\n   A. 16:9 landscape (1920×1080) — TV / YouTube / desktop playback\n   B. 9:16 portrait (1080×1920) — TikTok / Reels / short-form mobile\n   C. 4:5 near-portrait (1080×1350) — Instagram feed / works for both platforms\n   ▸ My recommendation:  <recommendedRatio>  (matches source video W×H = <sourceW>×<sourceH>)\n\n2) Overall layout (how video & card coexist):\n   A. split   side-by-side (50/50)\n   B. stack   top-bottom (video top, card bottom)\n   C. pip     picture-in-picture (card full canvas, video rounded corner window)\n   D. overlay full-screen glass overlay (video full-bleed, card glass layer)\n\n3) Card style group (maps to frame auto-pick matrix, pick 1 of 3):\n   A. warm paper (warm-paper)      (academic / editorial / whiteboard / xhs)\n   B. clinical / cold (clinical)   (audit / swiss / terminal / minimal)\n   C. experimental (experimental)  (geom / spotlight)\n\n4) Card count (takeaway pacing):\n   A. Auto (recommended) — approx <autoCount> cards\n   B. Fewer — approx round(<autoCount> × 0.6) cards\n   C. More — approx round(<autoCount> × 1.5) cards\n   D. Give me a specific number (e.g. \"8\", \"20\")\n\nReply format: \"1A 2C 3B 4A\" or natural language is fine.\nIf you want all recommended defaults, reply \"default\" / \"auto\" / \"use all recommendations\".\n```\n\nParsing the plain-text reply:\n\n- Accept loose formats: `\"1A 2C 3B 4A\"`, `\"A C B A\"`, `\"16:9 / pip /\ndata / auto\"`, full sentences, or `default`.\n- If any answer is ambiguous → re-ask only the ambiguous ones (still\n  inside the 2–5 cap).\n- If the user says \"default / auto / use all recommendations\" → skip without re-asking.\n\nAfter the user answers (any channel):\n\n1. **Resolve the output canvas** from the ratio answer — these are the\n   exact `storyboard.composition.width / height` values to write:\n\n   | user choice | composition.width × height | storyboard.layout field                                       |\n   | ----------- | -------------------------- | ------------------------------------------------------------- |\n   | `16:9`      | **1920 × 1080**            | `\"landscape\"`                                                 |\n   | `9:16`      | **1080 × 1920**            | `\"portrait\"`                                                  |\n   | `4:5`       | **1080 × 1350**            | `\"portrait\"` (schema treats 4:5 as portrait — height > width) |\n\n   For **4:5 bounds inside `references/layouts/*.html`** — those files\n   only document landscape (1920×1080) and portrait (1080×1920). For\n   4:5 (1080×1350) derive bounds by **proportional scaling from\n   portrait**: keep horizontal values, scale vertical values by\n   `1350/1920 ≈ 0.703`. Example: `overlay` portrait card =\n   `{ x: 24, y: 1280, w: 1032, h: 564 }` → 4:5 card =\n   `{ x: 24, y: round(1280 × 0.703), w: 1032, h: round(564 × 0.703) }`\n   = `{ x: 24, y: 900, w: 1032, h: 397 }`.\n\n2. **Map the style group to a specific style** by looking at the\n   transcript tone — pick the one that best fits, but stay inside the\n   user's chosen group. If you're unsure between two specific styles\n   inside the group, send a second `AskUserQuestion` with those 2–4\n   specific style options.\n\n3. **Resolve final cardCount** from the density answer:\n\n   | user choice             | final cardCount                           |\n   | ----------------------- | ----------------------------------------- |\n   | Auto (recommended)      | the `autoCount` you already computed      |\n   | Fewer                   | `max(5, round(autoCount × 0.6))`          |\n   | More                    | `round(autoCount × 1.5)` (no upper clamp) |\n   | Other = \"<n>\" (integer) | `max(5, parseInt(n))`                     |\n   | Other = anything else   | fall back to `autoCount`                  |\n\n4. **Auto-pick the video frame** from this table (frames don't ask the\n   user — they follow from layout × style):\n\n   | layout    | warm-paper styles (academic / whiteboard / editorial / xhs) | clinical styles (audit / swiss / terminal / minimal) | experimental styles (geom / spotlight) |\n   | --------- | ----------------------------------------------------------- | ---------------------------------------------------- | -------------------------------------- |\n   | `split`   | `polaroid`                                                  | `hairline`                                           | `clean`                                |\n   | `stack`   | `polaroid`                                                  | `hairline`                                           | `clean`                                |\n   | `pip`     | `clean` (pip pill already has chrome)                       | `clean`                                              | `clean`                                |\n   | `overlay` | `clean` (full-bleed forbids deco frames)                    | `clean`                                              | `clean`                                |\n\n5. **Tell the user what you chose** in one sentence — ratio (+ canvas\n   size), layout, specific style, frame, and final cardCount — then\n   proceed with the rest of Step 7 (per-card layouts, motion patterns).\n6. Record the five values (ratio / layout / style / frame / cardCount)\n   in working memory (no schema field needed); you'll reference them\n   while writing each card's HTML in Step 8 and while reading the\n   matching `references/<dim>/<key>.html` for tokens and structure.\n\nIf the user picks an answer via \"Other\" with a free-text style name not\nin the 10-style library, treat it as a hint to design a fresh card\nvisual yourself, but still anchor on the chosen layout's bounds.\n\n#### Render Strategy Inputs\n\nWith ratio / layout / style / cardCount / frame locked from Step 7.0,\nthe remaining per-card decisions are:\n\n- **Source-video fit inside the GSAP target**: video element has\n  `object-fit: cover` and is clipped to `#video-wrap`'s tween bounds.\n  If you want NO cropping (e.g. portrait source on landscape canvas\n  shouldn't get its top/bottom chopped), aim the tween at a rect that\n  matches the source's aspect ratio and let surrounding canvas show\n  through (or fill with the card / a backdrop).\n- **`card.zone` per card**: derive from your chosen composition layout\n  (split → side-panel, stack → lower-third, pip → fullscreen, overlay\n  → video-overlay), OR pick a different zone for one-off variants\n  (fullscreen for hero / quote, whiteboard-area for dense data).\n- **`accentIndex` per card**: each card pulls one of the 5 theme accent\n  colors. Vary across cards for rhythm; reuse the same index when two\n  cards belong to the same narrative beat.\n- **Motion vocabulary**: pick 2–3 repeatable patterns from\n  `data-anim` kinds (see the table later) and stick to them so the\n  composition feels coherent.\n\nPick from these `themeId` palettes (use them as `--accent-N` /\n`--bg` / `--text` CSS variables in your composition `<style>` block):\n\n| themeId | accent palette (5 colors)                 | board bg          | text      |\n| ------- | ----------------------------------------- | ----------------- | --------- |\n| classic | `#1971c2 #e03131 #2f9e44 #e8590c #9c36b5` | `#FFF9E3` (paper) | `#1e1e1e` |\n| noir    | `#4cc9f0 #f72585 #4ade80 #fb923c #a78bfa` | `#1a1a1a`         | `#f1f1f1` |\n| mint    | `#0077b6 #d62828 #2d6a4f #e76f51 #7209b7` | `#e8faf0`         | `#1b4332` |\n| craft   | `#bf5700 #d62728 #6c757d #e9b54a #3d5a80` | `#f6efe1`         | `#2d2d2d` |\n| slate   | `#0ea5e9 #ef4444 #22c55e #f97316 #a855f7` | `#1e293b`         | `#f1f5f9` |\n| mono    | `#000 #555 #888 #aaa #ccc`                | `#fff`            | `#000`    |\n\nAvailable fonts (woff2 in `<SKILL_DIR>/assets/fonts/`, staged to work dir in Step 9): `Caveat` (handwriting),\n`LXGW WenKai TC` (Chinese hand-script), `Inter` (modern sans), `Virgil`\n(geometric hand). Reference via `@font-face` or `font-family` directly.\n\nFor inspiration on visual patterns, `<SKILL_DIR>/references/styles/`\nships 10 self-contained reference cards (academic / editorial / minimal\n/ spotlight / geom / whiteboard / audit / terminal / swiss / xhs) that\nyou can copy as starting points — but **do not feel constrained to\nmatch any of these**. Each card is your own design.\n\n#### Visual Design Library (<SKILL_DIR>/references/)\n\nBeyond the composition-level `themeId`, the skill ships a richer **reference\nlibrary** at `<SKILL_DIR>/references/` covering three **orthogonal**\nvisual dimensions you can freely mix:\n\n```\nStyle  ×  Layout  ×  VideoFrame\n (10)      (4)         (3)\n```\n\n| dimension  | keys                                                                                              | what it decides                                                          |\n| ---------- | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |\n| **style**  | `academic` `editorial` `minimal` `spotlight` `geom` `whiteboard` `audit` `terminal` `swiss` `xhs` | the card's visual language — fonts, colors, ornament, layout-within-card |\n| **layout** | `split` `stack` `pip` `overlay`                                                                   | how the source video and the card share the canvas                       |\n| **frame**  | `clean` `hairline` `polaroid`                                                                     | the decorative chrome around the video element                           |\n\nRead `<SKILL_DIR>/references/DESIGN_INDEX.md`\nfor the full matrix and a loose decision guide (interview / product launch / data analysis /\nsocial clip / technical tutorial / emotional story …). When you decide to use a specific\nstyle / layout / frame, Read the corresponding file:\n\n- `references/styles/<key>.html` — self-contained card fragment with that\n  style's CSS tokens (colors, fonts, padding, ornament) and a placeholder\n  takeaway. Copy the `.card[data-card-id=\"ref-<key>\"]` style block, rename\n  the data-card-id to your card's id, swap the placeholder content for the\n  real takeaway, and you're done.\n- `references/layouts/<key>.html` — exact `videoBounds` + `cardBounds` for\n  both landscape and portrait, with a copy-paste JSON snippet for\n  `storyboard.json`'s per-card `layout` field.\n- `references/frames/<key>.html` — decorative HTML to add as a sibling of\n  `#video-wrap`, plus placement instructions for the composition CSS.\n\nPick `style × layout × frame` **per card** — you can change all three\nbetween cards as long as the transitions read smoothly. A common rhythm:\nopen `editorial × overlay × clean`, switch to `audit × split × hairline`\nfor the data card, close on `whiteboard × pip × polaroid`.\n\nThe 10 styles are skill-side design tokens, **not composition-level themes** —\nthey don't need to be declared in `storyboard.composition`; they live\ninside each card's HTML. The `themeId` field can still pick a\ncomposition-level palette (table above) that controls page-body background\nand video border chrome.\n\n#### Layout Compositions (Card + Video)\n\nTwo coordinated decisions per card define how it shares the canvas with\nthe source video:\n\n- **`card.zone`** (declared in `storyboard.json`) — one of the 5 schema\n  values; resolve it into pixel bounds (per the table in Step 6) when\n  you write the card-host wrapper's inline `style` in Step 9.\n- **`#video-wrap` bounds at this card's time window** (declared\n  imperatively in the composition's GSAP timeline) — the agent tweens\n  `#video-wrap` to a target rect for each layout transition.\n\nSchema does NOT store per-card video bounds. `videoTrack.bounds` is\n**one-time** at composition level (defaults to full canvas). Video\n\"moving\" between cards is purely a GSAP animation authored in\n`index.html`. There is no `card.layout` field — earlier versions of this\ndoc invented one; the real schema only has `card.zone`.\n\n**4 composition layouts** (from `references/layouts/`) — each is a\nrecipe pairing a `zone` with a `#video-wrap` tween target:\n\n| composition layout | recommended `card.zone` | GSAP target for `#video-wrap` (landscape 1920×1080)                       | GSAP target for `#video-wrap` (portrait 1080×1920)                | when to use                                     |\n| ------------------ | ----------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------------- |\n| `split`            | `side-panel`            | `{ left: 960, top: 0, width: 960, height: 1080 }`                         | `{ left: 0, top: 960, width: 1080, height: 960 }` (bottom half)   | speaker + data side-by-side / 50:50 weight      |\n| `stack`            | `lower-third`           | `{ left: 14, top: 14, width: 1892, height: 548 }` (top 52%)               | `{ left: 0, top: 0, width: 1080, height: 844 }` (top 44%)         | speaker on top + summary card below             |\n| `pip`              | `fullscreen`            | `{ left: 1480, top: 760, width: 400, height: 300 }` + add `.framed` class | `{ left: 690, top: 28, width: 360, height: 203 }` + add `.framed` | content-heavy card + corner pip                 |\n| `overlay`          | `video-overlay`         | `{ left: 0, top: 0, width: 1920, height: 1080 }` (full-bleed)             | `{ left: 0, top: 0, width: 1080, height: 1920 }`                  | cinematic / dramatic / glass card on full video |\n\nFor 4:5 (1080×1350), scale portrait y/h values by `1350/1920 ≈ 0.703`\n(see Step 7.0 Channel A / Channel B `recommendedRatio` resolution\ntable).\n\n**Other zone values for one-off variants** (still uses `card.zone`; no\nfake \"layout\" field):\n\n| `zone`            | resolved bounds                                        | common use                            |\n| ----------------- | ------------------------------------------------------ | ------------------------------------- |\n| `fullscreen`      | covers whole canvas                                    | hero card, video tweens to hidden/pip |\n| `whiteboard-area` | inset 40px margin (landscape) or bottom 45% (portrait) | dense data card, free margins         |\n| `lower-third`     | bottom 30% band                                        | talking-head annotation               |\n| `side-panel`      | right 42% (landscape) or bottom 40% (portrait)         | sidebar / \"split\" recipe              |\n| `video-overlay`   | full canvas; expect transparent card root              | glass overlay on full-bleed video     |\n\nYou can mix recipes per card — choose `card.zone` based on what suits\nthe moment, then write the GSAP tween for `#video-wrap` between cards.\n\n#### Storyboard Render Contract\n\n`storyboard.json` is an agent-internal planning artifact — no CLI\ncommand parses it. It exists to keep your timing and content decisions\nexplicit before you write each card's HTML. Stick to the v3-style\nshape below so the same outline drives the composition you assemble in\nStep 9.\n\nRequired structure (see Step 6 for the full example):\n\n- `schemaVersion: 3`\n- `composition: { fps, width, height, durationSeconds, layout, themeId, seed }` — note `durationSeconds`/`fps`/`themeId`/`layout` live **inside** `composition`, NOT at top level\n- `videoTrack: { sourcePath, startSec, endSec, bounds? }` — video bounds default to full canvas\n- `subtitles: { enabled, ... }`\n- `cards[]` — each card has the 6 required fields: `id`, `intent`, `startSec`, `endSec`, `accentIndex`, `zone`, `contentHints`\n\nRules:\n\n- Card times stay inside `composition.durationSeconds` and should not overlap unless intentional (use `data-track-index` to control z-order when they do).\n- Visual details live in card HTML fragments (Step 8), NOT in `contentHints`. `contentHints` is your own structured prompt for designing the card; the rendered look is the HTML.\n- Keep the storyboard shape stable — even though nothing parses it, you read it back while authoring Step 8/9, and consistency keeps card IDs and timing in sync.\n- Agent-side decisions like \"I picked overlay × geom × clean\" do NOT belong in `storyboard.json` — keep them in working memory and use them when authoring card HTML + GSAP tweens.\n\n**Transparent card backgrounds for cards that share canvas with video.**\nWhen the GSAP tween leaves video visible behind/beside the card (overlay\nrecipe, pip recipe, or any `card.zone = 'lower-third' | 'video-overlay'`\nmoment), the card's `.root` MUST NOT paint a full opaque background —\notherwise it occludes the video. Two patterns:\n\n```css\n/* Pattern A: transparent root, page body provides the cream backdrop */\nhtml,\nbody {\n  background: var(--bg);\n}\n.card[data-card-id=\"card-X\"] .root {\n  background: transparent;\n}\n\n/* Pattern B: explicit per-card background ONLY for fullscreen cards */\n.card[data-card-id=\"card-hero\"] .root {\n  background: var(--bg);\n}\n.card[data-card-id=\"card-overlay\"] .root {\n  background: transparent;\n}\n```\n\nFor `side-panel`-zone cards (split recipe), the card-host is already\nonly half the canvas, so an opaque card bg is fine — it only covers its\nhalf.\n\n### 8. Write Each Card's HTML\n\nCreate `$WORK_DIR/public/cards/{card-id}.html` for each card. Each file\ncontains a single rooted HTML fragment that follows this contract:\n\n#### Card HTML Contract\n\n```html\n<div class=\"card\" data-card-id=\"{cardId}\">\n  <style>\n    /* MUST: every rule starts with .card[data-card-id=\"{cardId}\"] */\n    .card[data-card-id=\"card-01\"] .root {\n      width: 100%; height: 100%;\n      display: flex; ...;\n      font-family: 'Caveat', 'LXGW WenKai TC', serif;\n      color: var(--text);\n      background: var(--bg);\n    }\n    .card[data-card-id=\"card-01\"] .title { font-size: 84px; ... }\n  </style>\n\n  <div class=\"root\">\n    <h1\n      id=\"card-01-title\"\n      data-anim=\"kinetic-chars\"\n      data-anim-at=\"0.3\"\n      data-anim-duration=\"0.5\"\n      data-anim-stagger=\"0.04\"\n      data-anim-pattern=\"pop\"\n    >\n      <span class=\"char\">S</span>\n      <span class=\"char\">u</span>\n    </h1>\n    <div\n      id=\"card-01-line\"\n      data-anim=\"grow-x\"\n      data-anim-at=\"0.65\"\n      data-anim-duration=\"0.5\"\n      data-anim-target-w=\"420\"\n      style=\"width:0;height:8px;background:var(--accent-0);border-radius:4px;\"\n    ></div>\n  </div>\n</div>\n```\n\n**Hard rules** (`hyperframes` lint will reject violations):\n\n- Single root `<div class=\"card\" data-card-id=\"{cardId}\">`\n- Inline `<style>` rules MUST be prefixed with the scope selector above\n- **No `<script>` tags**\n- **No external URLs** in `src=` / `href=` (no CDN, no remote fonts)\n- **No inline event handlers** (`onclick=` etc.)\n- All assets via relative paths into the same `public/` directory\n- Colors via `var(--accent-N)` etc. for portability across themes\n\n**Animations are declared, not coded.** Use `data-anim-*` attributes\nonly; never write `<script>` to animate. You compile every `data-anim-*`\ndeclaration into the single master GSAP timeline in Step 9.\n\n#### Card Sizing — Mobile-First in Portrait\n\nThe 10 `references/styles/*.html` are sized for a **1920×1080 landscape**\npreview. When `storyboard.layout = \"portrait\"` (1080×1920, the dominant\ncase for social / mobile), **scale every visual size up** — phones hold\nthe screen close, and the same pixel count reads smaller than on a\nlandscape TV-style canvas.\n\n| token                     | landscape baseline | **portrait target** | scale         |\n| ------------------------- | ------------------ | ------------------- | ------------- |\n| title (h1/h2 hero)        | 64–96px            | **88–132px**        | ×1.35         |\n| detail / body             | 24–30px            | **30–40px**         | ×1.30         |\n| kicker / chip label       | 14–16px            | **18–22px**         | ×1.30         |\n| timecode / meta           | 12–14px            | **16–18px**         | ×1.30         |\n| data block primary number | 48–60px            | **64–88px**         | ×1.40         |\n| line-height multiplier    | 1.05–1.5           | same                | (don't scale) |\n\n**Rule of thumb:** `portraitPx = round(landscapePx × 1.3)`, then floor\nto a nearby 4px multiple for visual rhythm. Hero headlines may go up to\n×1.4; small meta text stays at ×1.2 to avoid crowding.\n\nPadding **shrinks slightly** in portrait — the card is narrower so big\nlandscape padding (40–64px) eats too much width. Use 24–36px horizontal\npadding in portrait.\n\nIf you're producing a single card that must work in **both** layouts,\nprefer a `@container` query on the card root over hard-coding sizes:\n\n```css\n.card[data-card-id=\"X\"] .root {\n  container-type: inline-size;\n}\n.card[data-card-id=\"X\"] .title {\n  font-size: clamp(64px, 8.5cqi, 132px);\n}\n.card[data-card-id=\"X\"] .detail {\n  font-size: clamp(24px, 3.2cqi, 40px);\n}\n```\n\nBut for most cards, a single layout choice is fine — just pick the size\ntable column that matches the storyboard's `layout` field.\n\n#### Available `data-anim` Kinds\n\nThis list is closed, and deliberately so: a card is an HTML fragment whose motion this\nskill compiles into the shared overlay timeline in Step 9 (see the GSAP mapping table\nthere). That is why this workflow does not search the HyperFrames component registry the\nway the composition workflows do — `npx hyperframes catalog` returns standalone\ncompositions that carry their own timeline, and a card has no place to mount one. Reach a\nlook the kinds below cannot express with plain CSS inside the card's scoped `<style>`.\n\n| kind            | use for             | key params                                                                                      |\n| --------------- | ------------------- | ----------------------------------------------------------------------------------------------- |\n| `fade-in`       | enter               | `at`, `duration`, `ease?`                                                                       |\n| `fade-out`      | exit                | `at`, `duration`, `ease?`                                                                       |\n| `slide-in`      | slide enter         | `at`, `duration`, `from=left\\|right\\|top\\|bottom`, `distance`                                   |\n| `kinetic-chars` | per-char pop        | `at`, `duration`, `stagger`, `pattern=pop\\|fade` — element needs `<span class=\"char\">` children |\n| `typewriter`    | per-char fade       | same as kinetic-chars but slower default stagger                                                |\n| `count-up`      | animate number      | `at`, `duration`, `from`, `to`, `format=.0f\\|.1f\\|.2f\\|,d`                                      |\n| `draw-path`     | SVG path reveal     | `at`, `duration` — element should be a `<path>`                                                 |\n| `grow-y`        | bar height          | `at`, `duration`, `target-h` (px) — element starts `height:0`                                   |\n| `grow-x`        | bar width           | `at`, `duration`, `target-w` (px) — element starts `width:0`                                    |\n| `scale-pop`     | pop entrance        | `at`, `duration`                                                                                |\n| `blur-in`       | unfocused → focused | `at`, `duration`                                                                                |\n| `mask-reveal`   | clip reveal         | `at`, `duration`, `direction=left\\|right\\|top\\|bottom`                                          |\n| `morph-to`      | tween any CSS       | `at`, `duration`, `props='{...JSON...}'`                                                        |\n\n`data-anim-at` is **seconds relative to the card's startSec** — when you\ncompile each declaration into the GSAP timeline in Step 9, add the\ncard's `startSec` to get the absolute time and quantize to 1/fps.\n\n### 9. Assemble the Composition HTML\n\nStage the assets and write `$WORK_DIR/public/index.html`:\n\n```bash\n# SKILL_DIR is injected by the host (\"Base directory for this skill: …\")\nSKILL_DIR=\"<SKILL_DIR>\"\n\nmkdir -p \"$WORK_DIR/public/fonts\" \"$WORK_DIR/public/vendor\" \"$WORK_DIR/public/cards\"\ncp -n \"$SKILL_DIR/assets/fonts/\"*            \"$WORK_DIR/public/fonts/\"\ncp -n \"$SKILL_DIR/assets/vendor/gsap.min.js\" \"$WORK_DIR/public/vendor/\"\n# stage the input video — RE-ENCODE with dense keyframes. Sources with a sparse GOP\n# (keyframe interval > ~1s) freeze on seek in the renderer (a frozen frame under the\n# overlays); -g / -keyint_min set to your composition fps make every frame seekable.\n# (Set both to your fps — 30 shown; use 24/25/60 to match.)\nffmpeg -y -i \"$VIDEO_PATH\" -c:v libx264 -crf 18 -g 30 -keyint_min 30 \\\n  -pix_fmt yuv420p -movflags +faststart -c:a aac \"$WORK_DIR/public/input-video.mp4\"\n```\n\n#### Composition Template\n\n```html\n<!doctype html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <style>\n      @font-face {\n        font-family: \"Caveat\";\n        src: url(\"fonts/Caveat-400-latin.woff2\") format(\"woff2\");\n        font-weight: 400;\n        font-display: block;\n      }\n      @font-face {\n        font-family: \"Caveat\";\n        src: url(\"fonts/Caveat-700-latin.woff2\") format(\"woff2\");\n        font-weight: 700;\n        font-display: block;\n      }\n      @font-face {\n        font-family: \"LXGW WenKai TC\";\n        src: url(\"fonts/LXGWWenKaiTC-400-latin.woff2\") format(\"woff2\");\n        font-weight: 400;\n        font-display: block;\n      }\n      @font-face {\n        font-family: \"Inter\";\n        src: url(\"fonts/Inter-400-latin.woff2\") format(\"woff2\");\n        font-weight: 400;\n        font-display: block;\n      }\n      @font-face {\n        font-family: \"Inter\";\n        src: url(\"fonts/Inter-700-latin.woff2\") format(\"woff2\");\n        font-weight: 700;\n        font-display: block;\n      }\n      @font-face {\n        font-family: \"Virgil\";\n        src: url(\"fonts/Virgil.woff2\") format(\"woff2\");\n        font-display: block;\n      }\n\n      :root {\n        /* Pick from the themeId palette table in Step 7 — example: classic */\n        --bg: #fff9e3;\n        --text: #1e1e1e;\n        --accent-0: #1971c2;\n        --accent-1: #e03131;\n        --accent-2: #2f9e44;\n        --accent-3: #e8590c;\n        --accent-4: #9c36b5;\n        --font-family: \"Caveat\", \"LXGW WenKai TC\", serif;\n      }\n      * {\n        box-sizing: border-box;\n      }\n      /* Body font-family MUST list concrete font names (not just var(--font-family)) —\n   the HyperFrames renderer's static analyzer doesn't expand CSS variables when\n   resolving fonts, so a var-only chain triggers `font_family_without_font_face`\n   lint and falls back to a generic. Use the concrete chain here; cards that\n   want the theme font can still reference var(--font-family) internally. */\n      html,\n      body {\n        margin: 0;\n        padding: 0;\n        width: 100%;\n        height: 100%;\n        overflow: hidden;\n        background: #000;\n        font-family: \"Inter\", \"Caveat\", \"LXGW WenKai TC\", ui-sans-serif, system-ui, sans-serif;\n      }\n      #stage {\n        position: relative;\n        width: 100%;\n        height: 100%;\n        overflow: hidden;\n      }\n\n      /* video-wrapper holds the source video. Its position / size are animated\n   over time by the master timeline (one tween per layout transition). */\n      .video-wrapper {\n        position: absolute;\n        left: 0;\n        top: 0;\n        width: 1920px;\n        height: 1080px;\n        overflow: hidden;\n        border-radius: 0;\n        box-shadow: none;\n      }\n      .video-wrapper video {\n        width: 100%;\n        height: 100%;\n        object-fit: cover;\n      }\n\n      .card-host {\n        position: absolute;\n        pointer-events: none;\n        overflow: hidden;\n      }\n      .card-host .card {\n        position: relative;\n        width: 100%;\n        height: 100%;\n        overflow: hidden;\n      }\n      .card-host .char {\n        display: inline-block;\n        visibility: visible;\n      }\n\n      /* Subtle drop shadow + rounded corners for non-fullscreen video framings */\n      .video-wrapper.framed {\n        border-radius: 16px;\n        box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);\n      }\n    </style>\n  </head>\n  <body>\n    <div\n      id=\"stage\"\n      data-composition-id=\"talking-head-recut\"\n      data-start=\"0\"\n      data-duration=\"121.2\"\n      data-fps=\"30\"\n      data-width=\"1920\"\n      data-height=\"1080\"\n    >\n      <!-- Layer 1: source video — initial position matches card-01's layout -->\n      <div class=\"video-wrapper\" id=\"video-wrap\">\n        <video\n          id=\"bg-video\"\n          src=\"input-video.mp4\"\n          playsinline\n          data-has-audio=\"true\"\n          data-start=\"0\"\n          data-duration=\"121.2\"\n          data-track-index=\"1\"\n        ></video>\n      </div>\n\n      <!-- Layer 2: each card-host sits at the bounds dictated by i\n\nFile v1.0.15:_meta.json\n\n{\n  \"ownerId\": \"kn77d06grj6xqp3dqwkk4bavhn89pegt\",\n  \"slug\": \"talking-head-recut\",\n  \"version\": \"1.0.15\",\n  \"publishedAt\": 1791141639279\n}\n\nFile v1.0.15:references/DESIGN_INDEX.md\n\n# V—Take Visual Design Library\n\nThis directory is a **reference library** for the talking-head-recut skill. Style, layout,\nand video frame are three **orthogonal** dimensions you can freely mix when\ndesigning a takeaway video.\n\n```\nStyle  ×  Layout  ×  VideoFrame\n (10)      (4)         (3)        = 120 possible combinations\n```\n\nRead a reference file when you decide to use that dimension. Each file is a\nself-contained HTML fragment that follows the talking-head-recut card-HTML contract\n(scoped `<style>`, no `<script>`, no external URLs, animations only via\n`data-anim-*`).\n\n## Layouts — how video and card share the canvas\n\n| key       | file                                         | what it does                                            | best for                                |\n| --------- | -------------------------------------------- | ------------------------------------------------------- | --------------------------------------- |\n| `split`   | [layouts/split.html](layouts/split.html)     | 50/50 side-by-side (landscape) or top/bottom (portrait) | speaker + data equal weight             |\n| `stack`   | [layouts/stack.html](layouts/stack.html)     | video on top (~52%), card below                         | talking-head with summary card          |\n| `pip`     | [layouts/pip.html](layouts/pip.html)         | card fills canvas, video rounded PiP in corner          | content-heavy moment, speaker secondary |\n| `overlay` | [layouts/overlay.html](layouts/overlay.html) | video full-bleed, glass card floats on bottom           | cinematic / dramatic moments            |\n\nA layout is a **two-part recipe**: pick a `card.zone` value to put in\n`storyboard.json` AND author a GSAP tween for `#video-wrap` to its\ntarget rect in the composition's `<script>`. Open the layout file's\nheader for the recommended `zone` + the GSAP statement to paste.\n(Earlier docs referenced a `card.layout` field — that field does NOT\nexist in the real schema; the strict v3 schema only has `card.zone`.)\n\n## Styles — the card's visual language\n\n| key          | file                                             | character                                            | accent    | suggested font      |\n| ------------ | ------------------------------------------------ | ---------------------------------------------------- | --------- | ------------------- |\n| `academic`   | [styles/academic.html](styles/academic.html)     | warm paper · grid · serif · blue highlight           | `#2557a7` | serif               |\n| `editorial`  | [styles/editorial.html](styles/editorial.html)   | cream · coral block · big italic quote               | `#ff3a2d` | Playfair-like serif |\n| `minimal`    | [styles/minimal.html](styles/minimal.html)       | pure black/white · huge type · generous space        | `#000`    | Inter               |\n| `spotlight`  | [styles/spotlight.html](styles/spotlight.html)   | dark purple gradient · glow · dramatic               | `#a78bfa` | sans                |\n| `geom`       | [styles/geom.html](styles/geom.html)             | chartreuse + hot pink + black collision              | `#d4ff00` | Inter bold          |\n| `whiteboard` | [styles/whiteboard.html](styles/whiteboard.html) | paper · Caveat handwriting · sketched borders        | `#ff6b35` | Caveat              |\n| `audit`      | [styles/audit.html](styles/audit.html)           | manila paper · justified serif · APPROVED stamp      | `#8b1d1d` | serif               |\n| `terminal`   | [styles/terminal.html](styles/terminal.html)     | dark · monospace · ASCII border · prompt cursor      | `#4ade80` | mono                |\n| `swiss`      | [styles/swiss.html](styles/swiss.html)           | white · Helvetica · strict double rules · red accent | `#e8190f` | Helvetica/Inter     |\n| `xhs`        | [styles/xhs.html](styles/xhs.html)               | cream + hot pink · chips · #hashtags · ❤️💬 row      | `#ff2e63` | sans                |\n\nChoose by content tone, not by content type — `academic` works for finance\ntoo if the tone is reflective; `terminal` works for non-tech if the tone is\n\"engineering rigor\".\n\n## Video Frames — decoration around the video element\n\n| key        | file                                         | character                                                    | when to skip                                     |\n| ---------- | -------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------ |\n| `clean`    | [frames/clean.html](frames/clean.html)       | no decoration; raw video                                     | default; safest                                  |\n| `hairline` | [frames/hairline.html](frames/hairline.html) | double-stroke + four-corner viewfinder ticks                 | over `overlay` layout (clashes with full-bleed)  |\n| `polaroid` | [frames/polaroid.html](frames/polaroid.html) | white photo frame + Caveat label + blue washi tape (no tilt) | over `overlay` layout; portrait PiP gets cramped |\n\nA frame is a decorative div that sits **next to** the `#video-wrap` inside\nthe composition's `#stage`. It is one-time HTML (not animated), but you can\nfade it in/out across cards. See each frame file for the placement snippet\nand the inline `<style>` it needs.\n\n## Decision guide (loose, not prescriptive)\n\n| video content                    | suggested combos                                         |\n| -------------------------------- | -------------------------------------------------------- |\n| interview / dialogue             | `academic` × `stack`, `audit` × `split`                  |\n| product launch / announcement    | `editorial` × `overlay`, `geom` × `pip`                  |\n| data analysis / financial report | `audit` × `split`, `swiss` × `stack`, `terminal` × `pip` |\n| social clip (9:16)               | `xhs` × `overlay`, `editorial` × `stack`                 |\n| technical tutorial               | `terminal` × `split`, `whiteboard` × `pip`               |\n| emotional story / narration      | `spotlight` × `overlay`, `whiteboard` × `overlay`        |\n| minimalist presentation          | `minimal` × `split`, `swiss` × `overlay`                 |\n\nThese are starting points only. Look at the transcript, pick the tone, then\npick the visual.\n\n## Portrait sizing — bigger type for mobile\n\nEvery `references/styles/*.html` is sized for a **1920×1080 landscape**\npreview. When the final composition is **portrait (1080×1920)** — the\ndefault for social / mobile — scale every visual size up so it reads on a\nphone held close.\n\n| token                 | landscape | **portrait** | scale |\n| --------------------- | --------- | ------------ | ----- |\n| hero title (h1/h2)    | 64–96px   | **88–132px** | ×1.35 |\n| detail / body         | 24–30px   | **30–40px**  | ×1.30 |\n| kicker / chip / meta  | 14–18px   | **18–22px**  | ×1.25 |\n| primary number / stat | 48–60px   | **64–88px**  | ×1.40 |\n| horizontal padding    | 40–64px   | **24–36px**  | ÷1.5  |\n\n`portraitPx ≈ round(landscapePx × 1.3)`. Hero headlines can go ×1.4;\nsmall meta stays at ×1.2. Padding **shrinks** in portrait since the card\nis narrower.\n\nFor a card that must work in both, use a container query on the card\nroot: `container-type: inline-size` + `font-size: clamp(64px, 8.5cqi, 132px)`.\n\n## Source aspect ratio independence\n\nOutput canvas is independent of source video aspect. Three supported\noutput ratios (selected by the user in Step 7.0 of SKILL.md):\n\n| ratio  | canvas    | `storyboard.layout`                                    | best for                                                   |\n| ------ | --------- | ------------------------------------------------------ | ---------------------------------------------------------- |\n| `16:9` | 1920×1080 | `\"landscape\"`                                          | YouTube / TV / desktop playback                            |\n| `9:16` | 1080×1920 | `\"portrait\"`                                           | TikTok / Reels / short-form mobile                         |\n| `4:5`  | 1080×1350 | `\"portrait\"` (schema treats 4:5 as portrait since h>w) | Instagram feed / WeChat Moments / works for both platforms |\n\nThe layout reference files in `layouts/` document **landscape** and\n**portrait** bounds only. For **4:5** derive bounds by proportional\nvertical scaling from portrait: `4:5 y/h = round(portrait y/h × 0.703)`,\nkeep `x/w` identical. The composer doesn't care about the named layout\nvalue; it just uses `composition.width × height`.\n\n- Landscape video on landscape canvas → `videoBounds` matches video aspect, no letterbox\n- Portrait video on landscape canvas → `videoBounds` is a narrower box (e.g. `pip` becomes 248×440); empty side filled by card or background\n- Landscape video on portrait canvas → `videoBounds` becomes a wide-but-short band; `stack` and `overlay` work best\n- Portrait video on portrait canvas → most natural; any layout\n\nThe layout reference files show landscape values; for portrait you usually\nflip the long axis: `split` becomes top/bottom, `pip` video bubble shrinks\n~20%, `overlay` card slot widens to full width.\n\n## Constraints you must obey when copying from these references\n\n1. **No `<script>`** — animations only via `data-anim-*` attributes\n2. **No external URLs** — no Google Fonts CDN, no remote images; the\n   skill provides Caveat / LXGW WenKai TC / Inter / Virgil locally\n3. **All `<style>` rules must be prefixed with `.card[data-card-id=\"...\"]`** —\n   the hyperframes sanitizer auto-scopes them, but write them already-scoped to\n   stay readable\n4. **No `on*=` inline handlers**\n5. **CSS variables for colors** when you want a card to switch theme cleanly;\n   inline hex when you want this specific style's signature look\n\nIf a reference uses a font you don't have, fall back:\n\n- Playfair Display / Noto Serif SC → `ui-serif, \"Songti SC\", \"Times New Roman\", serif`\n- Noto Sans SC → `ui-sans-serif, system-ui, sans-serif`\n- JetBrains Mono → `ui-monospace, \"SF Mono\", Menlo, monospace`\n- Kalam → `'Caveat', cursive`\n\nFile v1.0.15:NOTICE.md\n\n# Attribution\n\nThe `talking-head-recut` skill (its card-based design system — styles, layouts, frames,\nfonts, and the GSAP-driven composition workflow) is **adapted from** the open-source\n**vtake-skills** project (`vtake-cut`):\n\n> https://github.com/notedit/vtake-skills\n\nAdaptations for this repo: renamed to `talking-head-recut`; transcription repointed to\nlocal Whisper via `hyperframes transcribe` (dropping the third-party `@notedit/vtake`\nCLI and the `vtake.app` proxy); audio/metadata extraction inlined with `ffmpeg`/`ffprobe`;\nthe fixed third-party brand outro removed in favour of an optional, neutral outro;\nartifacts aligned to the `videos/<project>/` convention.\n\nThe original is MIT-licensed; its notice is retained below as required.\n\n```\nMIT License\n\nCopyright (c) 2026 leeoxiang\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```\n\nFile v1.0.15:skill-card.md\n\n## Description:\n\nAdds transcript-synced graphic overlays to an existing talking-head, interview, or podcast video while leaving the underlying clip intact.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[heygen-com](https://clawhub.ai/user/heygen-com)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nVideo editors and creators use this skill to turn an existing spoken-word clip into a designed video with timed titles, quotes, data callouts, lower-thirds, and picture-in-picture overlays.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Unpinned HyperFrames commands can run package code that changes between installations.\n\nMitigation: Use a pinned, reviewed HyperFrames version or render in a controlled environment, especially for sensitive videos.\n\nRisk: The suggested skill update can change the instructions and code used in later runs.\n\nMitigation: Confirm updates with the user and review changes before relying on the updated skill.\n\n## Reference(s):\n\n- [ClawHub skill release](https://clawhub.ai/heygen-com/skills/talking-head-recut)\n- [Overlay design index](artifact/references/DESIGN_INDEX.md)\n\n## Skill Output:\n\n**Output Type(s):** [Code, Shell commands, Video]\n\n**Output Format:** [HTML/CSS/JavaScript overlays, JSON storyboard, and MP4 video]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Cards are timed to a locally generated transcript; the input clip plays beneath the overlays.]\n\n## Skill Version(s):\n\n1.0.15 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nArchive v1.0.14: 24 files, 92191 bytes\n\nFiles: assets/vendor/gsap.min.js (72925b), media-contract.test.mjs (912b), NOTICE.md (1826b), references/DESIGN_INDEX.md (10171b), references/frames/clean.html (2626b), references/frames/hairline.html (5921b), references/frames/polaroid.html (5349b), references/layouts/overlay.html (5463b), references/layouts/pip.html (4650b), references/layouts/split.html (3805b), references/layouts/stack.html (3458b), references/styles/academic.html (6043b), references/styles/audit.html (6182b), references/styles/editorial.html (6586b), references/styles/geom.html (5776b), references/styles/minimal.html (4142b), references/styles/spotlight.html (4941b), references/styles/swiss.html (6053b), references/styles/terminal.html (6957b), references/styles/whiteboard.html (5829b), references/styles/xhs.html (7210b), skill-card.md (1759b), SKILL.md (65686b), _meta.json (138b)\n\nFile v1.0.14:SKILL.md\n\n---\nname: talking-head-recut\ndescription: Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, side panels, picture-in-picture — synced to the transcript, on a 16:9 / 9:16 / 4:5 canvas of your choice; the clip plays untouched underneath. Trigger on \"graphic overlays\", \"on-screen graphics\", \"package / dress up my video\". Not plain subtitles (/embedded-captions). Unclear → /hyperframes.\n---\n\n**Plugin installs:** Before setup or freshness commands, follow [plugin execution rules](../hyperframes/references/plugin-installation.md) when this skill is inside a HyperFrames plugin. Standalone installs keep the update instructions below.\n\n> **First, keep this skill fresh — confirm with the user before running:** `npx hyperframes skills update talking-head-recut`. A fast no-op when everything is current; otherwise it refreshes this skill plus the core domain skills it depends on before you rely on them.\n\n# Talking Head Recut\n\nTalking Head Recut takes a local video that **plays in full** and layers a sequence of\ntimed, designed **graphic cards** onto it — titles, lower-thirds, data callouts,\nquotes, side panels, picture-in-picture — synced to what's being said. The agent\ndesigns the cards (timing + content) and **writes each card's HTML directly in the\nconversation**, then assembles a single composition HTML and renders it to MP4 via\n`hyperframes`. There is no fixed archetype list and no prescribed card structure —\nthe overlays emerge from what the transcript actually says.\n\n> **The front door is `/hyperframes`.** This skill packages an **existing talking-head clip** with **designed graphic cards** (titles, lower-thirds, data callouts, quotes, side panels, PiP) — not plain captions (the spoken words as text). **The clip plays untouched.** Any other intent — plain subtitles, a standalone graphic, a from-scratch video — or any uncertainty → read `/hyperframes` first: the intent layer owns every route decision.\n\n> **Graphic-packaging sibling of `embedded-captions`.** Captions add the _spoken words_\n> as a readable subtitle; this adds _designed graphics_ on top of the playing video.\n> Plain subtitles → `embedded-captions`. Build a video from scratch → the creation\n> workflows (`product-launch-video` / `faceless-explainer` / …).\n\nRouted through `/hyperframes`, the intent layer confirms only the input (which clip) and **announces** the render-strategy questions as deferred asks — aspect, layout, style group, and card count stay at Step 7, where the probed footage and transcript ground the recommendations; the layer's run-shape questions don't apply. A `BRIEF.md`, when present, carries the confirmed input and any user notes — read it first.\n\nInspectable intermediate files in the work directory:\n\n- `metadata.json` — duration / width / height / fps\n- `audio.mp3` — extracted audio\n- `transcript.json` — a flat **word array** `[{ text, start, end }, …]` (Whisper; no `segments`, no `words` wrapper)\n- `storyboard.json` — lightweight card outline (the agent's plan)\n- `public/cards/card-XX.html` — one HTML fragment per card\n- `public/index.html` — final assembled composition\n- `output.mp4` — rendered video\n\n## CLI Resolution\n\n```bash\n# hyperframes — transcription (local Whisper) + rendering the assembled HTML to MP4\nnpx hyperframes --help\n```\n\nThis skill runs entirely on the **hyperframes** CLI plus system `ffmpeg` / `ffprobe`.\nTranscription is local **Whisper** via `hyperframes transcribe` — no third-party\nservice, API key, or rate-limited proxy.\n\n## Workflow\n\n### 1. Check Environment\n\n```bash\nnpx hyperframes doctor          # ffmpeg, headless browser, render deps\n# confirm bundled assets:\nls \"<SKILL_DIR>/assets/fonts\" \"<SKILL_DIR>/assets/vendor/gsap.min.js\"\n```\n\nRequired:\n\n- `ffmpeg` / `ffprobe` (system)\n- `<SKILL_DIR>/assets/fonts/*.woff2`, `<SKILL_DIR>/assets/vendor/gsap.min.js` (bundled inside this skill, staged to work dir in Step 9)\n\nTranscription needs no key — `hyperframes transcribe` runs Whisper locally (Step 4).\n\nStrongly recommended on macOS for `hyperframes render`:\n\n```bash\nexport PRODUCER_BROWSER_GPU_MODE=hardware\n```\n\n### 2. Create a Work Directory\n\nAll artifacts live under `videos/<project-name>/` — the same convention as the other\nvideo workflows (`product-launch-video` / `faceless-explainer` / `pr-to-video`). Keep\nthe cwd at the workspace root; everything below writes under this one subdirectory.\n\n```bash\nVIDEO_PATH=\"/absolute/path/input.mp4\"\nWORK_DIR=\"videos/$(basename \"$VIDEO_PATH\" | sed 's/\\.[^.]*$//')\"\nmkdir -p \"$WORK_DIR\"\n```\n\n### 3. Extract Audio and Metadata\n\n```bash\n# metadata — duration / width / height / fps\nffprobe -v error -select_streams v:0 \\\n  -show_entries stream=width,height,r_frame_rate \\\n  -show_entries format=duration -of json \"$VIDEO_PATH\" > \"$WORK_DIR/metadata.json\"\n# audio\nffmpeg -y -i \"$VIDEO_PATH\" -vn -acodec libmp3lame -q:a 2 \"$WORK_DIR/audio.mp3\"\n```\n\nOutputs: `metadata.json` (read `width`/`height`/`duration`; fps = the `r_frame_rate`\nfraction evaluated, e.g. `30000/1001 → 29.97`) + `audio.mp3`.\n\n### 4. Transcribe\n\n```bash\nnpx hyperframes transcribe \"$WORK_DIR/audio.mp3\" -d \"$WORK_DIR\" --json --model small.en\n```\n\nLocal **Whisper** — no API key, no proxy, no rate limit. Writes a word-level\n`transcript.json` into the work dir (word `text` + `start` / `end` timestamps).\nRead it for the word / sentence timings that drive card timing in Step 6; group\nwords into sentences yourself at punctuation / pauses if you need segment-level\nchunks.\n\n**Clamp to media duration.** Whisper can return the final word's `end` a hair past the\nactual clip length — clamp every card `endSec` and `composition.durationSeconds` to the\n`metadata.json` duration, or the render will show a black tail past the video.\n\n### 5. Correct Transcript\n\n`transcript.json` is a **flat array of word objects** — `[{ \"text\": \"...\", \"start\": s, \"end\": s }, …]` (no `segments` array, no `words` wrapper; the per-word key is **`text`**). Read it and fix obvious ASR errors:\n\n- Homophones, product names, technical terms, punctuation\n- Edit a word's `text` in place; **preserve its `start` / `end`** timestamps\n- There is no pre-grouped `segments` array — **group words into sentences yourself** (split at terminal punctuation / pauses) when you need segment-level chunks for card timing\n\n### 6. Draft a Lightweight Storyboard (in chat)\n\n**No CLI involved.** Read `transcript.json` + `metadata.json` and design\ncards directly. `storyboard.json` is an agent-internal planning artifact\n— no CLI command consumes it; it exists so you can think clearly\nabout timing and content before writing each card's HTML. Keep the\nshape consistent with the example below so the same outline can drive\nthe composition you author in Step 9:\n\n```json\n{\n  \"schemaVersion\": 3,\n  \"composition\": {\n    \"fps\": 30,\n    \"width\": 1080,\n    \"height\": 1920,\n    \"durationSeconds\": 121.2,\n    \"layout\": \"portrait\",\n    \"themeId\": \"noir\",\n    \"seed\": 42\n  },\n  \"videoTrack\": {\n    \"sourcePath\": \"input-video.mp4\",\n    \"startSec\": 0,\n    \"endSec\": 121.2,\n    \"bounds\": { \"x\": 0, \"y\": 0, \"width\": 1080, \"height\": 1920 }\n  },\n  \"subtitles\": { \"enabled\": false },\n  \"cards\": [\n    {\n      \"id\": \"card-01\",\n      \"intent\": \"Hook with the speaker's anxious midnight question\",\n      \"startSec\": 0.5,\n      \"endSec\": 13.0,\n      \"accentIndex\": 0,\n      \"zone\": \"fullscreen\",\n      \"contentHints\": {\n        \"kicker\": \"AN HONEST QUESTION\",\n        \"title\": \"The soul-searching question at 11 PM\",\n        \"detail\": \"Client's 60-second voice message: 'If the RMB appreciates, does that mean my USD policy is a terrible loss?'\"\n      }\n    }\n  ]\n}\n```\n\n**Required Card fields:**\n\n| field                   | type                                       | purpose                                                                                               |\n| ----------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------- |\n| `id`                    | string                                     | stable id used in card HTML & GSAP selectors                                                          |\n| `intent`                | string                                     | natural-language description; fed to card synthesis                                                   |\n| `startSec` / `endSec`   | number                                     | times in seconds (endSec > startSec)                                                                  |\n| `accentIndex`           | 0 \\| 1 \\| 2 \\| 3 \\| 4                      | which of the 5 theme accent colors this card pulls                                                    |\n| `zone`                  | enum (see below)                           | where on the canvas the card lives                                                                    |\n| `contentHints`          | object                                     | free-form bag; agent puts kicker/title/detail/data/quote here                                         |\n| `archetype` (optional)  | string                                     | free-form label you may attach to remember a card's pattern; absent = free-form, which is the default |\n| `transition` (optional) | enum: `cut` \\| `fade` \\| `slide` \\| `wipe` | declarative card-to-card transition                                                                   |\n\n**Five `zone` values:**\n\n| zone              | resolved bounds                                | when to use                             |\n| ----------------- | ---------------------------------------------- | --------------------------------------- |\n| `fullscreen`      | covers whole canvas                            | hero moments, big numbers, mantras      |\n| `whiteboard-area` | inset 40px margin (or 45% of portrait height)  | dense data / annotated content          |\n| `lower-third`     | bottom 30% band                                | annotation over visible video           |\n| `side-panel`      | right 42% (landscape) or bottom 40% (portrait) | data side, video other side             |\n| `video-overlay`   | full canvas, expects mostly-transparent card   | annotation overlays on full-bleed video |\n\nWhen you assemble the composition in Step 9, resolve each card's `zone`\ninto pixel bounds on the card-host wrapper following the table above.\nVideo bounds are set **once** at composition level (`videoTrack.bounds`);\nto make video appear to \"move between cards\", author GSAP tweens against\n`#video-wrap` in the composition's `<script>` (see Step 9).\n\n**No prescribed card roles, no prescribed narrative arc.** Cards emerge\nfrom what the video actually says — could be all quotes or all data,\ncould open with a number or with a story. Let the transcript drive the\nrhythm.\n\n**How many takeaways? — auto-infer from duration + density.** No fixed\nupper limit. Pick a **base pace** from the video duration, then adjust\nby **information density**. Only **floor is fixed: minimum 5 cards** so\neven short videos have rhythm.\n\n**Step 1 — base pace by duration** (the natural sec/card for medium density):\n\n| video duration     | base pace (sec per card) | rationale                                   |\n| ------------------ | ------------------------ | ------------------------------------------- |\n| < 60s (short reel) | **6–8s**                 | viewers expect fast cuts in short-form      |\n| 60s – 3 min        | **8–12s**                | normal social pace                          |\n| 3 – 10 min         | **12–20s**               | give breathing room; each card carries more |\n| 10 – 30 min        | **20–35s**               | long-form lecture / interview rhythm        |\n| > 30 min           | **30–60s**               | episodic, near-chapter feel                 |\n\n**Step 2 — density multiplier** (multiplies the base pace):\n\n| signal in the transcript                                                                                                    | multiplier | effect                   |\n| --------------------------------------------------------------------------------------------------------------------------- | ---------- | ------------------------ |\n| **High density** — many numbers, distinct claims, staccato pacing, list-like enumeration, every 1–2 sentences is a\n\nArchive v1.0.13: 24 files, 92221 bytes\n\nFiles: assets/vendor/gsap.min.js (72925b), media-contract.test.mjs (912b), NOTICE.md (1826b), references/DESIGN_INDEX.md (10171b), references/frames/clean.html (2626b), references/frames/hairline.html (5921b), references/frames/polaroid.html (5349b), references/layouts/overlay.html (5463b), references/layouts/pip.html (4650b), references/layouts/split.html (3805b), references/layouts/stack.html (3458b), references/styles/academic.html (6043b), references/styles/audit.html (6182b), references/styles/editorial.html (6586b), references/styles/geom.html (5776b), references/styles/minimal.html (4142b), references/styles/spotlight.html (4941b), references/styles/swiss.html (6053b), references/styles/terminal.html (6957b), references/styles/whiteboard.html (5829b), references/styles/xhs.html (7210b), skill-card.md (1936b), SKILL.md (65610b), _meta.json (138b)\n\nArchive v1.0.12: 24 files, 92571 bytes\n\nFiles: assets/vendor/gsap.min.js (72925b), media-contract.test.mjs (1350b), NOTICE.md (1826b), references/DESIGN_INDEX.md (10171b), references/frames/clean.html (2626b), references/frames/hairline.html (5884b), references/frames/polaroid.html (5349b), references/layouts/overlay.html (5463b), references/layouts/pip.html (4650b), references/layouts/split.html (3805b), references/layouts/stack.html (3458b), references/styles/academic.html (6043b), references/styles/audit.html (6182b), references/styles/editorial.html (6586b), references/styles/geom.html (5776b), references/styles/minimal.html (4142b), references/styles/spotlight.html (4941b), references/styles/swiss.html (6053b), references/styles/terminal.html (6957b), references/styles/whiteboard.html (5829b), references/styles/xhs.html (7210b), skill-card.md (1923b), SKILL.md (66091b), _meta.json (138b)\n\nArchive v1.0.11: 24 files, 92747 bytes\n\nFiles: assets/vendor/gsap.min.js (72925b), media-contract.test.mjs (1350b), NOTICE.md (1826b), references/DESIGN_INDEX.md (10171b), references/frames/clean.html (2626b), references/frames/hairline.html (5884b), references/frames/polaroid.html (5349b), references/layouts/overlay.html (5463b), references/layouts/pip.html (4650b), references/layouts/split.html (3805b), references/layouts/stack.html (3458b), references/styles/academic.html (6043b), references/styles/audit.html (6182b), references/styles/editorial.html (6586b), references/styles/geom.html (5776b), references/styles/minimal.html (4142b), references/styles/spotlight.html (4941b), references/styles/swiss.html (6053b), references/styles/terminal.html (6957b), references/styles/whiteboard.html (5829b), references/styles/xhs.html (7210b), skill-card.md (2598b), SKILL.md (65847b), _meta.json (138b)\n\nArchive v1.0.10: 24 files, 92915 bytes\n\nFiles: assets/vendor/gsap.min.js (72925b), media-contract.test.mjs (1350b), NOTICE.md (1826b), references/DESIGN_INDEX.md (10171b), references/frames/clean.html (2626b), references/frames/hairline.html (5884b), references/frames/polaroid.html (5349b), references/layouts/overlay.html (5463b), references/layouts/pip.html (4650b), references/layouts/split.html (3805b), references/layouts/stack.html (3458b), references/styles/academic.html (6043b), references/styles/audit.html (6182b), references/styles/editorial.html (6586b), references/styles/geom.html (5776b), references/styles/minimal.html (4142b), references/styles/spotlight.html (4941b), references/styles/swiss.html (6053b), references/styles/terminal.html (6957b), references/styles/whiteboard.html (5829b), references/styles/xhs.html (7210b), skill-card.md (3150b), SKILL.md (65852b), _meta.json (138b)\n\nArchive v1.0.9: 24 files, 92321 bytes\n\nFiles: assets/vendor/gsap.min.js (72925b), media-contract.test.mjs (1350b), NOTICE.md (1826b), references/DESIGN_INDEX.md (10171b), references/frames/clean.html (2626b), references/frames/hairline.html (5884b), references/frames/polaroid.html (5349b), references/layouts/overlay.html (5463b), references/layouts/pip.html (4650b), references/layouts/split.html (3805b), references/layouts/stack.html (3458b), references/styles/academic.html (6043b), references/styles/audit.html (6182b), references/styles/editorial.html (6586b), references/styles/geom.html (5776b), references/styles/minimal.html (4142b), references/styles/spotlight.html (4941b), references/styles/swiss.html (6053b), references/styles/terminal.html (6957b), references/styles/whiteboard.html (5829b), references/styles/xhs.html (7210b), skill-card.md (2365b), SKILL.md (65330b), _meta.json (137b)\n\nArchive v1.0.8: 24 files, 92248 bytes\n\nFiles: assets/vendor/gsap.min.js (72925b), media-contract.test.mjs (1350b), NOTICE.md (1826b), references/DESIGN_INDEX.md (10171b), references/frames/clean.html (2626b), references/frames/hairline.html (5884b), references/frames/polaroid.html (5349b), references/layouts/overlay.html (5463b), references/layouts/pip.html (4650b), references/layouts/split.html (3805b), references/layouts/stack.html (3458b), references/styles/academic.html (6043b), references/styles/audit.html (6182b), references/styles/editorial.html (6586b), references/styles/geom.html (5776b), references/styles/minimal.html (4142b), references/styles/spotlight.html (4941b), references/styles/swiss.html (6053b), references/styles/terminal.html (6957b), references/styles/whiteboard.html (5829b), references/styles/xhs.html (7210b), skill-card.md (2345b), SKILL.md (65317b), _meta.json (137b)\n\nArchive v1.0.7: 24 files, 92259 bytes\n\nFiles: assets/vendor/gsap.min.js (72925b), media-contract.test.mjs (1350b), NOTICE.md (1826b), references/DESIGN_INDEX.md (10171b), references/frames/clean.html (2626b), references/frames/hairline.html (5884b), references/frames/polaroid.html (5349b), references/layouts/overlay.html (5463b), references/layouts/pip.html (4650b), references/layouts/split.html (3805b), references/layouts/stack.html (3458b), references/styles/academic.html (6043b), references/styles/audit.html (6182b), references/styles/editorial.html (6586b), references/styles/geom.html (5776b), references/styles/minimal.html (4142b), references/styles/spotlight.html (4941b), references/styles/swiss.html (6053b), references/styles/terminal.html (6957b), references/styles/whiteboard.html (5829b), references/styles/xhs.html (7210b), skill-card.md (2421b), SKILL.md (65069b), _meta.json (137b)","readmeExcerpt":"Skill: talking-head-recut Owner: heygen-com Summary: Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, side panels, picture-in-picture — synced to the transcript, on a 16:9 / 9:16 / 4:5 canvas of your choice; the clip plays untouched underneath. Trigger on \"graphic overlays\", \"on-screen graphics\", \"package / d","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"# hyperframes — transcription (local Whisper) + rendering the assembled HTML to MP4\nnpx hyperframes --help"},{"language":"bash","snippet":"npx hyperframes doctor          # ffmpeg, headless browser, render deps\n# confirm bundled assets:\nls \"<SKILL_DIR>/assets/fonts\" \"<SKILL_DIR>/assets/vendor/gsap.min.js\""},{"language":"bash","snippet":"export PRODUCER_BROWSER_GPU_MODE=hardware"},{"language":"bash","snippet":"VIDEO_PATH=\"/absolute/path/input.mp4\"\nWORK_DIR=\"videos/$(basename \"$VIDEO_PATH\" | sed 's/\\.[^.]*$//')\"\nmkdir -p \"$WORK_DIR\""},{"language":"bash","snippet":"# metadata — duration / width / height / fps\nffprobe -v error -select_streams v:0 \\\n  -show_entries stream=width,height,r_frame_rate \\\n  -show_entries format=duration -of json \"$VIDEO_PATH\" > \"$WORK_DIR/metadata.json\"\n# audio\nffmpeg -y -i \"$VIDEO_PATH\" -vn -acodec libmp3lame -q:a 2 \"$WORK_DIR/audio.mp3\""},{"language":"bash","snippet":"npx hyperframes transcribe \"$WORK_DIR/audio.mp3\" -d \"$WORK_DIR\" --json --model small.en"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: talking-head-recut\ndescription: Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, side panels, picture-in-picture — synced to the transcript, on a 16:9 / 9:16 / 4:5 canvas of your choice; the clip plays untouched underneath. Trigger on \"graphic overlays\", \"on-screen graphics\", \"package / dress up my video\". Not plain subtitles (/embedded-captions). Unclear → /hyperframes.\n---\n\n**Plugin installs:** Before setup or freshness commands, follow [plugin execution rules](../hyperframes/references/plugin-installation.md) when this skill is inside a HyperFrames plugin. Standalone installs keep the update instructions below.\n\n> **First, keep this skill fresh — confirm with the user before running:** `npx hyperframes skills update talking-head-recut`. A fast no-op when everything is current; otherwise it refreshes this skill plus the core domain skills it depends on before you rely on them.\n\n# Talking Head Recut\n\nTalking Head Recut takes a local video that **plays in full** and layers a sequence of\ntimed, designed **graphic cards** onto it — titles, lower-thirds, data callouts,\nquotes, side panels, picture-in-picture — synced to what's being said. The agent\ndesigns the cards (timing + content) and **writes each card's HTML directly in the\nconversation**, then assembles a single composition HTML and renders it to MP4 via\n`hyperframes`. There is no fixed archetype list and no prescribed card structure —\nthe overlays emerge from what the transcript actually says.\n\n> **The front door is `/hyperframes`.** This skill packages an **existing talking-head clip** with **designed graphic cards** (titles, lower-thirds, data callouts, quotes, side panels, PiP) — not plain captions (the spoken words as text). **The clip plays untouched.** Any other intent — plain subtitles, a standalone graphic, a from-scratch video — or any uncertainty → read `/hyperframes` first: the intent layer owns every route decision.\n\n> **Graphic-packaging sibling of `embedded-captions`.** Captions add the _spoken words_\n> as a readable subtitle; this adds _designed graphics_ on top of the playing video.\n> Plain subtitles → `embedded-captions`. Build a video from scratch → the creation\n> workflows (`product-launch-video` / `faceless-explainer` / …).\n\nRouted through `/hyperframes`, the intent layer confirms only the input (which clip) and **announces** the render-strategy questions as deferred asks — aspect, layout, style group, and card count stay at Step 7, where the probed footage and transcript ground the recommendations; the layer's run-shape questions don't apply. A `BRIEF.md`, when present, carries the confirmed input and any user notes — read it first.\n\nInspectable intermediate files in the work directory:\n\n- `metadata.json` — duration / width / height / fps\n- `audio.mp3` — extracted audio\n- `transcript.json` — a flat **word array** `[{ text, start, end }, …]` (Whisper; no"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn77d06grj6xqp3dqwkk4bavhn89pegt\",\n  \"slug\": \"talking-head-recut\",\n  \"version\": \"1.0.16\",\n  \"publishedAt\": 1791142434907\n}"},{"path":"references/DESIGN_INDEX.md","content":"# V—Take Visual Design Library\n\nThis directory is a **reference library** for the talking-head-recut skill. Style, layout,\nand video frame are three **orthogonal** dimensions you can freely mix when\ndesigning a takeaway video.\n\n```\nStyle  ×  Layout  ×  VideoFrame\n (10)      (4)         (3)        = 120 possible combinations\n```\n\nRead a reference file when you decide to use that dimension. Each file is a\nself-contained HTML fragment that follows the talking-head-recut card-HTML contract\n(scoped `<style>`, no `<script>`, no external URLs, animations only via\n`data-anim-*`).\n\n## Layouts — how video and card share the canvas\n\n| key       | file                                         | what it does                                            | best for                                |\n| --------- | -------------------------------------------- | ------------------------------------------------------- | --------------------------------------- |\n| `split`   | [layouts/split.html](layouts/split.html)     | 50/50 side-by-side (landscape) or top/bottom (portrait) | speaker + data equal weight             |\n| `stack`   | [layouts/stack.html](layouts/stack.html)     | video on top (~52%), card below                         | talking-head with summary card          |\n| `pip`     | [layouts/pip.html](layouts/pip.html)         | card fills canvas, video rounded PiP in corner          | content-heavy moment, speaker secondary |\n| `overlay` | [layouts/overlay.html](layouts/overlay.html) | video full-bleed, glass card floats on bottom           | cinematic / dramatic moments            |\n\nA layout is a **two-part recipe**: pick a `card.zone` value to put in\n`storyboard.json` AND author a GSAP tween for `#video-wrap` to its\ntarget rect in the composition's `<script>`. Open the layout file's\nheader for the recommended `zone` + the GSAP statement to paste.\n(Earlier docs referenced a `card.layout` field — that field does NOT\nexist in the real schema; the strict v3 schema only has `card.zone`.)\n\n## Styles — the card's visual language\n\n| key          | file                                             | character                                            | accent    | suggested font      |\n| ------------ | ------------------------------------------------ | ---------------------------------------------------- | --------- | ------------------- |\n| `academic`   | [styles/academic.html](styles/academic.html)     | warm paper · grid · serif · blue highlight           | `#2557a7` | serif               |\n| `editorial`  | [styles/editorial.html](styles/editorial.html)   | cream · coral block · big italic quote               | `#ff3a2d` | Playfair-like serif |\n| `minimal`    | [styles/minimal.html](styles/minimal.html)       | pure black/white · huge type · generous space        | `#000`    | Inter               |\n| `spotlight`  | [styles/spotlight.html](styles/spotlight.html)   | dark purple gradient · glow · dramatic               | `#a78bfa` | sans                |\n| `geom`   "},{"path":"NOTICE.md","content":"# Attribution\n\nThe `talking-head-recut` skill (its card-based design system — styles, layouts, frames,\nfonts, and the GSAP-driven composition workflow) is **adapted from** the open-source\n**vtake-skills** project (`vtake-cut`):\n\n> https://github.com/notedit/vtake-skills\n\nAdaptations for this repo: renamed to `talking-head-recut`; transcription repointed to\nlocal Whisper via `hyperframes transcribe` (dropping the third-party `@notedit/vtake`\nCLI and the `vtake.app` proxy); audio/metadata extraction inlined with `ffmpeg`/`ffprobe`;\nthe fixed third-party brand outro removed in favour of an optional, neutral outro;\nartifacts aligned to the `videos/<project>/` convention.\n\nThe original is MIT-licensed; its notice is retained below as required.\n\n```\nMIT License\n\nCopyright (c) 2026 leeoxiang\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n```"},{"path":"skill-card.md","content":"## Description:\n\nAdds transcript-timed graphic overlays to an existing talking-head video while preserving the underlying clip.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[heygen-com](https://clawhub.ai/user/heygen-com)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nVideo editors and creators use this skill to add designed titles, quotes, data callouts, and other timed graphics to an existing interview, podcast, or talking-head clip.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Running or updating an unpinned external HyperFrames CLI can change the code the agent executes.\n\nMitigation: Review or pin the HyperFrames version before use, and confirm skill updates before running them.\n\nRisk: Extracted audio and transcripts may remain in the project work directory.\n\nMitigation: Avoid sensitive videos unless local storage of their audio and transcripts is acceptable.\n\n## Reference(s):\n\n- [Talking Head Recut on ClawHub](https://clawhub.ai/heygen-com/skills/talking-head-recut)\n- [Visual design reference library](references/DESIGN_INDEX.md)\n\n## Skill Output:\n\n**Output Type(s):** [Code, Shell commands, Guidance]\n\n**Output Format:** [Markdown guidance with HTML and JSON files, plus a rendered MP4 video]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces a storyboard, transcript, graphic-card HTML, a composition, and a rendered video.]\n\n## Skill Version(s):\n\n1.0.16 (source: ClawHub release metadata)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, side panels, picture-in-picture — synced to the transcript, on a 16:9 / 9:16 / 4:5 canvas of your choice; the clip plays untouched underneath. Trigger on \"graphic overlays\", \"on-screen graphics\", \"package / dress up my video\". Not plain subtitles (/embedded-captions). Unclear → /hyperframes. Skill: talking-head-recut Owner: heygen-com Summary: Package an existing talking-head / interview / podcast video with timed, designed GRAPHIC OVERLAY cards — kinetic titles, lower-thirds, data callouts, quotes, side panels, picture-in-picture — synced to the transcript, on a 16:9 / 9:16 / 4:5 canvas of your choice; the clip plays untouched underneath. Trigger on \"graphic overlays\", \"on-screen graphics\", \"package / d","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1507,"uniquenessScore":49,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T22:03:15.058Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T22:03:15.058Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T08:10:23.620Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}