## Summary
- Add zoom state (zoomMode, pixelsPerSecond) to player store
- Add timeline element updates (setElements, clearElements)
- Remove unused/duplicate exports from player barrel file
🤖 Generated with [Claude Code](https://claude.com/claude-code)
* feat(cli): add system metrics to telemetry and expand doctor command
Enrich render telemetry with device/environment metadata (CPU, memory,
OS, Docker/CI/WSL detection) following patterns from Next.js and
Turborepo. Add speed_ratio (render time / composition duration),
per-frame capture timing, and resource usage to render events.
Expand the doctor command with CPU, memory, disk, /dev/shm, and
environment checks to help debug rendering issues on user machines.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): invert speed_ratio to match experiment-framework convention
composition_duration / render_time — higher is better, >1 means faster
than realtime. Matches magic_edit.render.speed_ratio in experiment-framework.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(cli): wire errorMessage into render error telemetry
Address review feedback — the errorMessage field was declared in the
trackRenderError interface but never populated.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(cli): add render telemetry to embedded studio server
Track render_complete and render_error from the studio's render API
endpoint (hyperframes dev). Uses dynamic imports so telemetry is
resolved at call time within the CLI package — no telemetry coupling
added to @hyperframes/studio or @hyperframes/producer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Namespace skill names with `hyperframes-` prefix for clearer identity in
OSS contexts where users may have other skills installed.
Updates skill directories, SKILL.md frontmatter, CLAUDE.md, README.md,
CLI build script, init command, and project template.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Changes
Added a new lint rule `gsap_css_transform_conflict` that detects when GSAP animations will silently overwrite CSS transforms.
**`gsap_css_transform_conflict` (error)** — fires when an element has `transform: translateX(-50%)` or `transform: scale()` in CSS and a GSAP `tl.to/from` tween animates `x`, `y`, `xPercent`, `yPercent`, or `scale`. GSAP silently overwrites the full CSS transform, discarding centering tricks like `translateX(-50%)`. Fix hint guides authors to the safe `fromTo` + `xPercent` pattern.
## Root cause
This bug surfaced while building compositions where title reveals were placed off-center because `tl.to("#title", { x: 0 })` stripped the `translateX(-50%)` centering from CSS.
## Test coverage
- [x] `gsap_css_transform_conflict` — `tl.to` with `x` on CSS `translateX` element → error
- [x] `gsap_css_transform_conflict` — `tl.to` with `scale` on CSS `scale()` element → error
- [x] `gsap_css_transform_conflict` — `tl.fromTo` without CSS transform → no finding
Detects querySelector/querySelectorAll calls that use template literal
variables (e.g. `${compId}`) inside script tags. The HTML bundler's
cheerio/css-what parser crashes on these during compilation, causing
silent fallback to raw HTML without runtime injection.
Severity: error (breaks bundling)
Fix: replace template literal with hardcoded composition ID string
## What
Adds 4 new composition templates and fixes structural issues across all templates.
### New templates
- **decision-tree** — animated flowchart with branching paths
- **kinetic-type** — bold kinetic typography promo
- **product-promo** — multi-scene product showcase with SVG assets (3 scenes)
- **nyt-graph** — animated data chart in NYT print editorial style
### Fixes across all templates
- GSAP updated from 3.12.2 → 3.14.2 (all templates, including warm-grain, swiss-grid, vignelli, play-mode)
- New templates restructured with proper root wrapper div, `data-duration`, sub-composition refs with `data-composition-id` / `data-width` / `data-height`
- nyt-chart: replaced `${compId}` template literal variables with hardcoded `"nyt-chart"` string — cheerio's css-what parser crashes on template literals during bundling, causing silent fallback to raw HTML without runtime injection
- nyt-chart: added DOM readiness retry for dynamically created SVG elements
- kinetic-type: removed external S3 audio URL
- All templates: GSAP script loaded in `<head>` before any scripts reference it
## Why
The new templates expand the range of content types available via `hyperframes init`. The fixes ensure all templates work correctly in the studio preview (bundler inlines sub-compositions and injects the runtime).
## Test plan
- [x] All 4 new templates render in studio preview
- [x] nyt-graph chart animates bars, line, and labels on playback
- [x] Existing templates unaffected (GSAP version bump is backwards compatible)
- [x] `hyperframes lint` passes on all templates
- [x] `generators.ts` updated with new template IDs
## Summary
- Adds `process.exit(0)` after render completes in the CLI `render` command
- Fixes the process hanging indefinitely after `npx hyperframes render --output video.mp4`
- Root cause: Node.js `fetch()` keep-alive pool (from update checks and telemetry) keeps TCP connections open, preventing the event loop from draining
- Telemetry is preserved — the `exit` handler in `cli.ts` calls `flushSync()` which spawns a detached child process
## Test plan
- [x] Run `npx hyperframes render --output test.mp4` and verify the process exits after completion
- [x] Verify telemetry events are still sent (check PostHog)
Adds a contextual menu to every docs page with options to copy page
content, open in Claude, connect via MCP to Cursor/VS Code/Windsurf,
and file a GitHub issue — all directly from the docs header.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- README quick start now leads with opening in an AI agent after init
- Quickstart docs updated: interactive wizard is default, --non-interactive
replaces --human-friendly, edit step mentions AI agent workflow
- Init "next steps" now leads with opening in an AI agent as step 1,
followed by dev preview and render as steps 2 and 3
- Interactive init shows a tip about AI agent workflow after scaffolding
- Dev command output hints that compositions can be edited with an
AI agent and changes reload automatically in the studio
The shared CLAUDE.md in scaffolded projects mentioned
hyperframes.heygen.com alongside doc topic names, causing AI agents
to guess incorrect URLs like /compositions instead of using the local
`hyperframes docs` CLI command or the correct /concepts/compositions
path. Now explicitly directs agents to use the CLI for quick reference
and llms.txt for full doc URL discovery.
- Interactive wizard is now the default when running in a TTY terminal
- Non-interactive mode (for CI/agents) uses --non-interactive flag
- Template defaults to "blank" when not specified in non-interactive mode
- --template flag skips the template picker prompt in interactive mode
- Replaces --human-friendly flag with --non-interactive (inverted logic)
npm's sigstore provenance verification requires package.json
repository.url to match the GitHub repo. Without it, publish
fails with E422 "expected to match https://github.com/heygen-com/hyperframes".
- Compute CPU_CORE_COUNT once at module level instead of calling cpus()
multiple times
- Make RenderOptions.workers required (number, not optional) — the
caller resolves the default, callees don't re-derive it
- Remove redundant existsSync guard before mkdirSync({recursive})
- Trim oversized JSDoc on defaultWorkerCount
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace the hardcoded default of 4 workers with a CPU-aware heuristic:
half of available CPU cores, capped at 4. Each worker spawns a separate
Chrome browser process (~256MB RAM each), so the previous default of 4
caused resource contention on smaller machines.
The new defaults:
2-core laptop → 1 worker
4-core laptop → 2 workers
8-core desktop → 4 workers
16-core server → 4 workers (capped)
Also adds --workers auto flag support, improves help text to explain
what workers do, and adds a Workers section to the rendering docs with
guidance on when to increase or decrease parallelism.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
data-in-motion.md — minimal guide for data/stats in video:
- Visual continuity: related data stays in same visual space
- Numbers need visual weight: pair metrics with fills/shapes
- Avoid web patterns: no pie charts, dashboards, axes, legends
house-style.md refinements from eval iterations:
- Layout approach variety (step 4 in Before Writing HTML)
- Explicit weight contrast requirement
- SVG illustration anti-default
- Overlap anti-default
- Ambient motion variety (not always zoom)
SKILL.md — added reference to data-in-motion.md
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## What
Added three new lint rules to the Hyperframe HTML linter to catch common runtime errors and invalid script references.
## Why
These lint rules prevent silent failures and runtime errors that can break Hyperframe compositions:
1. Timeline assignments without initialization guards cause silent failures when `window.__timelines` is undefined
2. Mismatched timeline IDs between `data-composition-id` attributes and `window.__timelines` keys prevent proper auto-nesting
3. Hallucinated script sources referencing non-existent `@hyperframe/` packages result in 404 errors
## How
Implemented three new lint rules with corresponding error codes:
- `timeline_registry_missing_init`: Detects timeline assignments without proper initialization guard using regex pattern matching
- `timeline_id_mismatch`: Cross-references composition IDs from HTML attributes against timeline registry keys to identify mismatches
- `hallucinated_script_src`: Checks script `src` attributes against known bad patterns for non-existent CDN packages
Each rule provides specific error messages and fix hints to guide developers toward correct implementations.
## Test plan
- [x] Unit tests added/updated
- [x] Manual testing performed
- [ ] Documentation updated (if applicable)
Added comprehensive test coverage for all three new lint rules, including both positive and negative test cases to ensure proper detection and avoid false positives.
- Extract `resolveAssetDir()` helper to eliminate copy-paste across
getStaticTemplateDir, getSharedTemplateDir, getBundledSkillsDir
- Remove `counted` boolean in fallbackInstall() — collect installed
skills from first target explicitly, then copy to remaining targets
- Consolidate duplicate `installed.length > 0` check in runInstall()
into a single early return
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace custom git clone + copy logic with `npx skills add` from the
vercel-labs/skills ecosystem. This is the standard used by GSAP,
Remotion, and other skill providers.
- Primary path: `npx skills add heygen-com/hyperframes` and
`npx skills add greensock/gsap-skills` with `-g -y -a <agent>` flags
- Git clone + copy kept as fallback if npx is unavailable
- Added `skillsAgent` field to targets mapping CLI flags to the correct
agent names (e.g., gemini → gemini-cli)
- Removes ~80 lines of custom git/copy infrastructure
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New HyperFrames projects created via `hyperframes init` now include:
- CLAUDE.md + AGENTS.md — teaches AI agents about skills, commands,
project structure, and framework rules (class="clip", timeline
registration, determinism). Agents know to invoke /compose-video
before writing compositions.
- .claude/skills/{compose-video,captions} — project-level skills for
immediate availability in the current agent session (global skills
require a session restart to discover).
- Updated next-steps output with `hyperframes docs <topic>` and a
link to hyperframes.heygen.com.
- Updated README with "AI Agent Skills" section documenting
`npx hyperframes skills` and `npx skills add` install paths.
- Repo-level CLAUDE.md for framework contributors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## What
Enhanced timeline collection to discover GSAP-animated scene elements and persistent overlays through runtime introspection.
## Why
The existing timeline collection only captured elements with explicit timing attributes (`data-start`, `data-track-index`) or media elements, missing scene elements that are animated purely through GSAP tweens and persistent overlay elements that should appear for the full composition duration.
## How
Added two new discovery mechanisms to `collectRuntimeTimelinePayload`:
1. **GSAP Timeline Introspection**: Walks the master timeline's tweens using `getChildren()` to find animated elements, calculates absolute time ranges by traversing parent timelines, and bubbles child tween ranges up to their nearest scene-level ancestors (direct children of root with IDs).
2. **Persistent Overlay Detection**: Identifies direct children of the root composition that weren't captured by DOM queries or GSAP introspection, treating them as full-duration overlay elements while filtering out non-visual elements (script, style, meta tags) and hidden elements.
Both mechanisms respect existing track assignments and create new tracks when needed to avoid conflicts.
## Test plan
- [x] Unit tests added/updated
- [x] Manual testing performed
- [ ] Documentation updated (if applicable)
Added comprehensive test coverage for:
- GSAP-animated scene element discovery via timeline introspection
- Time range bubbling from child elements to scene ancestors
- Persistent overlay inclusion as full-duration clips
- Proper filtering of non-visual elements (script/style tags)


The 3-workflow chain (release.yml → release-tag.yml → publish.yml) was
broken by design: tags created by GITHUB_TOKEN don't trigger other
workflows, so merging a release PR never actually published.
Consolidate into a single publish.yml that triggers on both tag push
and release PR merge. Delete the redundant prepare-release and
tag-release workflows.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## What
Updated the GitHub Actions regression workflow to monitor specific package directories instead of the entire packages folder.
## Why
This change provides more granular control over when regression tests are triggered, allowing the workflow to run only when changes are made to the core, producer, or engine packages rather than any package in the repository.
## How
Modified the path filters in the regression workflow to explicitly list the three critical package directories (`packages/core/**`, `packages/producer/**`, `packages/engine/**`) instead of using the broad `packages/**` pattern.
## Test plan
How was this tested?
- [ ] Unit tests added/updated
- [ ] Manual testing performed
- [ ] Documentation updated (if applicable)
The blank template was a bare `<div>` fragment without `<!DOCTYPE>`,
`<head>`, or `<body>`. This caused:
- Blank preview (bundler/runtime can't initialize from a fragment)
- "Failed to run lint" (parsing errors on the malformed document)
All other templates (swiss-grid, vignelli, warm-grain, play-mode) are
proper HTML documents — blank was the only outlier.
Also improves lint error reporting to show the actual error message
instead of the generic "Failed to run lint."
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The SIGINT handlers that were meant to do graceful cleanup (close server,
remove symlinks) override Node's default exit behavior. If the cleanup
hangs (e.g. server.close() blocked by open connections), the process is
stuck and Ctrl+C does nothing.
Fix: don't intercept SIGINT at all. Node's default behavior exits the
process immediately on Ctrl+C. The OS reclaims the port and file handles.
Use process.on("exit") for best-effort symlink cleanup instead.
Also fixes running the CLI via `tsx` in dev mode — __CLI_VERSION__ is a
tsup build-time define that crashes at runtime without a fallback.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- Fix silent failure when `hyperframes dev` port (default 3002) is already in use (e.g., by Cursor IDE)
- Replace TOCTOU-prone `isPortAvailable()` probe with `serveWithPortFallback()` that binds the real server directly
- Auto-increment to next available port with a visible yellow warning, or show a clear error when all ports (range of 10) are exhausted
## What changed
The old approach used a throwaway `net.createServer()` to test port availability, closed it, then opened the real Hono server — a classic TOCTOU race. The fallback also silently returned the original port when all 10 were taken.
Now we use `createAdaptorServer()` (creates the Hono HTTP server without binding) and manually call `.listen(port)`, catching `EADDRINUSE` to try the next port. This eliminates the race entirely.
**Before:** `hyperframes dev` says "Studio running at http://localhost:3002" even when port 3002 belongs to another process.
**After:**
- Port available: works as before
- Port taken: `Port 3002 is in use, using 3003 instead` (yellow warning)
- All ports taken: `Ports 3002–3011 are all in use. Use --port to specify a different port.` (error + exit)
## Testing
- Verified TypeScript compiles cleanly (`tsc --noEmit`)
- All pre-commit hooks (lint, format, commitlint) pass
- Manual test: run another server on 3002, then `hyperframes dev` → confirms auto-increment message appears
🤖 Generated with [Claude Code](https://claude.com/claude-code)
The embedded dev server (hyperframes dev) silently reported success even
when the requested port was already in use (e.g., by Cursor IDE on 3002).
This happened because the old isPortAvailable() probe had a TOCTOU race
and findAvailablePort() silently fell back to the original port on exhaustion.
Replace with serveWithPortFallback() that binds the real Hono server
directly via createAdaptorServer + manual listen(), retrying on EADDRINUSE.
Shows a yellow warning when auto-incrementing and a clear error when all
ports are exhausted.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Use static import for copyFileSync (was unnecessary dynamic import)
- Shallow-copy config before mutating forceScreenshot (prevents
caller-provided config from being permanently modified)
- Consolidate isWebm/isWebmRender/outputFormat into single early
declaration in renderOrchestrator
- Fix debug output extension for WebM (was hardcoded .mp4)
- Log unexpected audio extraction errors instead of silently swallowing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Changes
- Add optional `entryFile` parameter to render API endpoints (`/v1/render` and `/v1/render-stream`)
- Enable rendering individual sub-compositions by extracting them from index.html context when the entry file is a `<template>` wrapper
- Change base64 audio/video linting from detecting "fabricated" media to prohibiting all inline base64 media
- Add manifest path resolution for bundled producer deployments
## API Changes
- `RenderConfig` — new optional `entryFile` field for specifying HTML file to render
- `server.ts` — parses `entryFile` from request body, validates file exists in project directory
- `executeRenderJob` — uses `entryFile` instead of hardcoded `"index.html"`
## Template Extraction
- `extractStandaloneEntryFromIndex` — extracts sub-composition hosts from index.html and creates standalone render context
- Handles `<template>` entry files by finding matching `data-composition-src` in index.html and isolating that host
- Resets `data-start` to 0 for standalone rendering
## Linting Updates
- Change rule #3.7 from detecting "fabricated" base64 media to prohibiting all inline base64 audio/video
- Lower detection threshold from 100+ to 20+ base64 characters
- All base64 media now triggers error severity with clearer messaging about file size bloat
## Usage
```json
POST /v1/render-stream
{ "projectDir": "/path/to/project", "entryFile": "compositions/intro.html" }
```
Omit `entryFile` for default behavior (renders `index.html`).
- Engine: document getEncoderPreset() for MP4/WebM, VP9 alpha flags,
Opus audio in mux step
- Producer: document format field in RenderConfig, WebM usage example,
pipeline steps updated for WebM
- CLI: add render command examples in --help (including WebM overlay)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>