byheygen-com· 46 skills
Turn a weekly changelog .md into a finished branded changelog video (square 1080, ~45-60s, Annie VO, animated brand background, mock-UI visualizations, lowkey captions). Use when the user provides a changelog/digest markdown and wants the weekly video, or says "changelog video". Self-contained — fonts, background, lexicon, and scripts ship in this skill.
$npx -y skills add heygen-com/hyperframes --skill changelog-videoInstalls into the current project.
Run `npx skills use "https://github.com/heygen-com/hyperframes" --skill "heygen-com/hyperframes/changelog-video"` and follow the generated skill instructions now. Read its complete output, redirecting it to a temporary file first if necessary. Resolve relative paths from the supporting-files directory it provides.
Use the skills in "https://github.com/heygen-com/hyperframes" that are relevant to the current task. Run `npx skills add "https://github.com/heygen-com/hyperframes"` and select the relevant skills, then follow their instructions.
| 1 | # Changelog → Branded Video |
| 2 | |
| 3 | Input: a changelog .md (themes + items, like the weekly HyperFrames digest). |
| 4 | Output: a lint-clean, seam-gate-green HyperFrames project in |
| 5 | `projects/active/weekly-changelog-<range>/`. Render only when asked. |
| 6 | |
| 7 | **Load first, non-negotiable:** `motion-doctrine` (+ `cut-the-curve`, |
| 8 | `oversized-cursor` if a cursor appears, `seam-craft`) and `captions-overlay`. |
| 9 | This skill supplies the changelog-specific pipeline; the doctrine supplies the |
| 10 | motion law. |
| 11 | |
| 12 | ## The prime directive: visualize, don't list |
| 13 | |
| 14 | Every theme is illustrated by an **animated mock of the actual UI or a |
| 15 | faithful analog** acting out the change in experience — never text bullets. |
| 16 | Route every theme/item through `references/visualization-registry.md` BEFORE |
| 17 | writing the script; the registry decides ui-recreate / ui-analog / terminal / |
| 18 | checklist. Text checklist is the LAST resort, reserved for genuinely |
| 19 | non-visual items (reliability fix lists). |
| 20 | |
| 21 | ## Pipeline |
| 22 | |
| 23 | ### 0 · Bootstrap the project from THIS skill's assets — non-negotiable |
| 24 | |
| 25 | **Do this before writing any composition HTML. Skipping it always produces a video that looks like a similar project you built before, NOT this skill's brand — that's the single most common way this skill goes off-brand.** The skill's assets, fonts, and scaffold are the skill; the SKILL.md prompt is a router. |
| 26 | |
| 27 | ```bash |
| 28 | mkdir -p project/assets/fonts |
| 29 | cp <SKILL_DIR>/assets/fonts/*.woff2 project/assets/fonts/ |
| 30 | cp <SKILL_DIR>/assets/bgm.mp3 project/bgm.mp3 |
| 31 | ffmpeg -y -stream_loop 15 -i <SKILL_DIR>/assets/bg-pattern.mp4 -t <TOTAL> \ |
| 32 | -vf "scale=1080:1080,fps=30,eq=saturation=0.72,drawbox=c=black@0.5:t=fill" \ |
| 33 | -an -c:v libx264 -crf 20 -pix_fmt yuv420p project/assets/bg-pattern-<TOTAL>s.mp4 |
| 34 | cp <SKILL_DIR>/examples/master-skeleton.html project/index.html |
| 35 | ``` |
| 36 | |
| 37 | Then **read `references/build-spec.md` end-to-end** (not skimmed) — it defines the brand tokens (TT Norms Pro + ABC Solar Display + TT Norms Mono, cream `#f5f6f4`, rationed green `#5ef17c`, glass cards with green-tinted borders, kicker/sec-chip pill shape, 32px caption rail at `top: 990`) that every scene inherits from the scaffold. |
| 38 | |
| 39 | Only THEN begin steps 1-6 below. Steps 1-4 (parse, route, script, VO) plan what goes into the scaffold; step 5 fills placeholders (`<RANGE>`, `<TOTAL>`, `<CUT_N>`, `<DUR_N>`, scene bodies) inside the already-copied `project/index.html` — you do NOT rewrite the scaffold's chrome, fonts, palette, or layout shell. |
| 40 | |
| 41 | If you catch yourself reaching for `cp` on a prior video's `index.html`, or writing your own `@font-face` declarations, or designing a WebGL shader background instead of using the encoded bg-pattern MP4 above: STOP. Delete the current `index.html` and restart at the `cp` of the master-skeleton scaffold. Rebuilding scene content on the right scaffold is cheaper than retrofitting brand into the wrong scaffold. |
| 42 | |
| 43 | ### 1 · Parse + editorial cut |
| 44 | |
| 45 | - Extract: week range, headline stats (releases, commits), themes, items. |
| 46 | - **Budget: 45-60s total.** Title ≤2s, outro ≤3.5s, 4 themes ≈ 9-12s each. |
| 47 | - Per theme keep ONE hero visualization + at most 3 spoken items. Everything |
| 48 | else exists only as the outro's "full digest" pointer. Cutting is the job: |
| 49 | a changelog with 30 items still yields ≤14 spoken beats. |
| 50 | - Order themes by story: marquee feature → product surface → performance → |
| 51 | reliability (the digest usually already reads this way). |
| 52 | |
| 53 | ### 2 · Visualization routing |
| 54 | |
| 55 | For each theme, pick the surface from `references/visualization-registry.md` |
| 56 | and write one line: `theme → surface → the 2-4 sequenced actions the mock |
| 57 | performs, each tied to a script phrase`. If no registry surface fits and no |
| 58 | faithful analog exists, it's a checklist scene — don't invent fake UI for |
| 59 | something we can't represent honestly. |
| 60 | |
| 61 | ### 3 · Two-layer script (spoken vs display) |
| 62 | |
| 63 | Write the script as **token lines** per `references/script-voice.md`: |
| 64 | conversational register, every technical term carrying a `spoken` phonetic |
| 65 | form from `references/lexicon.json` while `display` keeps standard spelling. |
| 66 | Captions show `display`; the VO reads `spoken`. Any term not in the lexicon: |
| 67 | STOP and ask the user how it's pronounced, then add it to the lexicon. |
| 68 | Save as `script-tokens.json` in the project. |
| 69 | |
| 70 | ### 4 · VO — Annie (HeyGen, pinned) |
| 71 | |
| 72 | ```bash |
| 73 | # spoken-layer text only; words JSON = ground-truth timestamps of the SPOKEN text |
| 74 | # Repo-native path: the changelog-video skill runs from the hyperframes repo root, |
| 75 | # so it uses the tracked hyperframes-media TTS helper directly (no `npx hyperframes |
| 76 | # skills` install step). If you've copied the skill into another repo, swap in |
| 77 | # your own path to the media-use / hyperframes-media heygen-tts.mjs. |
| 78 | node skills/hyperframes-media/scripts/heygen-tts.mjs ./vo-spoken.txt \ |
| 79 | -o voiceover.mp3 --words vo-words.json \ |
| 80 | --voice 330290724a1b470fb63153f34d4c0183 # Annie — lifelike (do not substitute) |
| 81 | ``` |
| 82 | |
| 83 | Requires `heygen` CLI ≥0.3.0 authenticated (`heygen auth login --oauth`). |
| 84 | Then align spoken timestamps back to display tokens: |
| 85 | |
| 86 | ```bash |
| 87 | node <SKILL_DIR>/scripts/align-captions.mjs \ |
| 88 | --tokens script-tokens.json --words vo-words.json --out captions.json |
| 89 | ``` |
| 90 | |
| 91 | `captions.json` is the caption-rail input (display spelling, spoken timing). |
| 92 | The aligner prints `MISMATCH` warnings — resolve every one before building |
| 93 | (usually a lexicon spelling the TTS renders as multiple words). **The audio |
| 94 | is the clock**: all beat times come from `vo-words.json`; a VO regen re-opens |
| 95 | every seam. |
| 96 | |
| 97 | **Word-timings are a hard gate.** Before moving on to step 5, verify |
| 98 | `vo-words.json` is non-empty and has a `words: [...]` array with `start`/`end` |
| 99 | per word. If it's empty (0 bytes) or missing the array — a known failure mode |
| 100 | when the TTS provider returns audio but no timestamp payload — DO NOT proceed |
| 101 | without them. Fallback: forced-align the produced audio against the display |
| 102 | script using local whisper: |
| 103 | |
| 104 | ```bash |
| 105 | uvx --from openai-whisper whisper voiceover.mp3 \ |
| 106 | --model base.en --language en --word_timestamps True \ |
| 107 | --output_format json --output_dir . |
| 108 | # then run align-captions.mjs with --words voiceover.json (same shape) |
| 109 | ``` |
| 110 | |
| 111 | Whisper mishears TTS renderings ("gee-sap" → "gsap", "heyjen" → "hey Jen", |
| 112 | etc.) — captions still use the DISPLAY spelling from `script-tokens.json`; |
| 113 | whisper only supplies the timestamps. `align-captions.mjs` handles the join. |
| 114 | This fallback is the difference between a captioned build and a silently |
| 115 | uncaptioned one. |
| 116 | |
| 117 | ### 5 · Build |
| 118 | |
| 119 | Follow `references/build-spec.md` exactly: brand tokens + fonts (bundled in |
| 120 | `<SKILL_DIR>/assets/`), the animated background encode, scene scaffold, |
| 121 | chrome, caption rail, one rationed green moment per scene. Then the doctrine |
| 122 | order: `ledger.json` (all ordinary seams cut-the-curve LEFT) → seam-stamp → |
| 123 | internal beats on VO words → seam-gate verify. |
| 124 | |
| 125 | **Captions are non-optional.** The master-skeleton ships a caption-rail IIFE |
| 126 | that reads a `LINES` array — leaving that array empty is a shipped bug, not a |
| 127 | style choice. Populate it from `captions.json` before proceeding to step 6: |
| 128 | |
| 129 | ```javascript |
| 130 | // paste in place of "const LINES = /* … */ []" in the caption-rail IIFE: |
| 131 | const LINES = /* contents of captions.json */ [ |
| 132 | { id: 0, end: 2.74, w: [["This", 0.0], ["week,", 0.30], …] }, |
| 133 | … |
| 134 | ]; |
| 135 | ``` |
| 136 | |
| 137 | If `align-captions.mjs` was skipped or `LINES` is `[]`, the frame check in |
| 138 | step 6 will fail — do not paper over it by removing `#cap-line` from the |
| 139 | scaffold. |
| 140 | |
| 141 | ### 6 · Gates (all green before presenting) |
| 142 | |
| 143 | 1. `bun run --cwd packages/cli hyperframes check` (or the installed |
| 144 | `hyperframes` CLI from the repo-local `skills/hyperframes-cli/` skill) — |
| 145 | 0 errors (contrast: dim text ≥ .66 alpha). Do NOT reach for |
| 146 | `npx hyperframes@latest`; the tracked repo-local CLI is the source of |
| 147 | truth for the composition contract this skill produces against. |
| 148 | 2. `seam-gate.mjs verify` — 0 fail. |
| 149 | 3. Restart the preview server (it caches the bundle), spot-check 3-4 beats |
| 150 | via `__player.seek` on the raw comp page. |
| 151 | 4. Do NOT render unless the user asks. After a requested render, verify |
| 152 | frames from the MP4 (`ffmpeg -ss <t> … -frames:v 1`): captions present, |
| 153 | background video not black, no tiny/frozen frames. |
| 154 | 5. **Caption presence gate — hard fail.** Sample 3-4 frames spread across |
| 155 | the VO's spoken window (e.g. `t=3`, `t=15`, `t=30`, `t=42` for a 48s VO) |
| 156 | and confirm the caption rail at `top: 990` renders visible text on each. |
| 157 | If any frame in a spoken interval is missing captions, the build ships |
| 158 | uncaptioned — treat it as a red gate and re-check step 5's `LINES` |
| 159 | population. This is exactly what went wrong on the Jul 13-20 v4 build. |
| 160 | |
| 161 | ## Project layout |
| 162 | |
| 163 | ``` |
| 164 | projects/active/weekly-changelog-<range>/ |
| 165 | ├── index.html # single-doc master (scenes as slides, stamped seams) |
| 166 | ├── ledger.json # vector ledger (seam-stamp input) |
| 167 | ├── script-tokens.json # two-layer script (source of truth for VO + captions) |
| 168 | ├── vo-spoken.txt # generated: spoken layer, one line |
| 169 | ├── voiceover.mp3 + vo-words.json + captions.json |
| 170 | ├── bgm.mp3 # copy from <SKILL_DIR>/assets/bgm.mp3 (the house track) unless the user supplies one |
| 171 | └── assets/fonts/ + assets/bg-pattern-<dur>s.mp4 |
| 172 | ``` |
| 173 | |
| 174 | ## Anti-patterns |
| 175 | |
| 176 | | Don't | Instead | |
| 177 | | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | |
| 178 | | Bullet-point slides for UI changes | Mock the surface acting out the change | |
| 179 | | Fake UI for un-representable items | Honest checklist scene | |
| 180 | | Plain "JSON"/"CLI" in the TTS text | Lexicon spoken forms; display stays standard | |
| 181 | | Phonetic spellings in captions | Captions always render the display layer | |
| 182 | | Guessing an unknown term's pronunciation | Ask, then grow the lexicon | |
| 183 | | Speaking every changelog item | ≤3 per theme; the digest link carries the rest | |
| 184 | | Green accents everywhere | One green moment per scene (#5ef17c) | |
| 185 | | Starting from a prior video's index.html | Step 0 — copy `examples/master-skeleton.html` from this skill into `project/index.html`, always | |
| 186 | | Hand-crafted `@font-face` / WebGL shader / custom BGM | Step 0 — copy this skill's `assets/` verbatim; the skill's assets ARE the brand | |
| 187 | | Delivered without CloudFront invalidation | Run `aws cloudfront create-invalidation` on distribution `E2BSLVSZ7FG3U0` for the exact path after any S3 replace — CDN caches the old file otherwise | |
| 188 | | Shipping with the `LINES` array empty in the scaffold | Step 4 must produce a populated `captions.json`; step 5 must paste it into the IIFE; step 6 gate 5 must confirm captions on rendered frames. An empty `LINES` = uncaptioned ship = re-do the run | |
| 189 | | No `vo-words.json` → skip captions and ship anyway | Fall back to whisper forced alignment on the produced audio; captions are non-optional | |