+````
+`````
+
+`````
The filename after the language tag tells readers where the code goes.
@@ -97,32 +99,27 @@ npx hyperframes dev
### Use CodeGroup for multi-platform commands
-```mdx
+````mdx
-```bash macOS
-brew install ffmpeg
-```
-```bash Ubuntu
-sudo apt install ffmpeg
-```
+ ```bash macOS brew install ffmpeg ``` ```bash Ubuntu sudo apt install ffmpeg ```
-```
+`````
## Mintlify Components — When to Use
-| Component | Use When |
-|-----------|----------|
-| `` | Sequential setup or tutorial instructions |
-| `` | Same action across platforms/languages |
-| `` | Alternative approaches with equal weight |
-| `` / `` | Navigation to related pages, next steps |
-| `` | FAQ or optional detail that would bloat the page |
-| `` | Non-obvious behavior the reader should know |
-| `` | Something that will break if ignored |
-| `` | Helpful shortcut or best practice |
-| `` | Context that aids understanding |
-| `` | File/directory structure |
-| `` | Screenshots or diagrams with captions |
+| Component | Use When |
+| ---------------------- | ------------------------------------------------ |
+| `` | Sequential setup or tutorial instructions |
+| `` | Same action across platforms/languages |
+| `` | Alternative approaches with equal weight |
+| `` / `` | Navigation to related pages, next steps |
+| `` | FAQ or optional detail that would bloat the page |
+| `` | Non-obvious behavior the reader should know |
+| `` | Something that will break if ignored |
+| `` | Helpful shortcut or best practice |
+| `` | Context that aids understanding |
+| `` | File/directory structure |
+| `` | Screenshots or diagrams with captions |
### Callout budget: max 2-3 per page
diff --git a/bun.lock b/bun.lock
index ad88feeff..dbbcfed9f 100644
--- a/bun.lock
+++ b/bun.lock
@@ -8,6 +8,7 @@
"@commitlint/cli": "^20.5.0",
"@commitlint/config-conventional": "^20.5.0",
"@types/node": "^25.0.10",
+ "@typescript/native-preview": "^7.0.0-dev.20260323.1",
"concurrently": "^8.2.0",
"knip": "^6.0.3",
"lefthook": "^2.1.4",
@@ -665,6 +666,22 @@
"@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "22.19.15" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="],
+ "@typescript/native-preview": ["@typescript/native-preview@7.0.0-dev.20260323.1", "", { "optionalDependencies": { "@typescript/native-preview-darwin-arm64": "7.0.0-dev.20260323.1", "@typescript/native-preview-darwin-x64": "7.0.0-dev.20260323.1", "@typescript/native-preview-linux-arm": "7.0.0-dev.20260323.1", "@typescript/native-preview-linux-arm64": "7.0.0-dev.20260323.1", "@typescript/native-preview-linux-x64": "7.0.0-dev.20260323.1", "@typescript/native-preview-win32-arm64": "7.0.0-dev.20260323.1", "@typescript/native-preview-win32-x64": "7.0.0-dev.20260323.1" }, "bin": { "tsgo": "bin/tsgo.js" } }, "sha512-e8rnqL5I4DUSjiy6jiWqYFKcgKq8tC4S+uEmJwWiyTgSIGDhaRUujJ2pb6EXmi+NPeXoES6vIG7e9BsEV0WSow=="],
+
+ "@typescript/native-preview-darwin-arm64": ["@typescript/native-preview-darwin-arm64@7.0.0-dev.20260323.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-C3tQdgMaYn57xzRUWek+zNKMiP0z9j7fqbCjr0wlyiLNIh5jMwDArjBDKHlqSu58FKvZg7baqbqB5Mcepb3s6w=="],
+
+ "@typescript/native-preview-darwin-x64": ["@typescript/native-preview-darwin-x64@7.0.0-dev.20260323.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-YE6pD4wdMqNgaBkXicQBLFwABOEmLxDclSM7grl0fw4cQSbfVwFCbSlwFDkmISKdmsgtWdYeMohrsTU710ufpg=="],
+
+ "@typescript/native-preview-linux-arm": ["@typescript/native-preview-linux-arm@7.0.0-dev.20260323.1", "", { "os": "linux", "cpu": "arm" }, "sha512-6zFO/SF9Gu8rtRyEt1b10TNapQGq5b/wUjCLG14675n155r4EO3JFMgnltBViV2Eatnq7G+bXD65BUBk7Ixyhw=="],
+
+ "@typescript/native-preview-linux-arm64": ["@typescript/native-preview-linux-arm64@7.0.0-dev.20260323.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Jzr2gBY0ifA3XejAl7kPeHLT72JFBfzLSafOAQbANh5Iag02uPl99k8ORMfKREbYgEMMOzqPpe+r6eaKy+VEfw=="],
+
+ "@typescript/native-preview-linux-x64": ["@typescript/native-preview-linux-x64@7.0.0-dev.20260323.1", "", { "os": "linux", "cpu": "x64" }, "sha512-UvsQdVI/LayXTowltMgtg2GHU/a/lcuOYbaAYm9+/nvgIs01VqVo0s1/lTSNBzepEk0y1EOYQ6SIsRM9lLGHxA=="],
+
+ "@typescript/native-preview-win32-arm64": ["@typescript/native-preview-win32-arm64@7.0.0-dev.20260323.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-3208Xoe+3Xblf6WLVTkIdyh6401zB2eXAhu1UaDpZY0rf8SMHCxKW3TSJDytpri5UivCotZ0CNC2wgJ1TlymUA=="],
+
+ "@typescript/native-preview-win32-x64": ["@typescript/native-preview-win32-x64@7.0.0-dev.20260323.1", "", { "os": "win32", "cpu": "x64" }, "sha512-DAiRqrcs58eXwjFOtbklbIHq70IpW7uYz1Bx3kNAzqoWlA7R4mC29N6G0kGEZDalGmj7f0HVuckq9AzaC1r6oQ=="],
+
"@vitejs/plugin-react": ["@vitejs/plugin-react@4.7.0", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/plugin-transform-react-jsx-self": "7.27.1", "@babel/plugin-transform-react-jsx-source": "7.27.1", "@rolldown/pluginutils": "1.0.0-beta.27", "@types/babel__core": "7.20.5", "react-refresh": "0.17.0" }, "peerDependencies": { "vite": "5.4.21" } }, "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA=="],
"@vitest/coverage-v8": ["@vitest/coverage-v8@3.2.4", "", { "dependencies": { "@ampproject/remapping": "2.3.0", "@bcoe/v8-coverage": "1.0.2", "ast-v8-to-istanbul": "0.3.12", "debug": "4.4.3", "istanbul-lib-coverage": "3.2.2", "istanbul-lib-report": "3.0.1", "istanbul-lib-source-maps": "5.0.6", "istanbul-reports": "3.2.0", "magic-string": "0.30.21", "magicast": "0.3.5", "std-env": "3.10.0", "test-exclude": "7.0.2", "tinyrainbow": "2.0.0" }, "peerDependencies": { "vitest": "3.2.4" } }, "sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ=="],
diff --git a/docs/concepts/compositions.mdx b/docs/concepts/compositions.mdx
index ea9872163..1304714e9 100644
--- a/docs/concepts/compositions.mdx
+++ b/docs/concepts/compositions.mdx
@@ -10,8 +10,7 @@ A composition is an HTML document that defines a video timeline. Every clip -- v
Every composition needs a root element with `data-composition-id`:
```html index.html
-
+
```
@@ -68,6 +67,7 @@ You can embed one composition inside another in two ways: loading from an extern
```
+
Define a nested composition directly inside the parent. This is simpler for one-off compositions that do not need to be reused.
@@ -93,6 +93,7 @@ You can embed one composition inside another in two ways: loading from an extern
```
Inline compositions do not use `` tags or `data-composition-src`.
+
@@ -122,7 +123,9 @@ Every composition has two layers:
- **Script** -- effects, transitions, dynamic DOM, canvas, SVG -- creative animation via [GSAP](/guides/gsap-animation). Scripts do **not** control media playback or clip visibility.
- Never use scripts to play/pause/seek media elements or to show/hide clips based on timing. The framework handles this automatically from data attributes. Scripts that duplicate this behavior will conflict with the framework. See [Common Mistakes](/guides/common-mistakes) for examples.
+ Never use scripts to play/pause/seek media elements or to show/hide clips based on timing. The
+ framework handles this automatically from data attributes. Scripts that duplicate this behavior
+ will conflict with the framework. See [Common Mistakes](/guides/common-mistakes) for examples.
## Variables
@@ -130,7 +133,7 @@ Every composition has two layers:
Compositions can expose variables for dynamic content:
```html compositions/card.html
-
+
```
Variables make compositions reusable as [templates](/guides/templates) -- the same composition can render different content by injecting variable values at render time.
diff --git a/docs/concepts/data-attributes.mdx b/docs/concepts/data-attributes.mdx
index 0b7b66e3c..4d86633f0 100644
--- a/docs/concepts/data-attributes.mdx
+++ b/docs/concepts/data-attributes.mdx
@@ -7,38 +7,35 @@ Hyperframes uses HTML data attributes to control timing, media playback, and [co
## Timing Attributes
-| Attribute | Example | Description |
-|-----------|---------|-------------|
-| `data-start` | `"0"` or `"intro"` | Start time in seconds, or a clip ID reference for [relative timing](#relative-timing) |
-| `data-duration` | `"5"` | Duration in seconds. Required for images. Optional for video/audio (defaults to source duration). Not used on compositions. |
-| `data-track-index` | `"0"` | Timeline track number. Controls z-ordering (higher = in front) and groups clips into rows. Clips on the same track cannot overlap. |
+| Attribute | Example | Description |
+| ------------------ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
+| `data-start` | `"0"` or `"intro"` | Start time in seconds, or a clip ID reference for [relative timing](#relative-timing) |
+| `data-duration` | `"5"` | Duration in seconds. Required for images. Optional for video/audio (defaults to source duration). Not used on compositions. |
+| `data-track-index` | `"0"` | Timeline track number. Controls z-ordering (higher = in front) and groups clips into rows. Clips on the same track cannot overlap. |
## Media Attributes
-| Attribute | Example | Description |
-|-----------|---------|-------------|
-| `data-media-start` | `"2"` | Media playback offset / trim point in seconds. Default: `0` |
-| `data-volume` | `"0.8"` | Audio/video volume, 0 to 1 |
-| `data-has-audio` | `"true"` | Indicates video has an audio track |
+| Attribute | Example | Description |
+| ------------------ | -------- | ----------------------------------------------------------- |
+| `data-media-start` | `"2"` | Media playback offset / trim point in seconds. Default: `0` |
+| `data-volume` | `"0.8"` | Audio/video volume, 0 to 1 |
+| `data-has-audio` | `"true"` | Indicates video has an audio track |
## Composition Attributes
-| Attribute | Example | Description |
-|-----------|---------|-------------|
-| `data-composition-id` | `"root"` | Unique ID for [composition](/concepts/compositions) wrapper (required on every composition) |
-| `data-width` | `"1920"` | Composition width in pixels |
-| `data-height` | `"1080"` | Composition height in pixels |
-| `data-composition-src` | `"./intro.html"` | Path to external [composition](/concepts/compositions) HTML file |
+| Attribute | Example | Description |
+| ---------------------- | ---------------- | ------------------------------------------------------------------------------------------- |
+| `data-composition-id` | `"root"` | Unique ID for [composition](/concepts/compositions) wrapper (required on every composition) |
+| `data-width` | `"1920"` | Composition width in pixels |
+| `data-height` | `"1080"` | Composition height in pixels |
+| `data-composition-src` | `"./intro.html"` | Path to external [composition](/concepts/compositions) HTML file |
## Element Visibility
Add `class="clip"` to all timed elements so the runtime can manage their visibility lifecycle:
```html index.html
-
- Hello World
-
+
Hello World
```
## Relative Timing
@@ -59,12 +56,22 @@ Add `+ N` or `- N` after the ID to offset from the end of the referenced clip:
```html index.html
-
+
-
+
```
@@ -74,16 +81,18 @@ Add `+ N` or `- N` after the ID to offset from the end of the referenced clip:
**Same composition only** -- references resolve within the clip's parent [composition](/concepts/compositions). You cannot reference a clip in a sibling or parent composition.
- **No circular references** -- A cannot start after B if B starts after A. The resolver detects cycles and throws an error.
+**No circular references** -- A cannot start after B if B starts after A. The resolver detects cycles and throws an error.
- **Referenced clip must have a known duration** -- either an explicit `data-duration` or a duration inferred from source media. If the referenced clip has no known duration, the reference cannot resolve.
+**Referenced clip must have a known duration** -- either an explicit `data-duration` or a duration inferred from source media. If the referenced clip has no known duration, the reference cannot resolve.
- **Parsing rules** -- if the value is a valid number, it is treated as absolute seconds. Otherwise it is parsed as one of:
- - `` -- start when that clip ends
- - ` + ` -- start N seconds after that clip ends
- - ` - ` -- start N seconds before that clip ends
+**Parsing rules** -- if the value is a valid number, it is treated as absolute seconds. Otherwise it is parsed as one of:
+
+- `` -- start when that clip ends
+- ` + ` -- start N seconds after that clip ends
+- ` - ` -- start N seconds before that clip ends
+
+**Chain length** -- references can chain (`A` -> `B` -> `C`), but deeply nested chains make the timeline harder to reason about. Keep chains under 3-4 levels for readability.
- **Chain length** -- references can chain (`A` -> `B` -> `C`), but deeply nested chains make the timeline harder to reason about. Keep chains under 3-4 levels for readability.
## Next Steps
diff --git a/docs/concepts/determinism.mdx b/docs/concepts/determinism.mdx
index 11788c6a2..7c66734dc 100644
--- a/docs/concepts/determinism.mdx
+++ b/docs/concepts/determinism.mdx
@@ -56,6 +56,7 @@ npx hyperframes render --docker -o output.mp4
```
Docker mode uses an exact Chrome version and font set, ensuring:
+
- Same Chromium rendering engine across all platforms
- Same system fonts (no platform-specific font substitution)
- Same FFmpeg encoder version
@@ -71,7 +72,8 @@ The browser preview and the rendered MP4 should match. Hyperframes achieves this
- **Readiness gates** -- `__playerReady` and `__renderReady` ensure the [composition](/concepts/compositions) is fully loaded before any frame is captured
- Local rendering (without Docker) may show slight differences due to platform-specific font rendering and Chrome version. Use Docker mode when exact reproducibility matters.
+ Local rendering (without Docker) may show slight differences due to platform-specific font
+ rendering and Chrome version. Use Docker mode when exact reproducibility matters.
## For Adapter Authors
diff --git a/docs/concepts/frame-adapters.mdx b/docs/concepts/frame-adapters.mdx
index 3a1d9c3c1..b1e561567 100644
--- a/docs/concepts/frame-adapters.mdx
+++ b/docs/concepts/frame-adapters.mdx
@@ -10,7 +10,8 @@ The Frame Adapter pattern is how Hyperframes supports multiple animation runtime
If a runtime can answer that, it can plug into Hyperframes.
- The Adapter API is currently at **v0** (experimental). Breaking changes are possible until v1. The core contract (seek-by-frame, deterministic output) is stable, but method signatures may evolve.
+ The Adapter API is currently at **v0** (experimental). Breaking changes are possible until v1. The
+ core contract (seek-by-frame, deterministic output) is stable, but method signatures may evolve.
## How It Works
@@ -106,13 +107,13 @@ These rules are non-negotiable for any adapter. They are the foundation of Hyper
First-party adapters:
-| Runtime | Seek Method | Status |
-|---------|------------|--------|
-| [GSAP](/guides/gsap-animation) | `timeline.seek(frame / fps)` | Available |
-| CSS/WAAPI | `animation.currentTime` | Planned |
-| Lottie | Set animation frame/progress | Planned |
-| Three.js/WebGL | Compute deterministic scene state | Planned |
-| SVG/Anime | Implement seek + duration contract | Planned |
+| Runtime | Seek Method | Status |
+| ------------------------------ | ---------------------------------- | --------- |
+| [GSAP](/guides/gsap-animation) | `timeline.seek(frame / fps)` | Available |
+| CSS/WAAPI | `animation.currentTime` | Planned |
+| Lottie | Set animation frame/progress | Planned |
+| Three.js/WebGL | Compute deterministic scene state | Planned |
+| SVG/Anime | Implement seek + duration contract | Planned |
Community adapters are welcome -- if it can seek by frame, it belongs in Hyperframes.
diff --git a/docs/contributing.mdx b/docs/contributing.mdx
index fa8879ce1..95e8d7b69 100644
--- a/docs/contributing.mdx
+++ b/docs/contributing.mdx
@@ -9,36 +9,21 @@ Thanks for your interest in contributing to Hyperframes! This guide covers every
- Fork the repository on GitHub, then clone your fork:
- ```bash
- git clone https://github.com/YOUR_USERNAME/hyperframes.git
- cd hyperframes
- ```
+ Fork the repository on GitHub, then clone your fork: ```bash git clone
+ https://github.com/YOUR_USERNAME/hyperframes.git cd hyperframes ```
- Hyperframes uses [pnpm](https://pnpm.io/) for package management:
- ```bash
- pnpm install
- ```
+ Hyperframes uses [pnpm](https://pnpm.io/) for package management: ```bash pnpm install ```
- Build the monorepo to ensure everything compiles:
- ```bash
- pnpm build
- ```
+ Build the monorepo to ensure everything compiles: ```bash pnpm build ```
- Start the development server to verify your setup:
- ```bash
- pnpm dev
- ```
- If the studio opens at `http://localhost:3000` with a preview, your environment is ready.
+ Start the development server to verify your setup: ```bash pnpm dev ``` If the studio opens at
+ `http://localhost:3000` with a preview, your environment is ready.
- Create a feature branch for your work:
- ```bash
- git checkout -b my-feature
- ```
+ Create a feature branch for your work: ```bash git checkout -b my-feature ```
@@ -56,18 +41,10 @@ pnpm -r typecheck # Type-check all packages
### Running Tests
-```bash Core
-pnpm --filter @hyperframes/core test
-```
-```bash Engine
-pnpm --filter @hyperframes/engine test
-```
-```bash Runtime Contract
-pnpm --filter @hyperframes/core test:hyperframe-runtime-ci
-```
-```bash Producer (Docker)
-cd packages/producer && pnpm docker:build:test && pnpm docker:test
-```
+ ```bash Core pnpm --filter @hyperframes/core test ``` ```bash Engine pnpm --filter
+ @hyperframes/engine test ``` ```bash Runtime Contract pnpm --filter @hyperframes/core
+ test:hyperframe-runtime-ci ``` ```bash Producer (Docker) cd packages/producer && pnpm
+ docker:build:test && pnpm docker:test ```
### Running All Tests
@@ -78,13 +55,13 @@ pnpm -r test
## Packages
-| Package | Path | Description |
-|---------|------|-------------|
-| [`@hyperframes/core`](/packages/core) | `packages/core` | Types, HTML generation, runtime, linter |
-| [`@hyperframes/engine`](/packages/engine) | `packages/engine` | Seekable page-to-video capture engine |
-| [`@hyperframes/producer`](/packages/producer) | `packages/producer` | Full rendering pipeline (capture + encode) |
-| [`@hyperframes/studio`](/packages/studio) | `packages/studio` | Composition editor UI |
-| [`hyperframes`](/packages/cli) | `packages/cli` | CLI for creating, previewing, and rendering |
+| Package | Path | Description |
+| --------------------------------------------- | ------------------- | ------------------------------------------- |
+| [`@hyperframes/core`](/packages/core) | `packages/core` | Types, HTML generation, runtime, linter |
+| [`@hyperframes/engine`](/packages/engine) | `packages/engine` | Seekable page-to-video capture engine |
+| [`@hyperframes/producer`](/packages/producer) | `packages/producer` | Full rendering pipeline (capture + encode) |
+| [`@hyperframes/studio`](/packages/studio) | `packages/studio` | Composition editor UI |
+| [`hyperframes`](/packages/cli) | `packages/cli` | CLI for creating, previewing, and rendering |
## What to Work On
@@ -142,7 +119,11 @@ All of the following must pass before your PR can be merged:
Report bugs, request features, and discuss ideas.
-
+
Our community standards and expectations.
diff --git a/docs/guides/common-mistakes.mdx b/docs/guides/common-mistakes.mdx
index c1d8ae0cd..ca51aaa96 100644
--- a/docs/guides/common-mistakes.mdx
+++ b/docs/guides/common-mistakes.mdx
@@ -6,7 +6,9 @@ description: "Pitfalls that break Hyperframes compositions."
These are mistakes that cannot be caught by the linter. For automated checks, run `npx hyperframes lint` (see [CLI](/packages/cli#lint)).
- The first two mistakes — animating video element dimensions and controlling media playback in scripts — are the most common causes of broken compositions. If your video looks wrong, check these first.
+ The first two mistakes — animating video element dimensions and controlling media playback in
+ scripts — are the most common causes of broken compositions. If your video looks wrong, check
+ these first.
@@ -38,6 +40,7 @@ These are mistakes that cannot be caught by the linter. For automated checks, ru
```
Use a non-timed wrapper `
` for visual effects like picture-in-picture. Animate the wrapper; let the video fill it via CSS.
+
@@ -62,6 +65,7 @@ These are mistakes that cannot be caught by the linter. For automated checks, ru
```
The framework reads [`data-start`](/concepts/data-attributes#timing-attributes), [`data-media-start`](/concepts/data-attributes#media-attributes), and [`data-volume`](/concepts/data-attributes#media-attributes) to control when and how media plays. See [Compositions: Two Layers](/concepts/compositions#two-layers-primitives-and-scripts) for the separation between HTML primitives and scripts.
+
@@ -90,6 +94,7 @@ These are mistakes that cannot be caught by the linter. For automated checks, ru
A quick check: run `npx hyperframes compositions` to see the resolved duration of each composition. If it is shorter than expected, your timeline needs extending.
+
@@ -118,6 +123,7 @@ These are mistakes that cannot be caught by the linter. For automated checks, ru
The linter catches this one: `npx hyperframes lint` will flag timed elements missing `class="clip"`.
+
@@ -140,6 +146,7 @@ These are mistakes that cannot be caught by the linter. For automated checks, ru
//
window.__timelines["my-video"] = tl;
```
+
diff --git a/docs/guides/gsap-animation.mdx b/docs/guides/gsap-animation.mdx
index 26d78c6a5..4d66f372a 100644
--- a/docs/guides/gsap-animation.mdx
+++ b/docs/guides/gsap-animation.mdx
@@ -27,7 +27,9 @@ Include GSAP and create a paused timeline:
```
- The key you use in `window.__timelines` must match the `data-composition-id` attribute on your composition's root element. See [Compositions](/concepts/compositions) for how the root element is structured.
+ The key you use in `window.__timelines` must match the `data-composition-id` attribute on your
+ composition's root element. See [Compositions](/concepts/compositions) for how the root element is
+ structured.
## Key Rules
@@ -39,12 +41,12 @@ Include GSAP and create a paused timeline:
## Supported Methods
-| Method | Description |
-|--------|-------------|
-| `tl.to(target, vars, position)` | Animate to values |
-| `tl.from(target, vars, position)` | Animate from values |
+| Method | Description |
+| ----------------------------------------------- | ---------------------- |
+| `tl.to(target, vars, position)` | Animate to values |
+| `tl.from(target, vars, position)` | Animate from values |
| `tl.fromTo(target, fromVars, toVars, position)` | Animate from/to values |
-| `tl.set(target, vars, position)` | Set values instantly |
+| `tl.set(target, vars, position)` | Set values instantly |
## Supported Properties
@@ -73,7 +75,9 @@ tl.set({}, {}, 283);
```
- This is one of the most common mistakes in Hyperframes. If your video cuts off early, the timeline is too short. See [Common Mistakes: Composition Duration Shorter Than Video](/guides/common-mistakes) for more details.
+ This is one of the most common mistakes in Hyperframes. If your video cuts off early, the timeline
+ is too short. See [Common Mistakes: Composition Duration Shorter Than
+ Video](/guides/common-mistakes) for more details.
## What NOT to Do
diff --git a/docs/guides/rendering.mdx b/docs/guides/rendering.mdx
index 18a3ce22c..304e73ef9 100644
--- a/docs/guides/rendering.mdx
+++ b/docs/guides/rendering.mdx
@@ -23,6 +23,7 @@ Render your Hyperframes [compositions](/concepts/compositions) to MP4 with the [
✓ Docker available
✓ Disk space OK
```
+
Before rendering, preview your composition in the browser to verify it looks correct:
@@ -30,6 +31,7 @@ Render your Hyperframes [compositions](/concepts/compositions) to MP4 with the [
```bash Terminal
npx hyperframes dev
```
+
Run the render command from your project directory:
@@ -45,6 +47,7 @@ Render your Hyperframes [compositions](/concepts/compositions) to MP4 with the [
✓ Captured 240 frames in 8.2s
✓ Encoded to output.mp4 (8.0s, 1920x1080, 4.2MB)
```
+
@@ -70,6 +73,7 @@ Render your Hyperframes [compositions](/concepts/compositions) to MP4 with the [
**Cons:**
- Output may vary across platforms due to font and Chrome version differences
- Not suitable for CI/CD pipelines that require reproducibility
+
### Docker Mode
@@ -94,35 +98,37 @@ Render your Hyperframes [compositions](/concepts/compositions) to MP4 with the [
Docker mode uses `chrome-headless-shell` with [BeginFrame](/concepts/determinism#how-it-works) control for frame-perfect, deterministic capture.
+
## When to Use Each Mode
-| Scenario | Recommended Mode |
-|----------|-----------------|
-| Local development and iteration | Local |
-| CI/CD pipeline | Docker |
-| Sharing renders with a team | Docker |
-| Quick preview export | Local |
-| AI agent-driven rendering | Docker |
-| Benchmarking performance | Local |
+| Scenario | Recommended Mode |
+| ------------------------------- | ---------------- |
+| Local development and iteration | Local |
+| CI/CD pipeline | Docker |
+| Sharing renders with a team | Docker |
+| Quick preview export | Local |
+| AI agent-driven rendering | Docker |
+| Benchmarking performance | Local |
## Options
-| Flag | Values | Default | Description |
-|------|--------|---------|-------------|
-| `-f, --fps` | 24, 30, 60 | 30 | Frames per second |
-| `-q, --quality` | draft, standard, high | standard | Encoding quality preset |
-| `-w, --workers` | 1-8 | auto | Parallel render workers |
-| `--gpu` | — | off | GPU encoding (NVENC, VideoToolbox, VAAPI) |
-| `-o, --output` | path | — | Output file path |
-| `--docker` | — | off | Use Docker for [deterministic rendering](/concepts/determinism) |
+| Flag | Values | Default | Description |
+| --------------- | --------------------- | -------- | --------------------------------------------------------------- |
+| `-f, --fps` | 24, 30, 60 | 30 | Frames per second |
+| `-q, --quality` | draft, standard, high | standard | Encoding quality preset |
+| `-w, --workers` | 1-8 | auto | Parallel render workers |
+| `--gpu` | — | off | GPU encoding (NVENC, VideoToolbox, VAAPI) |
+| `-o, --output` | path | — | Output file path |
+| `--docker` | — | off | Use Docker for [deterministic rendering](/concepts/determinism) |
## Tips
- Use `draft` quality during development for fast previews. Switch to `standard` or `high` for final output.
+ Use `draft` quality during development for fast previews. Switch to `standard` or `high` for final
+ output.
- Use `npx hyperframes benchmark` to find optimal settings for your system
diff --git a/docs/guides/templates.mdx b/docs/guides/templates.mdx
index 7f24e5a38..f0702c990 100644
--- a/docs/guides/templates.mdx
+++ b/docs/guides/templates.mdx
@@ -35,6 +35,7 @@ This creates a new project directory with an `index.html` composition and any re
├── index.html # Empty root composition with GSAP setup
└── assets/ # Empty directory for your media files
```
+
### title-card
@@ -55,6 +56,7 @@ This creates a new project directory with an `index.html` composition and any re
├── index.html # Title + subtitle with fade animations
└── assets/ # Empty directory for your media files
```
+
### video-edit
@@ -75,19 +77,22 @@ This creates a new project directory with an `index.html` composition and any re
├── index.html # Video + audio + overlay composition
└── assets/ # Place your video and audio files here
```
+
## Choosing a Template
-| Template | Best for | Complexity |
-|----------|----------|------------|
-| `blank` | Full control, agent-generated compositions | Minimal |
-| `title-card` | Text intros, outros, chapter markers | Simple |
-| `video-edit` | Video cutting, overlays, multi-track editing | Moderate |
+| Template | Best for | Complexity |
+| ------------ | -------------------------------------------- | ---------- |
+| `blank` | Full control, agent-generated compositions | Minimal |
+| `title-card` | Text intros, outros, chapter markers | Simple |
+| `video-edit` | Video cutting, overlays, multi-track editing | Moderate |
- If you are new to Hyperframes, start with `title-card` to see a working animation, then move to `blank` when you are comfortable with the [composition model](/concepts/compositions) and [GSAP animation](/guides/gsap-animation).
+ If you are new to Hyperframes, start with `title-card` to see a working animation, then move to
+ `blank` when you are comfortable with the [composition model](/concepts/compositions) and [GSAP
+ animation](/guides/gsap-animation).
## Custom Templates
@@ -101,9 +106,13 @@ Your custom template needs:
3. Any assets in the same directory or a subdirectory
```html index.html
-
-
+
diff --git a/docs/guides/troubleshooting.mdx b/docs/guides/troubleshooting.mdx
index 5458cef33..fa75d9b2f 100644
--- a/docs/guides/troubleshooting.mdx
+++ b/docs/guides/troubleshooting.mdx
@@ -17,6 +17,7 @@ If your issue is about a specific coding mistake (animations not working, video
```
+
@@ -46,6 +47,7 @@ If your issue is about a specific coding mistake (animations not working, video
If you cannot install FFmpeg, use [Docker mode](/guides/rendering) instead — it bundles FFmpeg inside the container: `npx hyperframes render --docker -o output.mp4`
+
@@ -58,6 +60,7 @@ If your issue is about a specific coding mistake (animations not working, video
| Overlapping timelines | Clips on the same [`data-track-index`](/concepts/data-attributes#timing-attributes) cannot overlap in time. |
| Unmuted video elements | Video elements should be `muted` unless `data-has-audio="true"` is set. |
| Deprecated attribute names | `data-layer` and `data-end` have been replaced. Check the [HTML Schema Reference](/reference/html-schema). |
+
@@ -69,6 +72,7 @@ If your issue is about a specific coding mistake (animations not working, video
2. Stop and restart `npx hyperframes dev`
3. Hard-refresh the browser: **Ctrl+Shift+R** (Windows/Linux) or **Cmd+Shift+R** (macOS)
4. Clear the browser cache if CSS changes are not reflected
+
@@ -83,6 +87,7 @@ If your issue is about a specific coding mistake (animations not working, video
```
See [Rendering: When to Use Each Mode](/guides/rendering#when-to-use-each-mode) for guidance on choosing between local and Docker rendering.
+
@@ -96,6 +101,7 @@ If your issue is about a specific coding mistake (animations not working, video
- **Docker not running:** Start Docker Desktop or the Docker daemon
- **Permission denied:** Add your user to the `docker` group (`sudo usermod -aG docker $USER`) and restart your shell
- **Image pull fails:** Check your internet connection; the first render downloads the Hyperframes Docker image
+
@@ -108,6 +114,7 @@ If your issue is about a specific coding mistake (animations not working, video
5. Check that your composition does not have unnecessary elements or overly complex animations
See [Rendering: Options](/guides/rendering#options) for all available flags.
+
diff --git a/docs/introduction.mdx b/docs/introduction.mdx
index aac295f03..7db967bb9 100644
--- a/docs/introduction.mdx
+++ b/docs/introduction.mdx
@@ -10,20 +10,36 @@ Hyperframes is an open-source framework that turns HTML into deterministic, fram
Here is a video defined entirely as HTML:
```html
-
-
-
-
-
+
+
+
+
Welcome to Hyperframes
-
+
```
@@ -33,31 +49,47 @@ Run `npx hyperframes render -o demo.mp4` and this produces an MP4 with determini
- **You already know the stack.** Compositions are HTML files with data attributes. Animations use GSAP, Lottie, CSS, or any runtime that can seek to a given frame. There is no custom DSL, no proprietary component system, and no React requirement. If you can build a web page, you can build a video.
+ **You already know the stack.** Compositions are HTML files with data attributes. Animations use
+ GSAP, Lottie, CSS, or any runtime that can seek to a given frame. There is no custom DSL, no
+ proprietary component system, and no React requirement. If you can build a web page, you can
+ build a video.
- **Agents already speak HTML.** Most video tools require complex APIs or drag-and-drop interfaces that agents cannot operate. Hyperframes compositions are plain HTML documents — the format LLMs are best at generating. An agent can compose, modify, and render videos using tools it already understands.
+ **Agents already speak HTML.** Most video tools require complex APIs or drag-and-drop interfaces
+ that agents cannot operate. Hyperframes compositions are plain HTML documents — the format LLMs
+ are best at generating. An agent can compose, modify, and render videos using tools it already
+ understands.
- **Determinism by design.** The rendering pipeline is seek-driven with no wall-clock dependencies. `frame = floor(time * fps)` — every frame is independently captured via Chrome's `beginFrame` API and encoded with FFmpeg. Same input always produces identical output, making CI testing and batch rendering reliable.
+ **Determinism by design.** The rendering pipeline is seek-driven with no wall-clock
+ dependencies. `frame = floor(time * fps)` — every frame is independently captured via Chrome's
+ `beginFrame` API and encoded with FFmpeg. Same input always produces identical output, making CI
+ testing and batch rendering reliable.
- Hyperframes was designed from the ground up for AI agent integration. Because compositions are plain HTML, any LLM can generate, edit, and iterate on video content without specialized tooling. Pair it with function-calling agents to build fully automated video pipelines.
+ Hyperframes was designed from the ground up for AI agent integration. Because compositions are
+ plain HTML, any LLM can generate, edit, and iterate on video content without specialized tooling.
+ Pair it with function-calling agents to build fully automated video pipelines.
## How It Works
- Define your video as an HTML document. Each element gets data attributes for timing (`data-start`, `data-duration`) and layout (`data-track-index`). Add animations with GSAP, Lottie, CSS transitions, or any seekable runtime via the Frame Adapter pattern.
+ Define your video as an HTML document. Each element gets data attributes for timing
+ (`data-start`, `data-duration`) and layout (`data-track-index`). Add animations with GSAP,
+ Lottie, CSS transitions, or any seekable runtime via the Frame Adapter pattern.
- Run `npx hyperframes dev` to open a live preview at `localhost:3000`. Edit your HTML and see changes instantly — no build step, no compilation.
+ Run `npx hyperframes dev` to open a live preview at `localhost:3000`. Edit your HTML and see
+ changes instantly — no build step, no compilation.
- Run `npx hyperframes render -o output.mp4` to produce a final video. The engine seeks each frame in headless Chrome, captures it with `beginFrame`, and pipes the result through FFmpeg. Run locally or in Docker for fully reproducible output.
+ Run `npx hyperframes render -o output.mp4` to produce a final video. The engine seeks each frame
+ in headless Chrome, captures it with `beginFrame`, and pipes the result through FFmpeg. Run
+ locally or in Docker for fully reproducible output.
@@ -68,7 +100,8 @@ Run `npx hyperframes render -o demo.mp4` and this produces an MP4 with determini
Types, HTML parsing, runtime, and composition linter — the foundation everything else builds on.
- Seekable page-to-video capture engine. Loads HTML in headless Chrome and captures frame-by-frame.
+ Seekable page-to-video capture engine. Loads HTML in headless Chrome and captures
+ frame-by-frame.
Full rendering pipeline combining capture and FFmpeg encoding into a single API call.
diff --git a/docs/packages/cli.mdx b/docs/packages/cli.mdx
index 4a2a9c605..fbc569862 100644
--- a/docs/packages/cli.mdx
+++ b/docs/packages/cli.mdx
@@ -14,6 +14,7 @@ npx hyperframes
## When to Use
**Use the CLI when you want to:**
+
- Create a new composition project from a template
- Preview compositions with live hot reload during development
- Render compositions to MP4 (locally or in Docker)
@@ -21,69 +22,40 @@ npx hyperframes
- Check your environment for missing dependencies
**Use a different package if you want to:**
+
- Render programmatically from Node.js code — use the [producer](/packages/producer)
- Build a custom frame capture pipeline — use the [engine](/packages/engine)
- Embed a composition editor in your own web app — use the [studio](/packages/studio)
- Parse or generate composition HTML in code — use [core](/packages/core)
- The CLI is the recommended starting point for all Hyperframes users. It wraps the producer, engine, and studio packages so you do not need to install them separately.
+ The CLI is the recommended starting point for all Hyperframes users. It wraps the producer,
+ engine, and studio packages so you do not need to install them separately.
## Getting Started
- Scaffold a new composition from a template:
- ```bash
- npx hyperframes init --template title-card
- ```
- ```
- Creating composition in ./title-card...
- index.html
- assets/
- package.json
- Done! Run `cd title-card && npx hyperframes dev` to preview.
- ```
- See [Templates](/guides/templates) for all available templates.
+ Scaffold a new composition from a template: ```bash npx hyperframes init --template title-card
+ ``` ``` Creating composition in ./title-card... index.html assets/ package.json Done! Run `cd
+ title-card && npx hyperframes dev` to preview. ``` See [Templates](/guides/templates) for all
+ available templates.
- Start the development server with live hot reload:
- ```bash
- cd title-card
- npx hyperframes dev
- ```
- ```
- Hyperframes Studio v0.1.0
- Local: http://localhost:3000
- Watching for changes...
- ```
- Edit `index.html` and the preview updates instantly.
+ Start the development server with live hot reload: ```bash cd title-card npx hyperframes dev ```
+ ``` Hyperframes Studio v0.1.0 Local: http://localhost:3000 Watching for changes... ``` Edit
+ `index.html` and the preview updates instantly.
- Check for structural issues before rendering:
- ```bash
- npx hyperframes lint
- ```
- ```
- Linting index.html...
- No issues found.
- ```
+ Check for structural issues before rendering: ```bash npx hyperframes lint ``` ``` Linting
+ index.html... No issues found. ```
- Produce the final video:
- ```bash
- npx hyperframes render -o output.mp4
- ```
- ```
- Rendering index.html...
- [========================================] 100% (900/900 frames)
- Output: output.mp4 (30s, 1920x1080, 30fps)
- ```
- For deterministic output, add `--docker`:
- ```bash
- npx hyperframes render --docker -o output.mp4
- ```
+ Produce the final video: ```bash npx hyperframes render -o output.mp4 ``` ``` Rendering
+ index.html... [========================================] 100% (900/900 frames) Output:
+ output.mp4 (30s, 1920x1080, 30fps) ``` For deterministic output, add `--docker`: ```bash npx
+ hyperframes render --docker -o output.mp4 ```
@@ -120,6 +92,7 @@ npx hyperframes
root index.html (30s, 1920x1080)
intro-anim compositions/intro.html (5s, 1920x1080)
```
+
### `dev`
@@ -155,6 +128,7 @@ npx hyperframes
```
The linter detects missing attributes, deprecated names, structural problems, and more. See [Common Mistakes](/guides/common-mistakes) for details on each rule.
+
### `render`
@@ -196,6 +170,7 @@ npx hyperframes
Recommended: quality=standard fps=30 (best speed/quality balance)
```
+
### `doctor`
@@ -245,6 +220,7 @@ npx hyperframes
Upgrading...
Done! Run `npx hyperframes doctor` to verify.
```
+
diff --git a/docs/packages/core.mdx b/docs/packages/core.mdx
index f9c4b4e33..8d1cfb77f 100644
--- a/docs/packages/core.mdx
+++ b/docs/packages/core.mdx
@@ -12,10 +12,13 @@ npm install @hyperframes/core
## When to Use
- **Most users do not need to install `@hyperframes/core` directly.** The [CLI](/packages/cli), [producer](/packages/producer), and [studio](/packages/studio) packages all depend on core internally. You only need it if you are doing one of the things listed below.
+ **Most users do not need to install `@hyperframes/core` directly.** The [CLI](/packages/cli),
+ [producer](/packages/producer), and [studio](/packages/studio) packages all depend on core
+ internally. You only need it if you are doing one of the things listed below.
**Use `@hyperframes/core` when you need to:**
+
- Lint compositions programmatically (CI pipelines, editor plugins)
- Parse HTML compositions into structured TypeScript objects
- Generate composition HTML from data (e.g., from an API or AI agent)
@@ -23,28 +26,29 @@ npm install @hyperframes/core
- Embed the Hyperframes runtime in a custom player
**Use a different package if you want to:**
+
- Preview compositions in the browser — use the [CLI](/packages/cli) (`npx hyperframes dev`) or [studio](/packages/studio)
- Render compositions to MP4 — use the [CLI](/packages/cli) (`npx hyperframes render`) or [producer](/packages/producer)
- Capture frames from a headless browser — use the [engine](/packages/engine)
## What's Inside
-| Module | Description |
-|--------|-------------|
-| `core.types` | TypeScript types for compositions, clips, timelines, and render config |
-| `parsers/` | HTML-to-composition parsing — turns an HTML string into a typed `Composition` object |
-| `generators/` | Composition-to-HTML generation — turns a `Composition` object back into HTML |
-| `runtime/` | The Hyperframes runtime that manages playback, seeking, and clip lifecycle |
-| `lint/` | Composition linter with rules for structural correctness |
-| `adapters/` | Frame Adapter types and the built-in GSAP adapter |
-| `templates/` | HTML composition templates used by `hyperframes init` |
+| Module | Description |
+| ------------- | ------------------------------------------------------------------------------------ |
+| `core.types` | TypeScript types for compositions, clips, timelines, and render config |
+| `parsers/` | HTML-to-composition parsing — turns an HTML string into a typed `Composition` object |
+| `generators/` | Composition-to-HTML generation — turns a `Composition` object back into HTML |
+| `runtime/` | The Hyperframes runtime that manages playback, seeking, and clip lifecycle |
+| `lint/` | Composition linter with rules for structural correctness |
+| `adapters/` | Frame Adapter types and the built-in GSAP adapter |
+| `templates/` | HTML composition templates used by `hyperframes init` |
## Linter
The composition linter checks for structural issues that would cause rendering failures or unexpected behavior. You can run it from the CLI with `npx hyperframes lint`, or call it programmatically:
```typescript
-import { lintHyperframeHtml } from '@hyperframes/core';
+import { lintHyperframeHtml } from "@hyperframes/core";
const html = `
- For a full list of what the linter catches and how to fix each issue, see [Common Mistakes](/guides/common-mistakes) and [Troubleshooting](/guides/troubleshooting).
+ For a full list of what the linter catches and how to fix each issue, see [Common
+ Mistakes](/guides/common-mistakes) and [Troubleshooting](/guides/troubleshooting).
## Types
@@ -76,19 +81,14 @@ Detected issues include:
Import the core types for use in your own tooling or integrations:
```typescript
-import type {
- Composition,
- Clip,
- RenderConfig,
- FrameAdapterContext,
-} from '@hyperframes/core';
+import type { Composition, Clip, RenderConfig, FrameAdapterContext } from "@hyperframes/core";
// Example: define a render configuration
const config: RenderConfig = {
fps: 30,
width: 1920,
height: 1080,
- quality: 'standard',
+ quality: "standard",
};
// Example: work with a parsed composition
@@ -102,13 +102,13 @@ function getClipCount(composition: Composition): number {
Round-trip between HTML and structured data:
```typescript
-import { parseHyperframeHtml, generateHyperframeHtml } from '@hyperframes/core';
+import { parseHyperframeHtml, generateHyperframeHtml } from "@hyperframes/core";
// Parse HTML into a Composition object
const composition = parseHyperframeHtml(htmlString);
-console.log(composition.id); // "root"
-console.log(composition.width); // 1920
-console.log(composition.clips); // [{ id: "clip-1", start: 0, ... }, ...]
+console.log(composition.id); // "root"
+console.log(composition.width); // 1920
+console.log(composition.clips); // [{ id: "clip-1", start: 0, ... }, ...]
// Generate HTML from a Composition object
const html = generateHyperframeHtml(composition);
@@ -130,7 +130,8 @@ pnpm --filter @hyperframes/core build:hyperframes-runtime
```
- You should not need to build the runtime yourself unless you are developing the Hyperframes framework itself. The CLI and producer packages bundle the runtime automatically.
+ You should not need to build the runtime yourself unless you are developing the Hyperframes
+ framework itself. The CLI and producer packages bundle the runtime automatically.
## Frame Adapters
@@ -138,7 +139,7 @@ pnpm --filter @hyperframes/core build:hyperframes-runtime
The core package defines the [Frame Adapter](/concepts/frame-adapters) interface — the abstraction that lets Hyperframes work with any animation runtime. The built-in GSAP adapter lives here:
```typescript
-import type { FrameAdapterContext } from '@hyperframes/core';
+import type { FrameAdapterContext } from "@hyperframes/core";
// Every adapter must answer: "what should the screen look like at this time?"
// See the Frame Adapters concept page for the full API.
diff --git a/docs/packages/engine.mdx b/docs/packages/engine.mdx
index a57d4b592..ce2db045c 100644
--- a/docs/packages/engine.mdx
+++ b/docs/packages/engine.mdx
@@ -12,16 +12,20 @@ npm install @hyperframes/engine
## When to Use
- **Most users should NOT use the engine directly.** Use the [CLI](/packages/cli) (`npx hyperframes render`) or the [producer](/packages/producer) package instead — they handle runtime injection, audio mixing, and encoding for you.
+ **Most users should NOT use the engine directly.** Use the [CLI](/packages/cli) (`npx hyperframes
+ render`) or the [producer](/packages/producer) package instead — they handle runtime injection,
+ audio mixing, and encoding for you.
**Use `@hyperframes/engine` when you need to:**
+
- Build a custom rendering pipeline with full control over frame capture
- Integrate Hyperframes capture into an existing video processing system
- Capture individual frames (e.g., for thumbnails or sprite sheets) without encoding to video
- Implement a custom encoding backend (not FFmpeg)
**Use a different package if you want to:**
+
- Render an HTML composition to a finished MP4 — use the [producer](/packages/producer) or [CLI](/packages/cli)
- Preview compositions in the browser — use the [CLI](/packages/cli) or [studio](/packages/studio)
- Lint or parse composition HTML — use [core](/packages/core)
@@ -32,19 +36,25 @@ The engine implements a **seek-and-capture** loop that is fundamentally differen
- The engine starts `chrome-headless-shell`, a minimal headless Chrome binary optimized for programmatic control via the Chrome DevTools Protocol (CDP).
+ The engine starts `chrome-headless-shell`, a minimal headless Chrome binary optimized for
+ programmatic control via the Chrome DevTools Protocol (CDP).
- Your HTML composition is loaded into a browser page. The Hyperframes runtime is injected to manage timeline seeking.
+ Your HTML composition is loaded into a browser page. The Hyperframes runtime is injected to
+ manage timeline seeking.
- For every frame in the video (e.g., 900 frames for a 30-second video at 30fps), the engine calls `renderSeek(time)` to advance the composition to the exact timestamp. No wall clock is involved — each frame is independently positioned.
+ For every frame in the video (e.g., 900 frames for a 30-second video at 30fps), the engine calls
+ `renderSeek(time)` to advance the composition to the exact timestamp. No wall clock is involved
+ — each frame is independently positioned.
- Chrome's `HeadlessExperimental.beginFrame` API captures the compositor output as a pixel buffer. This produces pixel-perfect frames without any screen recording artifacts.
+ Chrome's `HeadlessExperimental.beginFrame` API captures the compositor output as a pixel buffer.
+ This produces pixel-perfect frames without any screen recording artifacts.
- Captured frame buffers are passed to a consumer — typically FFmpeg (via the producer) for encoding into MP4, but you can provide your own consumer.
+ Captured frame buffers are passed to a consumer — typically FFmpeg (via the producer) for
+ encoding into MP4, but you can provide your own consumer.
@@ -53,36 +63,36 @@ This approach guarantees [deterministic rendering](/concepts/determinism): the s
## Configuration
```typescript
-import type { EngineConfig } from '@hyperframes/engine';
+import type { EngineConfig } from "@hyperframes/engine";
const config: EngineConfig = {
- fps: 30, // Frames per second: 24, 30, or 60
- width: 1920, // Output width in pixels
- height: 1080, // Output height in pixels
- quality: 'standard', // Encoding preset: 'draft', 'standard', or 'high'
+ fps: 30, // Frames per second: 24, 30, or 60
+ width: 1920, // Output width in pixels
+ height: 1080, // Output height in pixels
+ quality: "standard", // Encoding preset: 'draft', 'standard', or 'high'
};
```
### Quality Presets
-| Preset | Use Case | Speed |
-|--------|----------|-------|
-| `draft` | Fast iteration during development | Fastest |
+| Preset | Use Case | Speed |
+| ---------- | -------------------------------------------------- | -------- |
+| `draft` | Fast iteration during development | Fastest |
| `standard` | Production renders with good quality/speed balance | Moderate |
-| `high` | Final delivery, maximum quality | Slowest |
+| `high` | Final delivery, maximum quality | Slowest |
### FPS Options
-| FPS | Use Case |
-|-----|----------|
-| `24` | Cinematic look, smaller file size |
-| `30` | Standard web video, good balance |
+| FPS | Use Case |
+| ---- | ----------------------------------------------- |
+| `24` | Cinematic look, smaller file size |
+| `30` | Standard web video, good balance |
| `60` | Smooth motion, UI animations, screen recordings |
## Programmatic Usage
```typescript
-import { createEngine } from '@hyperframes/engine';
+import { createEngine } from "@hyperframes/engine";
const engine = createEngine({
fps: 30,
@@ -91,7 +101,7 @@ const engine = createEngine({
});
// Capture all frames from a composition
-const frames = await engine.capture('./my-video/index.html');
+const frames = await engine.capture("./my-video/index.html");
// Each frame is a pixel buffer (PNG/raw)
for (const frame of frames) {
@@ -136,7 +146,8 @@ The engine requires `chrome-headless-shell`, which is included when you install
- Wraps the engine with runtime injection, FFmpeg encoding, and audio mixing for complete MP4 output.
+ Wraps the engine with runtime injection, FFmpeg encoding, and audio mixing for complete MP4
+ output.
Provides the types, runtime, and linter that the engine depends on.
diff --git a/docs/packages/producer.mdx b/docs/packages/producer.mdx
index 689aa2e98..b2eef896b 100644
--- a/docs/packages/producer.mdx
+++ b/docs/packages/producer.mdx
@@ -12,19 +12,23 @@ npm install @hyperframes/producer
## When to Use
**Use `@hyperframes/producer` when you need to:**
+
- Render compositions to MP4 programmatically from Node.js (e.g., in a backend service or CI pipeline)
- Build a custom rendering service with fine-grained control over the pipeline
- Run visual regression tests against golden baselines
- Benchmark render performance across different configurations
**Use a different package if you want to:**
+
- Render from the command line without writing code — use the [CLI](/packages/cli) (`npx hyperframes render`)
- Preview compositions in the browser — use the [CLI](/packages/cli) or [studio](/packages/studio)
- Capture frames without encoding — use the [engine](/packages/engine)
- Lint or parse composition HTML — use [core](/packages/core)
- If you are building a web application or script that just needs to render a video, the [CLI](/packages/cli) is the fastest path. The producer package is for when you need programmatic control inside Node.js.
+ If you are building a web application or script that just needs to render a video, the
+ [CLI](/packages/cli) is the fastest path. The producer package is for when you need programmatic
+ control inside Node.js.
## What It Does
@@ -39,47 +43,50 @@ The producer orchestrates the full render pipeline:
Adds the runtime script that manages timeline seeking, clip lifecycle, and media playback.
- Polls for `window.__playerReady` and `window.__renderReady` to ensure all assets (fonts, images, video) are loaded before capture begins.
+ Polls for `window.__playerReady` and `window.__renderReady` to ensure all assets (fonts, images,
+ video) are loaded before capture begins.
- Uses the [engine's](/packages/engine) BeginFrame pipeline to capture each frame as a pixel buffer.
+ Uses the [engine's](/packages/engine) BeginFrame pipeline to capture each frame as a pixel
+ buffer.
Pipes frame buffers into FFmpeg with the selected quality preset and encoding settings.
- Extracts audio from video clips and audio elements, applies `data-volume` and `data-media-start` offsets, and mixes them into the final MP4.
+ Extracts audio from video clips and audio elements, applies `data-volume` and `data-media-start`
+ offsets, and mixes them into the final MP4.
## Programmatic Usage
```typescript
-import { render } from '@hyperframes/producer';
+import { render } from "@hyperframes/producer";
const result = await render({
- input: './my-video/index.html',
- output: './output.mp4',
+ input: "./my-video/index.html",
+ output: "./output.mp4",
fps: 30,
- quality: 'standard',
+ quality: "standard",
});
-console.log(result.duration); // Total render time in ms
-console.log(result.frameCount); // Number of frames captured
-console.log(result.outputPath); // Absolute path to the output file
+console.log(result.duration); // Total render time in ms
+console.log(result.frameCount); // Number of frames captured
+console.log(result.outputPath); // Absolute path to the output file
```
### With All Options
```typescript
await render({
- input: './my-video/index.html',
- output: './output.mp4',
+ input: "./my-video/index.html",
+ output: "./output.mp4",
fps: 30,
width: 1920,
height: 1080,
- quality: 'high',
- docker: true, // Use Docker for deterministic rendering
+ quality: "high",
+ docker: true, // Use Docker for deterministic rendering
});
```
@@ -96,26 +103,28 @@ await render({ input: './index.html', output: './out.mp4', docker: true });
```
- Docker mode requires Docker to be installed and running. Run `npx hyperframes doctor` to verify your environment. See [Deterministic Rendering](/concepts/determinism) for details on what makes Docker mode deterministic.
+ Docker mode requires Docker to be installed and running. Run `npx hyperframes doctor` to verify
+ your environment. See [Deterministic Rendering](/concepts/determinism) for details on what makes
+ Docker mode deterministic.
## Quality Presets
-| Preset | Resolution | Encoding | Use Case |
-|--------|-----------|----------|----------|
-| `draft` | Original | Fast CRF | Quick iteration, previewing edits |
-| `standard` | Original | Balanced CRF | Production renders, sharing |
-| `high` | Original | High-quality CRF | Final delivery, archival |
+| Preset | Resolution | Encoding | Use Case |
+| ---------- | ---------- | ---------------- | --------------------------------- |
+| `draft` | Original | Fast CRF | Quick iteration, previewing edits |
+| `standard` | Original | Balanced CRF | Production renders, sharing |
+| `high` | Original | High-quality CRF | Final delivery, archival |
## GPU Encoding
The producer supports hardware-accelerated encoding for faster renders:
-| Platform | Encoder | Flag |
-|----------|---------|------|
-| NVIDIA | NVENC | Auto-detected |
-| macOS | VideoToolbox | Auto-detected |
-| Linux | VAAPI | Auto-detected |
+| Platform | Encoder | Flag |
+| -------- | ------------ | ------------- |
+| NVIDIA | NVENC | Auto-detected |
+| macOS | VideoToolbox | Auto-detected |
+| Linux | VAAPI | Auto-detected |
GPU encoding is automatically used when available. To check your system's capabilities:
diff --git a/docs/packages/studio.mdx b/docs/packages/studio.mdx
index 4f953026c..df41a09b3 100644
--- a/docs/packages/studio.mdx
+++ b/docs/packages/studio.mdx
@@ -12,17 +12,21 @@ npm install @hyperframes/studio
## When to Use
**Use `@hyperframes/studio` when you need to:**
+
- Build a custom composition editor UI (e.g., embedded in your own web application)
- Integrate the Hyperframes preview player into a larger product
- Extend the editor with custom panels, toolbars, or integrations
**Use a different package if you want to:**
+
- Preview compositions during development — use the [CLI](/packages/cli) (`npx hyperframes dev`), which launches the studio for you
- Render compositions to MP4 — use the [CLI](/packages/cli) or [producer](/packages/producer)
- Capture frames programmatically — use the [engine](/packages/engine)
- **For most development workflows, you do not need to install the studio directly.** Running `npx hyperframes dev` starts the studio automatically with hot reload. Install `@hyperframes/studio` only if you are embedding the editor into your own application.
+ **For most development workflows, you do not need to install the studio directly.** Running `npx
+ hyperframes dev` starts the studio automatically with hot reload. Install `@hyperframes/studio`
+ only if you are embedding the editor into your own application.
## Running the Studio
@@ -111,7 +115,8 @@ import { Player, Timeline } from '@hyperframes/studio';
```
- The studio depends on `@hyperframes/core` for parsing and runtime injection. You do not need to install core separately — it is included as a dependency.
+ The studio depends on `@hyperframes/core` for parsing and runtime injection. You do not need to
+ install core separately — it is included as a dependency.
## Related Packages
diff --git a/docs/quickstart.mdx b/docs/quickstart.mdx
index 1feba800a..c334c4ce3 100644
--- a/docs/quickstart.mdx
+++ b/docs/quickstart.mdx
@@ -22,6 +22,7 @@ A 1920x1080 video with an animated title that fades in from above — rendered t
```bash Expected output
v20.11.0 # or any version >= 20
```
+
@@ -50,6 +51,7 @@ A 1920x1080 video with an animated title that fades in from above — rendered t
```bash Expected output
ffmpeg version 7.x ...
```
+
@@ -88,6 +90,7 @@ A 1920x1080 video with an animated title that fades in from above — rendered t
| `index.html` | Root composition — your video's entry point |
| `compositions/` | Sub-compositions loaded via `data-composition-src` |
| `assets/` | Media files (video, audio, images) |
+
@@ -105,6 +108,7 @@ A 1920x1080 video with an animated title that fades in from above — rendered t
The dev server supports hot reload — save your HTML file and the preview updates instantly, no manual refresh needed.
+
@@ -141,6 +145,7 @@ A 1920x1080 video with an animated title that fades in from above — rendered t
- **Root element** must have `data-composition-id`, `data-width`, and `data-height`
- **Timed elements** need `data-start`, `data-duration`, `data-track-index`, and `class="clip"`
- **GSAP timeline** must be created with `{ paused: true }` and registered on `window.__timelines`
+
@@ -155,17 +160,18 @@ A 1920x1080 video with an animated title that fades in from above — rendered t
```
Your video is now at `output.mp4`. Open it with any media player.
+
## Requirements summary
-| Dependency | Required | Notes |
-|-----------|----------|-------|
-| **Node.js** 20+ | Yes | Runtime for CLI and dev server |
-| **pnpm** or npm | Yes | Package manager (pnpm recommended) |
-| **FFmpeg** | Yes | Video encoding for local renders |
-| **Docker** | No | Optional — for deterministic, reproducible renders |
+| Dependency | Required | Notes |
+| --------------- | -------- | -------------------------------------------------- |
+| **Node.js** 20+ | Yes | Runtime for CLI and dev server |
+| **pnpm** or npm | Yes | Package manager (pnpm recommended) |
+| **FFmpeg** | Yes | Video encoding for local renders |
+| **Docker** | No | Optional — for deterministic, reproducible renders |
## Next steps
diff --git a/docs/reference/html-schema.mdx b/docs/reference/html-schema.mdx
index dd8877867..65814f9c7 100644
--- a/docs/reference/html-schema.mdx
+++ b/docs/reference/html-schema.mdx
@@ -27,7 +27,9 @@ The framework reads data attributes and automatically manages:
Mounting/unmounting controls **presence**, not appearance. Transitions (fade in, slide in) are animated in scripts.
- Do not manually call `video.play()`, `video.pause()`, set `audio.currentTime`, or mount/unmount clips in scripts. The framework owns media playback and clip lifecycle. See [Common Mistakes](/guides/common-mistakes) for more details.
+ Do not manually call `video.play()`, `video.pause()`, set `audio.currentTime`, or mount/unmount
+ clips in scripts. The framework owns media playback and clip lifecycle. See [Common
+ Mistakes](/guides/common-mistakes) for more details.
## Viewport
@@ -35,31 +37,31 @@ Mounting/unmounting controls **presence**, not appearance. Transitions (fade in,
Every composition must include `data-width` and `data-height` on the root element:
```html
-
+
```
Common sizes:
+
- **Landscape**: `data-width="1920" data-height="1080"`
- **Portrait**: `data-width="1080" data-height="1920"`
## All Clip Attributes
-| Attribute | Applies To | Required | Description |
-|-----------|-----------|----------|-------------|
-| `id` | All | Yes | Unique identifier (e.g., `"el-1"`). Used for relative timing references and CSS targeting. |
-| `class="clip"` | Visible elements | Yes | Enables runtime visibility management. Omit for audio-only clips. |
-| `data-start` | All | Yes | Start time in seconds (e.g., `"0"`, `"5.5"`), or a clip ID reference for [relative timing](#relative-timing) (e.g., `"intro"`). |
-| `data-duration` | video, img, audio | See below | Duration in seconds. **Required** for images. Optional for video/audio (defaults to source duration). Not used on compositions. |
-| `data-track-index` | All | Yes | Timeline track number. Controls z-ordering (higher = in front). Clips on the same track cannot overlap. |
-| `data-media-start` | video, audio | No | Playback offset / trim point in source file (seconds). Default: `0`. See [Data Attributes](/concepts/data-attributes). |
-| `data-volume` | audio, video | No | Volume level from `0` to `1`. Default: `1`. |
-| `data-composition-id` | div | On compositions | Unique composition ID. Must match the key used in `window.__timelines`. |
-| `data-composition-src` | div | No | Path to external composition HTML file (for [nested compositions](#composition-clips)). |
-| `data-width` | div | On compositions | Composition width in pixels. |
-| `data-height` | div | On compositions | Composition height in pixels. |
+| Attribute | Applies To | Required | Description |
+| ---------------------- | ----------------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------- |
+| `id` | All | Yes | Unique identifier (e.g., `"el-1"`). Used for relative timing references and CSS targeting. |
+| `class="clip"` | Visible elements | Yes | Enables runtime visibility management. Omit for audio-only clips. |
+| `data-start` | All | Yes | Start time in seconds (e.g., `"0"`, `"5.5"`), or a clip ID reference for [relative timing](#relative-timing) (e.g., `"intro"`). |
+| `data-duration` | video, img, audio | See below | Duration in seconds. **Required** for images. Optional for video/audio (defaults to source duration). Not used on compositions. |
+| `data-track-index` | All | Yes | Timeline track number. Controls z-ordering (higher = in front). Clips on the same track cannot overlap. |
+| `data-media-start` | video, audio | No | Playback offset / trim point in source file (seconds). Default: `0`. See [Data Attributes](/concepts/data-attributes). |
+| `data-volume` | audio, video | No | Volume level from `0` to `1`. Default: `1`. |
+| `data-composition-id` | div | On compositions | Unique composition ID. Must match the key used in `window.__timelines`. |
+| `data-composition-src` | div | No | Path to external composition HTML file (for [nested compositions](#composition-clips)). |
+| `data-width` | div | On compositions | Composition width in pixels. |
+| `data-height` | div | On compositions | Composition height in pixels. |
## Clip Types
@@ -88,6 +90,7 @@ Common sizes:
Do not animate `width`, `height`, `top`, or `left` directly on `