Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "hyperframes",
"description": "HyperFrames by HeyGen. Write HTML, render video. Compositions, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website capture for HyperFrames.",
"version": "0.8.44",
"version": "0.8.45",
"author": {
"name": "HeyGen",
"email": "hyperframes@heygen.com",
Expand Down
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "hyperframes",
"description": "Write HTML, render video. Compositions, Tailwind v4 styles, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website capture for HyperFrames.",
"version": "0.8.44",
"version": "0.8.45",
"author": {
"name": "HeyGen",
"email": "hyperframes@heygen.com",
Expand Down
2 changes: 1 addition & 1 deletion .cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"name": "hyperframes",
"displayName": "HyperFrames by HeyGen",
"description": "Write HTML, render video. Compositions, Tailwind v4 styles, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website capture for HyperFrames.",
"version": "0.8.44",
"version": "0.8.45",
"author": {
"name": "HeyGen",
"email": "hyperframes@heygen.com"
Expand Down
41 changes: 41 additions & 0 deletions docs/changelog.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,47 @@ Recent HyperFrames releases, including user-facing features, fixes, and migratio

{/* New release entries are prepended by `bun run changelog:draft <version> --write`. */}

<Update
label="HyperFrames v0.8.45"
description="Released - 2026-09-17"
tags={["Release", "Producer", "Engine", "CLI", "Telemetry", "Registry"]}
>
Motion blur arrives twice in this release, as two separate mechanisms for two different jobs. The catalog component reproduces the After Effects look, while the render engine computes the real shutter integral.

## Features

- **Producer:** `motionBlur` on a render configuration turns on sub-frame multi-sample blur. An empty object takes the defaults: 16 samples per frame, a 180 degree shutter angle and a shutter phase of -90. `samplesPerFrame` accepts up to 64. Setting it forces PNG frame capture, because the samples are averaged pixel by pixel and JPEG samples would be averaged after a lossy step. Whether a render captures lossless frames now has one owner instead of being decided in three places from a different fact ([b64a7a3a6](https://github.com/heygen-com/hyperframes/commit/b64a7a3a67ae1f5c22915a88938853169eb3cea2), [#4020](https://github.com/heygen-com/hyperframes/pull/4020)).
- **Engine:** Each output frame can be the average of several captures taken across the shutter window. Because each sample re-renders the page, this integrates whatever the composition actually does inside the window: rotation, scale, opacity, filters and child animation, not translation alone. It is off unless asked for, and a static frame still costs one capture ([0a1c6f5a4](https://github.com/heygen-com/hyperframes/commit/0a1c6f5a457ca1345d6b8ccede04769a0e009719), [#4019](https://github.com/heygen-com/hyperframes/pull/4019)).
- **Producer and CLI:** A render can output an HLS VOD package. It is the same H.264 and AAC encode as MP4, copied into MPEG-TS segments with playlists, and every segment starts on a keyframe ([462f9db73](https://github.com/heygen-com/hyperframes/commit/462f9db73dc0951a112a057416d03effb2fcf1a0), [#4014](https://github.com/heygen-com/hyperframes/pull/4014), [e4b1832fa](https://github.com/heygen-com/hyperframes/commit/e4b1832fadd4c063bcf9a19cd351684815fbc23e), [#4022](https://github.com/heygen-com/hyperframes/pull/4022)).
- **Telemetry:** `render_complete` and `render_error` carry more about the render they describe: the requested output shape, which deterministic adapters the composition exercised, counts of audio, image, sub-composition, audio group and color grading elements, whether a LUT is present, and the browser and FFmpeg major versions. Every value comes from work the render already did, so nothing new runs. A Docker render reports no tool versions, because its preflight happens inside the container ([71bb88719](https://github.com/heygen-com/hyperframes/commit/71bb88719e10ab7002dafd61478d2c84c255ba42), [#4017](https://github.com/heygen-com/hyperframes/pull/4017)).

## Fixes

- **Engine:** A frame that repeats its predecessor is reused instead of re-rendered, and with motion blur on that check ignored the shutter window. A still frame next to a moving one reused a buffer carrying none of that motion. The reuse now requires the whole window to be still. The guard's contract comes from [#4013](https://github.com/heygen-com/hyperframes/pull/4013) by Dante-dan ([9117b3647](https://github.com/heygen-com/hyperframes/commit/9117b364710444432504b98bfbb5543e381d956d), [#4025](https://github.com/heygen-com/hyperframes/pull/4025)).
- **Producer:** Asking for motion blur on the layered compositor route returned frames with no blur and no error. It now fails with a named error that says which route refused and why, instead of a render that looks finished and is not. The route is taken for HDR content and for shader transitions, and the message names both rather than blaming HDR for a composition that has none. "Does this capture route support motion blur" has one owner, keyed to the capture plan's own kind, so a new route cannot inherit silence. The explicit unsupported-mode error is the design in [#4013](https://github.com/heygen-com/hyperframes/pull/4013) by Dante-dan ([77a45f608](https://github.com/heygen-com/hyperframes/commit/77a45f6080daedd12ab67a3d1c9d165b8ae003b3), [#4026](https://github.com/heygen-com/hyperframes/pull/4026)).

## Catalog

- **Registry:** The `motion-blur` component now follows the After Effects shutter model instead of a row of hard copies. Measured against a real After Effects export over 72 frames, the match improved from 24.19 dB to 32.51 dB on average, and the worst frame from 17.07 dB to 27.57 dB ([9aa60a844](https://github.com/heygen-com/hyperframes/commit/9aa60a844fa645ef92949cf6025ddbb634a97e63), [#4008](https://github.com/heygen-com/hyperframes/pull/4008)).

## Choosing a motion blur, and what each one costs

The catalog component and the engine path do different things. Applying both blurs the same motion twice.

- The catalog component is cheap, blurs translation only, and deliberately reproduces the After Effects look, which composites a sharp copy over the smear.
- The engine path blurs any animated property and computes the shutter integral, which is what a real camera shutter does. Peak opacity therefore drops during fast motion rather than staying anchored to a sharp core. That is the correct answer for a shutter and a different picture from the component.
- The engine path costs one capture per sample. At 16 samples a 1080p frame spends roughly 600 ms in the blend on top of the 16 captures, so a slow render is expected rather than stuck.

## Known limits of the engine path

- A video's own motion does not blur. Injected video frames are extracted once per output frame, so a sub-frame seek does not move them. A render that injects video frames refuses rather than pretending.
- Capture modes other than screenshot are refused with a named error, as is the layered compositor route.
- Frames are captured as PNG for the whole render.
- A shutter that is both wide and not centered, meaning `shutterPhase + shutterAngle` above 360, seeks past the end of the composition on the last frames. No default or documented configuration reaches it and the behaviour there is unproven.

[View the full commit range](https://github.com/heygen-com/hyperframes/compare/v0.8.44...v0.8.45).
</Update>

<Update
label="HyperFrames v0.8.44"
description="Released - 2026-09-16"
Expand Down
2 changes: 1 addition & 1 deletion packages/aws-lambda/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/aws-lambda",
"version": "0.8.44",
"version": "0.8.45",
"description": "AWS Lambda adapter for HyperFrames distributed rendering — handler, client-side SDK, and CDK construct.",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/cli",
"version": "0.8.44",
"version": "0.8.45",
"description": "HyperFrames CLI — create, preview, and render HTML video compositions",
"license": "Apache-2.0",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/core",
"version": "0.8.44",
"version": "0.8.45",
"description": "",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/engine/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/engine",
"version": "0.8.44",
"version": "0.8.45",
"description": "Seekable web page to video rendering engine (Puppeteer + FFmpeg)",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/gcp-cloud-run/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/gcp-cloud-run",
"version": "0.8.44",
"version": "0.8.45",
"description": "Google Cloud Run + Workflows adapter for HyperFrames distributed rendering — request handler, client-side SDK, and Terraform module.",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/lint/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/lint",
"version": "0.8.44",
"version": "0.8.45",
"repository": {
"type": "git",
"url": "https://github.com/heygen-com/hyperframes",
Expand Down
2 changes: 1 addition & 1 deletion packages/parsers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/parsers",
"version": "0.8.44",
"version": "0.8.45",
"repository": {
"type": "git",
"url": "https://github.com/heygen-com/hyperframes",
Expand Down
2 changes: 1 addition & 1 deletion packages/player/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/player",
"version": "0.8.44",
"version": "0.8.45",
"description": "Embeddable web component for HyperFrames compositions",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/producer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/producer",
"version": "0.8.44",
"version": "0.8.45",
"description": "HTML-to-video rendering engine using Chrome's BeginFrame API",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/sdk",
"version": "0.8.44",
"version": "0.8.45",
"description": "Headless, framework-neutral HyperFrames composition editing engine",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/shader-transitions/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/shader-transitions",
"version": "0.8.44",
"version": "0.8.45",
"description": "WebGL shader transitions for HyperFrames compositions",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/studio-server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/studio-server",
"version": "0.8.44",
"version": "0.8.45",
"repository": {
"type": "git",
"url": "https://github.com/heygen-com/hyperframes",
Expand Down
2 changes: 1 addition & 1 deletion packages/studio/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperframes/studio",
"version": "0.8.44",
"version": "0.8.45",
"description": "",
"repository": {
"type": "git",
Expand Down
40 changes: 40 additions & 0 deletions releases/v0.8.45.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# HyperFrames v0.8.45

Released on 2026-09-17.

Motion blur arrives twice in this release, as two separate mechanisms for two different jobs. The catalog component reproduces the After Effects look, while the render engine computes the real shutter integral.

## Features

- **Producer:** `motionBlur` on a render configuration turns on sub-frame multi-sample blur. An empty object takes the defaults: 16 samples per frame, a 180 degree shutter angle and a shutter phase of -90. `samplesPerFrame` accepts up to 64. Setting it forces PNG frame capture, because the samples are averaged pixel by pixel and JPEG samples would be averaged after a lossy step. Whether a render captures lossless frames now has one owner instead of being decided in three places from a different fact ([b64a7a3a6](https://github.com/heygen-com/hyperframes/commit/b64a7a3a67ae1f5c22915a88938853169eb3cea2), [#4020](https://github.com/heygen-com/hyperframes/pull/4020)).
- **Engine:** Each output frame can be the average of several captures taken across the shutter window. Because each sample re-renders the page, this integrates whatever the composition actually does inside the window: rotation, scale, opacity, filters and child animation, not translation alone. It is off unless asked for, and a static frame still costs one capture ([0a1c6f5a4](https://github.com/heygen-com/hyperframes/commit/0a1c6f5a457ca1345d6b8ccede04769a0e009719), [#4019](https://github.com/heygen-com/hyperframes/pull/4019)).
- **Producer and CLI:** A render can output an HLS VOD package. It is the same H.264 and AAC encode as MP4, copied into MPEG-TS segments with playlists, and every segment starts on a keyframe ([462f9db73](https://github.com/heygen-com/hyperframes/commit/462f9db73dc0951a112a057416d03effb2fcf1a0), [#4014](https://github.com/heygen-com/hyperframes/pull/4014), [e4b1832fa](https://github.com/heygen-com/hyperframes/commit/e4b1832fadd4c063bcf9a19cd351684815fbc23e), [#4022](https://github.com/heygen-com/hyperframes/pull/4022)).
- **Telemetry:** `render_complete` and `render_error` carry more about the render they describe: the requested output shape, which deterministic adapters the composition exercised, counts of audio, image, sub-composition, audio group and color grading elements, whether a LUT is present, and the browser and FFmpeg major versions. Every value comes from work the render already did, so nothing new runs. A Docker render reports no tool versions, because its preflight happens inside the container ([71bb88719](https://github.com/heygen-com/hyperframes/commit/71bb88719e10ab7002dafd61478d2c84c255ba42), [#4017](https://github.com/heygen-com/hyperframes/pull/4017)).

## Fixes

- **Engine:** A frame that repeats its predecessor is reused instead of re-rendered, and with motion blur on that check ignored the shutter window. A still frame next to a moving one reused a buffer carrying none of that motion. The reuse now requires the whole window to be still. The guard's contract comes from [#4013](https://github.com/heygen-com/hyperframes/pull/4013) by Dante-dan ([9117b3647](https://github.com/heygen-com/hyperframes/commit/9117b364710444432504b98bfbb5543e381d956d), [#4025](https://github.com/heygen-com/hyperframes/pull/4025)).
- **Producer:** Asking for motion blur on the layered compositor route returned frames with no blur and no error. It now fails with a named error that says which route refused and why, instead of a render that looks finished and is not. The route is taken for HDR content and for shader transitions, and the message names both rather than blaming HDR for a composition that has none. "Does this capture route support motion blur" has one owner, keyed to the capture plan's own kind, so a new route cannot inherit silence. The explicit unsupported-mode error is the design in [#4013](https://github.com/heygen-com/hyperframes/pull/4013) by Dante-dan ([77a45f608](https://github.com/heygen-com/hyperframes/commit/77a45f6080daedd12ab67a3d1c9d165b8ae003b3), [#4026](https://github.com/heygen-com/hyperframes/pull/4026)).

## Catalog

- **Registry:** The `motion-blur` component now follows the After Effects shutter model instead of a row of hard copies. Measured against a real After Effects export over 72 frames, the match improved from 24.19 dB to 32.51 dB on average, and the worst frame from 17.07 dB to 27.57 dB ([9aa60a844](https://github.com/heygen-com/hyperframes/commit/9aa60a844fa645ef92949cf6025ddbb634a97e63), [#4008](https://github.com/heygen-com/hyperframes/pull/4008)).

## Choosing a motion blur, and what each one costs

The catalog component and the engine path do different things. Applying both blurs the same motion twice.

- The catalog component is cheap, blurs translation only, and deliberately reproduces the After Effects look, which composites a sharp copy over the smear.
- The engine path blurs any animated property and computes the shutter integral, which is what a real camera shutter does. Peak opacity therefore drops during fast motion rather than staying anchored to a sharp core. That is the correct answer for a shutter and a different picture from the component.
- The engine path costs one capture per sample. At 16 samples a 1080p frame spends roughly 600 ms in the blend on top of the 16 captures, so a slow render is expected rather than stuck.

## Known limits of the engine path

- A video's own motion does not blur. Injected video frames are extracted once per output frame, so a sub-frame seek does not move them. A render that injects video frames refuses rather than pretending.
- Capture modes other than screenshot are refused with a named error, as is the layered compositor route.
- Frames are captured as PNG for the whole render.
- A shutter that is both wide and not centered, meaning `shutterPhase + shutterAngle` above 360, seeks past the end of the composition on the last frames. No default or documented configuration reaches it and the behaviour there is unproven.

## Full changelog

https://github.com/heygen-com/hyperframes/compare/v0.8.44...v0.8.45
Loading