mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-12 15:20:13 +00:00
Packages Jake Moran's changelog-video pipeline (v1, validated end-to-end
by Home on the Jun 23-29 range) as a repo-native skill set that Claude
Code (.claude/skills/) and Codex CLI (.agents/skills/) auto-discover the
moment the repo is opened. No install step; run the skill against a
changelog markdown for a given git range and it produces a lint-clean,
seam-gate-green 1080x1080 MP4 (~45-60s, Annie VO, mock-UI visualizations,
caption rail) end-to-end.
Six skills added byte-identical in both mirror dirs:
- changelog-video (pipeline entry point)
- motion-doctrine (carries seam-stamp.mjs + seam-gate.mjs)
- cut-the-curve, captions-overlay, seam-craft, oversized-cursor
Layout:
- .claude/skills/ - Claude Code project-local auto-discover
- .agents/skills/ - Codex CLI project-local auto-discover (verified via
Magi's clean-home Codex 0.144.3 repro; NOT .codex/skills/)
Fonts, animated background (12 MB), house BGM (5 MB), lexicon, and
align-captions ship inside the skill dirs. .gitattributes routes only
.claude/skills/**/*.{mp4,mp3} + .agents/skills/**/*.{mp4,mp3} through
LFS — narrowly scoped so unrelated Player, Studio, registry, and
marketplace media stay put. HeyGen CLI auth is the one credential the
skill needs; Node >= 22, ffmpeg, and headless Chrome are documented
alongside in both READMEs.
.gitignore: rewrites .claude/ and .agents/ blocks to keep agent-installed
skill hygiene while re-including the six repo-native skill dirs plus
README.md.
CI:
- Extends changes.skills filter to match .claude/skills/**,
.agents/skills/**, scripts/lint-skills.ts, and scripts/check-skill-mirror.mjs.
- New 'Skills: project-native lint + mirror' job runs the extended
lint-skills.ts (schema-driven; required { name, description } + optional
{ license, allowed-tools, metadata }, name pattern check, description
length check) plus a new check-skill-mirror.mjs byte-integrity script
(24 mirrored files must match; README.md deliberately per-CLI).
- Wired into 'bun run lint' locally.
Frontmatter validator:
- Rejects unsupported top-level keys (catches category:-style drift).
- Requires name + description.
- Validates name pattern (^[a-z][a-z0-9-]{0,63}$) and description shape
(non-empty, <=1024 chars).
- Missing frontmatter block itself is a first-class error.
Also strips unsupported top-level 'category:' frontmatter from Jake's
motion-doctrine and cut-the-curve SKILL.mds (both mirrors), rewrites the
TTS invocation from ~/.claude/skills/media-use/... to the tracked
skills/hyperframes-media/scripts/heygen-tts.mjs, swaps npx hyperframes@latest
for the repo-local CLI in the gate step, and fixes a lint issue in Jake's
seam-gate.mjs (ternary-for-side-effect -> if/else).
Validated end-to-end by Home on Jun 23-29 (MP4 posted in C0ACCNHLG3U
thread 1784181166.041319). Independently reviewed R1/R2/R3 by Magi.
Co-authored-by: Jake Moran <jake@heygen.com>
94 lines
4.4 KiB
Markdown
94 lines
4.4 KiB
Markdown
# seam-stamp.mjs + seam-gate.mjs — usage + ledger schema
|
||
|
||
Generate-and-verify pair for the Seam Gate. Zero npm deps (node ≥ 22 + a local Chrome;
|
||
the gate finds `~/.cache/puppeteer` chrome-headless-shell or system Chrome automatically).
|
||
|
||
```bash
|
||
# STAMP: write the master seam block (base sets + all wrapper tweens) from the ledger.
|
||
# Replaces the // <seams:auto> … // </seams:auto> block (inserts after the
|
||
# window.__timelines["main"] registration if markers are absent). Stamped seams pass
|
||
# the gate by construction. match-cut/morph rows get visibility sets only — the
|
||
# carrier handoff stays hand-authored.
|
||
node <SKILL_DIR>/scripts/seam-stamp.mjs --ledger ledger.json --write index.html
|
||
```
|
||
|
||
Per-seam stamp options in the ledger: `exit.dur` / `entry.dur` (durations),
|
||
`entry.travel` (xPercent/yPercent offset, default 10 — use 8 for a soft entry),
|
||
`blur` (Z seams, default 18px full-frame / set 10 for text-scale).
|
||
|
||
```bash
|
||
# verify every seam in the ledger (exit 0 = gate passed)
|
||
node <SKILL_DIR>/scripts/seam-gate.mjs verify --ledger ledger.json --project <project-dir>
|
||
|
||
# reuse a RUNNING preview server (restart it after comp edits — stale bundle!)
|
||
node <SKILL_DIR>/scripts/seam-gate.mjs verify --ledger ledger.json --url http://localhost:5244
|
||
|
||
# discover movers around a cut time (use to author/fix ledger rows)
|
||
node <SKILL_DIR>/scripts/seam-gate.mjs probe --t 44.8 --project <project-dir>
|
||
```
|
||
|
||
`--project` spawns a fresh preview server with `HYPERFRAME_RUNTIME_URL` unset and kills
|
||
it after — preferred. `--json` for machine output. `--fps 30` default.
|
||
|
||
## ledger.json
|
||
|
||
Lives at the project root. One row per seam; this is the vector ledger as data.
|
||
|
||
```json
|
||
{
|
||
"fps": 30,
|
||
"seams": [
|
||
{
|
||
"id": "hook→claim",
|
||
"cut": 4.2,
|
||
"technique": "cut-the-curve LEFT",
|
||
"exit": { "selector": "#el-hook", "axis": "x", "dir": -1 },
|
||
"entry": { "selector": "#el-claim", "axis": "x", "dir": -1 }
|
||
},
|
||
|
||
{
|
||
"id": "claim→payoff",
|
||
"cut": 10.2,
|
||
"technique": "inverse zoom-through",
|
||
"exit": { "selector": "#el-claim", "axis": "z", "dir": -1 },
|
||
"entry": { "selector": "#el-payoff", "axis": "z", "dir": -1, "scanRoot": "#el-payoff" }
|
||
},
|
||
|
||
{
|
||
"id": "ui→player (match cut)",
|
||
"cut": 60.6,
|
||
"type": "match-cut",
|
||
"carrier": { "out": "#resting-card", "in": "#product-video" }
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
- `cut` — seconds on the master clock, the frame the incoming side ignites.
|
||
- `type` — `"cut"` (default; full vector checks), `"match-cut"` / `"morph"`
|
||
(carrier-continuity + overlap only; motion may start AT the boundary).
|
||
- `axis` — `"x"`, `"y"`, or `"z"` (z = scale). `dir` — sign of motion:
|
||
x −1 = leftward, y −1 = upward, z +1 = push (growing), z −1 = pull (shrinking).
|
||
- `selector` — the element that CARRIES the seam motion. Use the wrapper when the
|
||
master timeline moves the wrapper; use the in-comp hero (id or `[data-hf-id=…]`)
|
||
when the seam motion is authored inside the sub-comp. `probe` tells you which.
|
||
- `entry.scanRoot` (z seams) — subtree scanned for sign-fighting internal entrances;
|
||
defaults to the entry selector.
|
||
- `carrier` — optional on `"cut"` rows; required on match-cut/morph. `out`/`in` rects
|
||
must match at cut±1 frame (12px center / 5% size tolerance, ancestors included).
|
||
|
||
## What each check enforces (Seam Gate rule ↔ report row)
|
||
|
||
| Report row | Rule |
|
||
| ------------------------------------ | -------------------------------------------------------------- |
|
||
| `ledger` | exit/entry vectors match in the PLAN (axis + dir) |
|
||
| `exit-moving` / `entry-moving` | rule 1/3 — no settled exits, no from-rest entries |
|
||
| `exit-direction` / `entry-direction` | rule 3 — measured sign matches the ledger |
|
||
| `speed-match` (WARN) | law §3 — entry velocity ≈ exit velocity |
|
||
| `zero-overlap` | rule 6 — one side visible per frame, never both |
|
||
| `z-sign-scan` | rule 7 — incoming scene's own entrances don't fight the Z sign |
|
||
| `carrier-*` | rules 3/4 — carrier rect continuity, ancestor scale included |
|
||
|
||
Velocities are measured on `getBoundingClientRect` (center for x/y, width-ratio for z),
|
||
so ancestor wrapper transforms are automatically included.
|