Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
49cbf55
feat(skills): video-creation workflow suite — routable workflows
WaterrrForever Jun 11, 2026
e3f5fc7
feat(embedded-captions): nightcity cover-letterform theme + render-ch…
jieling-jenson Jun 11, 2026
0fd6158
style(skills): oxfmt suite tree + oxlint fixes; skill-lint rephrase
jieling-jenson Jun 11, 2026
d66c831
fix(embedded-captions): codeql hardening — execFileSync arg arrays + …
jieling-jenson Jun 11, 2026
a49f727
chore(fallow): ignore skills font bundles — runtime fs reads, not imp…
jieling-jenson Jun 11, 2026
c68236e
feat(skills): video-creation workflow suite — routable workflows
WaterrrForever Jun 11, 2026
7131cca
fix(skills): tighten video-workflow routing + scrub Claude-isms (PR #…
WaterrrForever Jun 11, 2026
dd5de4d
refactor(skills): split prep/validate + extract hierarchy gate (PLV/F…
WaterrrForever Jun 11, 2026
cad0d0e
feat(embedded-captions): nightcity cover-letterform theme + render-ch…
jieling-jenson Jun 11, 2026
9a1f131
style(skills): oxfmt suite tree + oxlint fixes; skill-lint rephrase
jieling-jenson Jun 11, 2026
f5497c5
fix(embedded-captions): codeql hardening — execFileSync arg arrays + …
jieling-jenson Jun 11, 2026
7259d10
chore(fallow): ignore skills font bundles — runtime fs reads, not imp…
jieling-jenson Jun 11, 2026
74ab35b
docs(embedded-captions): trim SKILL.md description to 1016 chars (<1024)
WaterrrForever Jun 11, 2026
9824349
fix(skills): route audio.mjs tmp files through private mkdtemp dir (P…
WaterrrForever Jun 11, 2026
55d41e5
fix(skills): harden tag-strip regexes flagged by CodeQL (PR #1349 tri…
WaterrrForever Jun 11, 2026
64e25bb
fix(skills): match attributed/self-closing end tags in block extracti…
WaterrrForever Jun 11, 2026
1499765
refactor(embedded-captions): fetch PP-MattingV2 model on demand inste…
WaterrrForever Jun 11, 2026
16d286f
refactor(hyperframes-animation): make examples self-contained, drop 3…
WaterrrForever Jun 11, 2026
a18f655
style(hyperframes-animation): oxfmt the 4 SVG-placeholder examples
WaterrrForever Jun 11, 2026
cc930eb
fix(cli): clear fallow audit gate (PR #1349 CI)
WaterrrForever Jun 12, 2026
bfefa50
Merge remote-tracking branch 'origin/feat/video-best-practice' into f…
jieling-jenson Jun 12, 2026
0a5d629
feat(embedded-captions): sync live skill — 22 new themes, Standard re…
jieling-jenson Jun 12, 2026
80d2e8e
Merge remote-tracking branch 'origin/main' into feat/video-best-practice
jieling-jenson Jun 12, 2026
005806d
fix(embedded-captions): clear CI lint — dead declarations + backtick …
jieling-jenson Jun 12, 2026
ece09e6
fix(embedded-captions): read-with-catch for matte.fps (CodeQL js/file…
jieling-jenson Jun 12, 2026
1e9f117
fix(embedded-captions): e2e cold-start findings — VFR matte desync +6
jieling-jenson Jun 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 8 additions & 0 deletions .fallowrc.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,14 @@
"packages/engine/tests/**",
"skills/**/test-corpus/**",
"skills/**/scripts/**",
// Agent-invoked motion-graphics tools co-located with their docs (run via
// `node <path>` per grounding/PROTOCOL.md / categories/maps/module.md
// prose), not import-graph reachable.
"skills/motion-graphics/grounding/**",
"skills/motion-graphics/categories/**",
// Bundled @font-face data (read at runtime via fs.readFileSync, invisible
// to the import graph) + its manual rebuild tool.
"skills/**/fonts/**",
// Golden snapshot files: data consumed by toMatchFileSnapshot, not importable modules.
"packages/**/__goldens__/**",
"registry/**",
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,5 @@ test-outputs/
.claude/
docs/superpowers/
.worktrees
hyperframes-bench/
tmp/
6 changes: 6 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,9 @@ packages/gcp-cloud-run/terraform/workflow.yaml

# toMatchFileSnapshot golden files — vitest writes these; oxfmt must not reformat them.
packages/**/__goldens__/

# vendored third-party bundles inside skills — never reformat
skills/**/assets/vendor/
skills/**/*.min.js
# reference snippets with intentional pseudo-markup (literal "..." attributes)
skills/graphic-overlays/references/frames/polaroid.html
13 changes: 13 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ This repo ships AI agent skills via [vercel-labs/skills](https://github.com/verc
npx skills add heygen-com/hyperframes
```

**Video-creation workflows** route through one entry skill — `/hyperframes-read-first` orients you to the whole surface and maps "make me a video" intent to a concrete workflow. Consult it before invoking a specific workflow:

- `/product-launch-video` — a **product** URL (or a pre-written script / text brief in no-capture mode) → product launch / promo video, up to ~3 min (sweet spot ~30-90s).
- `/website-to-video` — a **general** website / URL → a video _of_ the site (tour / showcase / social clip from captured screenshots + assets); for a product **launch / promo**, use `/product-launch-video`.
- `/faceless-explainer` — arbitrary text, **no URL and no website capture** → faceless explainer, up to ~3 min (sweet spot ~30-90s); every visual is LLM-invented (typography / abstract graphics / diagram / data-viz).
- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (verbatim rail + embedded climax, or pure-cinematic embed); the footage itself is untouched (no NLE-style editing).
- `/graphic-overlays` — an existing talking-head / interview / podcast video (MP4) → the same footage packaged with designed **graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath, footage untouched. Replaces the removed `/footage-recut`. For plain captions/subtitles → `/embedded-captions`.
- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → code-change explainer, up to ~3 min (changelog / feature reveal / fix / refactor). A PR link, not a product website.
- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
- `/general-video` — fallback for any other video creation (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition); the original hyperframes flow — design → plan → layout → build → validate, any length.

**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) video composition into HyperFrames HTML — a source migration, separate from the creation workflows above.

## Build & Test

```bash
Expand Down
128 changes: 55 additions & 73 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,105 +2,87 @@

Open-source video rendering framework: write HTML, render video.

```
packages/
cli/ → hyperframes CLI (create, preview, lint, render)
core/ → Types, parsers, generators, linter, runtime, frame adapters
engine/ → Seekable page-to-video capture engine (Puppeteer + FFmpeg)
player/ → Embeddable <hyperframes-player> web component
producer/ → Full rendering pipeline (capture + encode + audio mix)
studio/ → Browser-based composition editor UI
```
## Skills

## Development
This repo ships AI agent skills via [vercel-labs/skills](https://github.com/vercel-labs/skills). Install them before writing compositions — they encode framework-specific patterns that generic docs don't cover.

```bash
bun install # Install dependencies
bun run build # Build all packages
bun run test # Run tests
npx skills add heygen-com/hyperframes
```

**This repo uses bun**, not pnpm. Do NOT run `pnpm install` — it creates a `pnpm-lock.yaml` that should not exist. Workspace linking relies on bun's resolution from `"workspaces"` in root `package.json`.
**Video-creation workflows** route through one entry skill — `/hyperframes-read-first` orients you to the whole surface and maps "make me a video" intent to a concrete workflow. Consult it before invoking a specific workflow:

### Linting & Formatting
- `/product-launch-video` — a **product** URL (or a pre-written script / text brief in no-capture mode) → product launch / promo video, up to ~3 min (sweet spot ~30-90s).
- `/website-to-video` — a **general** website / URL → a video _of_ the site (tour / showcase / social clip from captured screenshots + assets); for a product **launch / promo**, use `/product-launch-video`.
- `/faceless-explainer` — arbitrary text, **no URL and no website capture** → faceless explainer, up to ~3 min (sweet spot ~30-90s); every visual is LLM-invented (typography / abstract graphics / diagram / data-viz).
- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (verbatim rail + embedded climax, or pure-cinematic embed); the footage itself is untouched (no NLE-style editing).
- `/graphic-overlays` — an existing talking-head / interview / podcast video (MP4) → the same footage packaged with designed **graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath, footage untouched. Replaces the removed `/footage-recut`. For plain captions/subtitles → `/embedded-captions`.
- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → code-change explainer, up to ~3 min (changelog / feature reveal / fix / refactor). A PR link, not a product website.
- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
- `/general-video` — fallback for any other video creation (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition); the original hyperframes flow — design → plan → layout → build → validate, any length.

This project uses **oxlint** and **oxfmt** (not biome, not eslint, not prettier).
**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) video composition into HyperFrames HTML — a source migration, separate from the creation workflows above.

## Build & Test

```bash
bunx oxlint <files> # Lint
bunx oxfmt <files> # Format (write)
bunx oxfmt --check <files> # Format (check only, used by pre-commit hook)
bun install # Install dependencies (NOT pnpm — do not create pnpm-lock.yaml)
bun run build # Build all packages
bun run test # Run all tests
```

Always run both on changed files before committing. The lefthook pre-commit hook runs `bunx oxlint` and `bunx oxfmt --check` automatically.

### Adding CLI Commands

When adding a new CLI command:

1. Define the command in `packages/cli/src/commands/<name>.ts` using `defineCommand` from citty
2. **Export `examples`** in the same file — `export const examples: Example[] = [...]` (import `Example` from `./_examples.js`). These are displayed by `--help`.
3. Register it in `packages/cli/src/cli.ts` under `subCommands` (lazy-loaded)
4. **Add to help groups** in `packages/cli/src/help.ts` — add the command name and description to the appropriate `GROUPS` entry. Without this, the command won't appear in `hyperframes --help` even though it works.
5. **Document it** in `docs/packages/cli.mdx` — add a section with usage examples and flags.
6. Validate by running `npx tsx packages/cli/src/cli.ts --help` (command appears in the list) and `npx tsx packages/cli/src/cli.ts <name> --help` (examples appear).

### Regression Test Golden Baselines (producer)
### Linting & Formatting

`packages/producer/tests/<name>/output/output.mp4` baselines MUST be generated
inside `Dockerfile.test`, not on your host. CI renders inside that Docker image
with a specific Chrome + ffmpeg build; pixel-level output drifts across
different host Chrome/ffmpeg versions and will fail PSNR at dozens of
checkpoints even when the code is correct.
Uses **oxlint** and **oxfmt** (not eslint, not prettier, not biome).

```bash
# Build the test image once:
docker build -t hyperframes-producer:test -f Dockerfile.test .

# Generate or update a baseline (runs the harness with --update inside Docker):
bun run --cwd packages/producer docker:test:update <test-name>
bunx oxlint <files> # Lint
bunx oxfmt <files> # Format
bunx oxfmt --check <files> # Check formatting (CI / pre-commit)
```

Never run `bun run --cwd packages/producer test:update` directly from the
host to capture a baseline that will be committed — the resulting output.mp4
will not match CI. Use it only for local-only experimentation.

## Releasing
Always lint and format changed files before committing. Lefthook pre-commit hooks enforce this automatically.

All eight packages share one version. `.github/workflows/publish.yml` publishes
them when a `v*` tag is pushed (it also accepts a manual `workflow_dispatch` with
a version input). The CLI publishes as the unscoped `hyperframes` package; the
other seven as `@hyperframes/*`.
### Composition Validation

Cut a release from `main`:
After creating or editing any `.html` composition:

```bash
bun run release:prepare <version> # e.g. 0.6.72
npx hyperframes lint # Static HTML structure check
npx hyperframes validate # Runtime check (headless Chrome — catches JS errors, missing assets)
```

Run it twice:
Both must pass before previewing or considering work complete.

1. **First run** writes `releases/v<version>.md` and prepends an entry to
`docs/changelog.mdx`, then stops with a non-zero exit. Edit both files: write
the 1–2 sentence summary and remove the `<!-- TODO -->` marker.
2. **Second run** (after the TODO is gone) bumps every package and plugin
manifest, creates the `chore: release v<version>` commit, and tags
`v<version>` (lightweight).
## Project Structure

Then push to trigger the publish:

```bash
git push origin main --tags
```
packages/
cli/ → hyperframes CLI (create, preview, lint, render)
core/ → Types, parsers, generators, linter, runtime, frame adapters
engine/ → Seekable page-to-video capture engine (Puppeteer + FFmpeg)
player/ → Embeddable <hyperframes-player> web component
producer/ → Full rendering pipeline (capture + encode + audio mix)
shader-transitions/ → WebGL shader transitions for compositions
studio/ → Browser-based composition editor UI
registry/
blocks/ → Installable sub-composition scenes (50+)
components/ → Installable effects and snippets
examples/ → Starter project templates
docs/ → Mintlify documentation site (hyperframes.heygen.com)
skills/ → AI agent skill definitions
```

Notes:
## Key Conventions

- Pre-release versions (`0.6.72-alpha.1`) publish to the matching npm dist-tag
(`alpha`) instead of `latest`.
- `--skip-changelog-check` skips the changelog gate for emergency releases.
- The publish step skips any version already on npm, so re-running a failed
workflow run is safe.
- **Package manager**: bun (not pnpm, not npm for workspace operations)
- **Commit format**: Conventional commits (`feat:`, `fix:`, `docs:`, `refactor:`, `test:`)
- **TypeScript**: Avoid `any` and `as T` assertions. Prefer type guards and narrowing.
- **Compositions**: HTML files with `data-*` attributes. Clips need `class="clip"`. GSAP timelines must be paused and registered on `window.__timelines`.
- **Frame Adapters**: Animation runtimes plug in via the seek-by-frame adapter pattern. GSAP is the primary adapter.
- **Deterministic rendering**: No `Date.now()`, no unseeded `Math.random()`, no render-time network fetches.

## Skills
## Documentation

Composition authoring (not repo development) is guided by skills installed via `npx skills add heygen-com/hyperframes`. See `skills/` for source. Invoke `/hyperframes`, `/hyperframes-cli`, `/hyperframes-registry`, `/tailwind`, or `/gsap` when authoring compositions. Use `/tailwind` for projects created with `hyperframes init --tailwind` so agents follow the pinned Tailwind v4 browser-runtime contract instead of Studio's Tailwind v3 setup. Use `/animejs`, `/css-animations`, `/lottie`, `/three`, or `/waapi` when a composition uses those first-party runtime adapters. Invoke `/hyperframes-media` for asset preprocessing (TTS narration, audio/video transcription, background removal for transparent overlays) — these commands have their own skill so the CLI skill stays focused on the dev loop. When a user provides a website URL and wants a video, invoke `/website-to-hyperframes` — it runs the full 7-step capture-to-video pipeline.
- Docs: https://hyperframes.heygen.com/introduction
- Catalog (50+ blocks): https://hyperframes.heygen.com/catalog/blocks/data-chart
2 changes: 1 addition & 1 deletion docs/guides/pipeline.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ Each artifact is a checkpoint, so you can stop, hand off to a human reviewer, or

The pipeline is the recommended structure for:

- Capturing a website with the [/website-to-hyperframes](/guides/prompting) skill, which follows it end-to-end.
- Capturing a website with the [/website-to-video](/guides/website-to-video) skill, which follows it end-to-end.
- Shipping a product launch. Most of the [HeyGen launch videos](/launch-videos) use this artifact layout.
- Any narrative video with three or more beats, where a storyboard pays for itself.
- Learning Hyperframes, because the artifacts leave every creative decision inspectable on disk.
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/prompting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ In Claude Code, restart the session after installing. Skills register as **slash
| `/hyperframes-cli` | Dev-loop CLI — `init`, `lint`, `inspect`, `preview`, `render`, `doctor` |
| `/hyperframes-media` | Asset preprocessing — `tts`, `transcribe`, `remove-background` |
| `/hyperframes-registry` | Block and component installation via `hyperframes add` |
| `/website-to-hyperframes` | Capture a URL and turn it into a video; runs the full [Hyperframes pipeline](/guides/pipeline) |
| `/website-to-video` | Capture a URL and turn it into a video; runs the full [Hyperframes pipeline](/guides/pipeline) |
| `/gsap` | GSAP animation API — timelines, easing, ScrollTrigger, plugins |

<Tip>
Expand Down
2 changes: 1 addition & 1 deletion docs/guides/website-to-video.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ See the [pipeline guide](/guides/pipeline#iterating) for more re-entry patterns.
npx skills add heygen-com/hyperframes
```

Lead your prompt with _"Use the /website-to-hyperframes skill"_ for the most reliable results. Agents also discover it automatically when they see a URL and a video request.
Lead your prompt with _"Use the /website-to-video skill"_ for the most reliable results. Agents also discover it automatically when they see a URL and a video request.
</Accordion>
</AccordionGroup>

Expand Down
2 changes: 1 addition & 1 deletion docs/packages/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ This is suppressed in CI environments, non-TTY shells, and when `HYPERFRAMES_NO_

The capture command extracts everything an AI agent needs to understand a website's visual identity: viewport screenshots at every scroll depth, color palette (pixel-sampled + DOM computed), font files, images with semantic names, SVGs, Lottie animations, video previews, WebGL shaders, visible text, and page structure.

Output is a self-contained directory with a `CLAUDE.md` file that any AI agent can read to understand the captured site. Used by the `/website-to-hyperframes` skill as step 1 of the video production pipeline.
Output is a self-contained directory with a `CLAUDE.md` file that any AI agent can read to understand the captured site. Used by the `/website-to-video` skill as step 1 of the video production pipeline.

Set `GEMINI_API_KEY` in a `.env` file for AI-powered image descriptions via Gemini vision (~$0.001/image). See the [Website to Video](/guides/website-to-video#enriching-captures-with-gemini-vision) guide for details.

Expand Down
12 changes: 11 additions & 1 deletion packages/cli/scripts/build-copy.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const DIST = join(CLI_ROOT, "dist");
const STUDIO_WAIT_TIMEOUT_MS = 30_000;
const STUDIO_POLL_INTERVAL_MS = 250;

// fallow-ignore-next-line complexity
async function waitForStudioDist(dir) {
const deadline = Date.now() + STUDIO_WAIT_TIMEOUT_MS;
while (Date.now() < deadline) {
Expand Down Expand Up @@ -54,6 +55,7 @@ function copyMdFiles(srcDir, destDir) {
}
}

// fallow-ignore-next-line complexity
async function main() {
for (const sub of ["studio", "docs", "templates", "skills", "docker"]) {
mkdirSync(join(DIST, sub), { recursive: true });
Expand All @@ -68,8 +70,16 @@ async function main() {
copyDir(join(CLI_ROOT, "src", "templates", tmpl), join(DIST, "templates", tmpl));
}

// Skills bundled into the published CLI. Branches don't all carry the same
// skills/ tree (it gets restructured), so each entry is existsSync-guarded:
// a missing skill dir warns + skips instead of crashing the build.
for (const skill of ["hyperframes", "hyperframes-cli", "gsap"]) {
copyDir(join(REPO_ROOT, "skills", skill), join(DIST, "skills", skill));
const src = join(REPO_ROOT, "skills", skill);
if (!existsSync(src)) {
console.warn(`[build-copy] skill not found, skipping: skills/${skill}`);
continue;
}
copyDir(src, join(DIST, "skills", skill));
}

const dockerfile = join(CLI_ROOT, "src", "docker", "Dockerfile.render");
Expand Down
6 changes: 4 additions & 2 deletions packages/cli/src/capture/agentPromptGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*
* This file generates a DATA INVENTORY that tells the AI agent what files
* exist and what they contain. The actual workflow lives in the
* website-to-hyperframes skill — this file points agents there.
* website-to-video skill — this file points agents there.
*/

import { writeFileSync, readdirSync, existsSync } from "node:fs";
Expand All @@ -20,6 +20,7 @@ import type { CatalogedAsset } from "./assetCataloger.js";
* Infer a human-readable role hint from a hex color based on luminance and saturation.
* Not a substitute for DESIGN.md — just helps orient agents scanning the brand summary.
*/
// fallow-ignore-next-line complexity
function inferColorRole(hex: string): string {
const r = parseInt(hex.slice(1, 3), 16) / 255;
const g = parseInt(hex.slice(3, 5), 16) / 255;
Expand Down Expand Up @@ -56,6 +57,7 @@ export function generateAgentPrompt(
writeFileSync(join(outputDir, ".cursorrules"), prompt, "utf-8");
}

// fallow-ignore-next-line complexity
function buildPrompt(
outputDir: string,
url: string,
Expand Down Expand Up @@ -196,7 +198,7 @@ function buildPrompt(

Source: ${url}

To create a video from this capture, use the \`website-to-hyperframes\` skill.
To create a video from this capture, use the \`website-to-video\` skill.

## What's in This Capture

Expand Down
Loading
Loading