Commit Graph
689 Commits
Author SHA1 Message Date
Miguel Ángel b9a9998ff0 chore: release v0.4.37 v0.4.37 2026-04-29 16:02:09 -04:00
Miguel Ángel f9d38a1542 feat(core): add anime.js runtime adapter (#569)
## Summary
- Adds a `RuntimeDeterministicAdapter` for anime.js v4+ alongside existing Lottie, Three.js, WAAPI, and CSS adapters
- Enables frame-accurate rendering of anime.js animations — the adapter converts seek time (seconds) to milliseconds and calls `.seek(timeMs)` on registered instances
- Auto-discovers running instances via `anime.running`; compositions can also register manually via `window.__hfAnime`

## Usage in compositions

```html
<script src="https://cdn.jsdelivr.net/npm/animejs@4.0.2/lib/anime.iife.min.js"></script>
<script>
  const anim = anime({
    targets: '.box',
    translateX: 250,
    rotate: '1turn',
    duration: 2000,
    autoplay: false,
  });
  window.__hfAnime = window.__hfAnime || [];
  window.__hfAnime.push(anim);
</script>
```

## Files changed
- `packages/core/src/runtime/adapters/animejs.ts` — adapter implementation
- `packages/core/src/runtime/adapters/animejs.test.ts` — 15 unit tests
- `packages/core/src/runtime/init.ts` — register adapter in runtime init
- `packages/core/src/runtime/window.d.ts` — add `anime` and `__hfAnime` globals

## Test plan
- [x] All 15 unit tests pass (`bun run --cwd packages/core test -- --run adapters/animejs`)
- [x] Build passes (`bun run build`)
- [x] Pre-commit hooks pass (lint, format, typecheck, commitlint)
- [x] Manual test: render a composition using anime.js animations
2026-04-29 21:30:17 +02:00
Miguel Ángel bcd7230557 fix: fall back to screenshot mode when any CDP call times out during calibration (#567)
## Summary

- **Root cause**: `shouldFallbackToScreenshotAfterCalibrationError` only matched `HeadlessExperimental.beginFrame` errors. When a composition with many heavy videos (e.g. 7 videos with sparse keyframes) caused Chrome to be unresponsive in BeginFrame mode during calibration, a `Runtime.callFunctionOn timed out` or `Runtime.evaluate timed out` error was treated as an opaque failure — not a BeginFrame-mode signal. The render kept BeginFrame mode, spawned 3 workers with `captureCostMultiplier=8`, and all 3 workers also timed out initialising their sessions (0 frames captured, render fails).
- **Fix**: Add `Runtime.callFunctionOn timed out` and `Runtime.evaluate timed out` to the screenshot-fallback pattern. Any CDP call timing out during the short-timeout calibration probe now routes the render into single-worker screenshot mode — the safe fallback already used for explicit BeginFrame timeouts.
- **Result**: Compositions that overwhelm BeginFrame mode (reported in #566: 7 videos, 8 audios, 330-second render) now fall back cleanly and complete instead of failing with 0 frames.

## Test plan

- [x] New unit test: `falls back to screenshot mode after Runtime.callFunctionOn timeout during calibration` — asserts both `Runtime.callFunctionOn timed out` and `Runtime.evaluate timed out` return `true`
- [x] All existing `capture calibration safeguards` unit tests still pass
- [x] Pre-commit hooks (lint, format, typecheck) pass

Fixes #566
2026-04-29 20:03:40 +02:00
Miguel Ángel 403c00eeae fix: warn on self-scoped composition selectors (#562) 2026-04-29 18:13:51 +02:00
Miguel Ángel 328bba0384 fix: make registry blocks pass lint errors (#564) 2026-04-29 17:53:26 +02:00
Miguel Ángel c0a74c1159 feat: add vertical flowchart block (#563) 2026-04-29 17:53:22 +02:00
Miguel Ángel c196b76a40 fix: isolate duplicate sub-composition instances (#561) 2026-04-29 17:53:18 +02:00
Miguel Ángel 857b870459 chore: release v0.4.36 v0.4.36 2026-04-29 14:55:45 +00:00
Miguel Ángel 8b234be20c fix(producer): handle no-audio stream gracefully in resolveMediaDuration
When an <audio> element referenced a file with no audio stream (e.g. a
silent screen-recording used as an audio src, or a video-only clip),
extractAudioMetadata threw "[FFmpeg] No audio stream found". The error
propagated uncaught through Promise.all in compileHtmlFile and crashed
the entire render.

Apply the same graceful-skip pattern already used for missing files and
failed downloads: catch the probe error and return { duration: 0 } so
the element is excluded from the composition without aborting the render.

Confirmed via 7 production HyperframeRenderWorkflow failures all sharing
the same TemporalMagicEditActivity.RENDER_PREVIEW stack trace.
2026-04-29 16:53:35 +02:00
Miguel Ángel eb065260dc chore: release v0.4.35 v0.4.35 2026-04-29 13:47:22 +00:00
Miguel Ángel 47b801fbf2 feat: add Studio NLE playback controls (#530)
## Problem

HyperFrames Studio made frame-accurate playback review slower than expected for editor-style workflows. Issue #527 called out missing loop playback, frame display/jump controls, preview-focused Space handling, frame stepping, and NLE-style J/K/L shuttle controls.

## What this fixes

- Adds a persistent Studio loop toggle and makes the playback loop restart when enabled.
- Adds a time/frame display toggle plus a jump-to-frame input in the player controls.
- Adds frame math helpers and frame-step behavior at the Studio preview frame rate.
- Expands keyboard handling so preview-focused Space toggles playback, ArrowLeft/ArrowRight step frames, Shift+Arrow steps 10 frames, and J/K/L shuttle controls work from the preview/timeline surface while ignoring form/button/slider targets.
- Adds J/K/L shuttle behavior: J plays backward, K pauses, L plays forward, repeated J/L ramps 1x -> 2x -> 4x, and K-held J/L frame-steps.
- Makes the preview wrapper focusable so keyboard playback shortcuts work after focusing the preview area.

## Root cause

The Studio playback layer only exposed mouse scrubbing, basic play/pause, a seconds-based readout, and slider-local arrow-key nudges. The global Space shortcut was also gated to `document.body`, so it stopped working once the actual preview/editor surface had focus. Studio needed a single playback-control layer above the runtime adapter that could translate editor keyboard intent into deterministic seek/play/pause operations.

## Verification

### Local checks

- `bun install`
- `bun run --filter @hyperframes/core build:hyperframes-runtime`
- `bunx oxfmt --check packages/studio/src/player/lib/time.ts packages/studio/src/player/lib/time.test.ts packages/studio/src/player/store/playerStore.ts packages/studio/src/player/store/playerStore.test.ts packages/studio/src/player/hooks/useTimelinePlayer.ts packages/studio/src/player/components/PlayerControls.tsx packages/studio/src/player/components/PlayerControls.test.ts packages/studio/src/components/nle/NLEPreview.tsx`
- `bunx oxlint packages/studio/src/player/lib/time.ts packages/studio/src/player/lib/time.test.ts packages/studio/src/player/store/playerStore.ts packages/studio/src/player/store/playerStore.test.ts packages/studio/src/player/hooks/useTimelinePlayer.ts packages/studio/src/player/components/PlayerControls.tsx packages/studio/src/player/components/PlayerControls.test.ts packages/studio/src/components/nle/NLEPreview.tsx`
- `bun run --filter @hyperframes/studio test -- src/player/lib/time.test.ts src/player/store/playerStore.test.ts src/player/components/PlayerControls.test.ts src/player/hooks/useTimelinePlayer.test.ts` -> 4 files passed, 52 tests passed
- `bun run --filter @hyperframes/studio typecheck`
- `bun run --filter @hyperframes/studio build`
- `git diff --check`
- Lefthook during commit -> lint, format, typecheck, commitlint pass

### Browser verification

- Created a temp project at `/tmp/hf-studio-nle-controls` with an animated 10s GSAP timeline.
- Started local Studio preview via `bun run --filter @hyperframes/cli dev -- preview /tmp/hf-studio-nle-controls` at `http://localhost:5194`.
- Used `agent-browser` to verify:
  - loop toggle changes to active state
  - frame display shows `current / total` frames
  - jump-to-frame input moves the seek position to frame 45 / frame 150
  - focused preview accepts Space play/pause
  - ArrowRight advances one frame from preview focus
  - J plays backward from frame 150 to a lower frame, then K stops
  - agent-browser-driven recording of the tested flow completed

## Notes

- Local proof artifacts are intentionally not committed:
  - `qa-artifacts/studio-nle-controls/frame-controls.png`
  - `qa-artifacts/studio-nle-controls/playback-controls.webm`
- Closes #527.
2026-04-29 05:04:46 +02:00
Miguel Ángel 5fe53a0f9c fix: keep caption shortcuts outside component 2026-04-28 22:44:23 -04:00
Miguel Ángel 9dc17ae30d fix: scope studio playback shortcuts 2026-04-28 22:32:23 -04:00
James Russo 02e8bac7e9 Merge pull request #547 from heygen-com/docs/readme-discord-badge
docs(readme): add Discord community badge
2026-04-28 17:04:28 -07:00
JamesandClaude Opus 4.7 be1fcfc4e6 docs(readme): add Discord community badge
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 23:59:24 +00:00
Miguel Ángel 31c4f974ea chore: release v0.4.34 v0.4.34 2026-04-28 23:39:28 +00:00
Vance Ingalls ad44c3133a perf(hdr): reduce layered composite overhead (#538) 2026-04-28 15:30:35 -07:00
Miguel Ángel fc3c601870 Merge pull request #541 from heygen-com/feat/studio-timeline-pinch-zoom
feat(studio): add timeline pinch zoom
2026-04-29 00:22:19 +02:00
Miguel Ángel 0a542f8c8e Merge pull request #540 from heygen-com/fix/studio-gsap-clip-offset
fix(studio): keep GSAP timeline clips stable
2026-04-29 00:09:40 +02:00
Miguel Ángel a45f900af7 feat: add Studio NLE playback controls 2026-04-28 17:51:38 -04:00
Miguel Ángel 635fca124d feat(studio): adapt timeline ruler density 2026-04-28 17:41:39 -04:00
Miguel Ángel 7ff1734db7 fix(studio): capture timeline pinch zoom 2026-04-28 17:31:49 -04:00
Miguel Ángel 820b07ddaa feat(studio): support trackpad timeline pinch zoom 2026-04-28 17:28:04 -04:00
Miguel Ángel 78d949b844 fix(studio): keep gsap timeline clips stable 2026-04-28 17:20:24 -04:00
Miguel Ángel e568235a1d Merge pull request #531 from heygen-com/lint/subcomposition-guidance
feat(lint): warn on dense compositions
2026-04-28 23:08:34 +02:00
Miguel Ángel e1d1103ef0 Merge pull request #532 from heygen-com/fix/snapshot-runtime-multi-strategy
fix(cli): use multi-strategy runtime resolver for snapshot
2026-04-28 23:08:08 +02:00
Miguel Ángel f7de8ebcb1 Merge pull request #539 from heygen-com/fix/subcomposition-audio-coverage
test: cover sub-composition audio extraction
2026-04-28 23:04:35 +02:00
Miguel Ángel 54cc0f1cba test: cover sub-composition audio extraction 2026-04-28 17:00:40 -04:00
Miguel Ángel f142a63e63 Merge pull request #523 from heygen-com/fix/cli-validate-smoke-ci
fix: validate CLI smoke paths
2026-04-28 22:44:54 +02:00
Miguel Ángel 4988b42362 ci: relax CLI smoke validate timeout 2026-04-28 16:18:46 -04:00
Miguel Ángel e14ff9b485 feat(lint): warn on dense compositions 2026-04-28 15:45:32 -04:00
ukimsanovandClaude Opus 4.7 ce4bcc47c0 fix(cli): use multi-strategy runtime resolver for snapshot
Use loadRuntimeSource() from runtimeSource.ts instead of a single
hardcoded path. Tries: build from source (dev), inlined constant
(production), pre-built artifact (fallback). Fixes snapshot in dev
mode where __dirname is src/commands/ not dist/.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 14:36:34 -04:00
Vance IngallsandClaude Opus 4.6 8f97edb2b9 fix(hdr): filter zero-opacity elements and support overflow:hidden clip rects (#522)
* fix(hdr): filter zero-opacity elements and support overflow:hidden clip rects in HDR compositor

Two bugs in the HDR render pipeline:

1. Child data-start elements inside a parent with opacity:0 were still
   composited as independent layers, painting over content in later scenes.
   Fix: filter elements with effective opacity 0 before groupIntoLayers().

2. CSS overflow:hidden on ancestor elements was ignored for HDR video layers,
   causing videos inside clipped containers (e.g. split-screen halves) to
   render full-frame. Fix: add clipRect to ElementStackingInfo, compute it
   from ancestor overflow:hidden in queryElementStacking(), and crop the
   source buffer to clip bounds before blitting in blitHdrVideoLayer().

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(hdr): move opacity filter into blit loop to preserve hide-list correctness

The previous approach filtered zero-opacity elements before groupIntoLayers(),
which broke the DOM screenshot hide-list — invisible video elements' <img>
replacements weren't properly hidden from sibling layer screenshots, causing
the vignelli-stacking regression.

Fix: keep all elements in groupIntoLayers() for correct hide-list generation.
Skip zero-opacity HDR elements only during the actual blit step with an early
`continue` in the compositing loop.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(hdr): route identity-matrix HDR elements through region blit for clip rect support

parseTransformMatrix returns a valid matrix even for untransformed HDR
elements (Chrome reports matrix(1,0,0,1,0,0)). This made the affine blit
path always run, bypassing the region blit path which is the only one that
applies clip rects from overflow:hidden ancestors.

Fix: detect identity matrices and route them through the region path so
the cropRgb48le clip logic is reachable for split-screen layouts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(hdr): handle translation-only matrices for clip rect support

The previous isIdentity check only caught matrix(1,0,0,1,0,0). Elements
with layout translation (e.g. right-half split at left:960px reporting
matrix(1,0,0,1,960,0)) still routed through the affine path where clip
rects are not applied.

Fix: check for translation-only matrices (scale=1, rotation=0, any tx/ty)
and route those through the region blit path. el.x/el.y from
getBoundingClientRect already include the translation, so the region path
handles positioning correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(render): auto-detect HDR from media probes, add --sdr flag

Replace the --hdr opt-in model with automatic detection. When no flags
are passed, the renderer probes all video/image sources and enables HDR
output if any HDR color space is detected. Existing --hdr flag becomes
a force override. New --sdr flag forces SDR output.

Behavior matrix:
  (no flags) + HDR content → HDR output
  (no flags) + SDR content → SDR output
  --hdr → force HDR (defaults to HLG if no HDR sources)
  --sdr → force SDR (skips probing)
  --hdr --sdr → error

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Revert "feat(render): auto-detect HDR from media probes, add --sdr flag"

This reverts commit 69fb52196f.

* chore(hdr): simplify review fixes — remove redundant guard, add image clip warning

- Remove redundant viewportMatrix.length >= 6 check (parseTransformMatrix
  always returns 6-element array or null)
- Add clip rect warning log to blitHdrImageLayer for parity with video path

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 10:15:25 -07:00
Miguel Ángel 46a4cacea2 chore: release v0.4.33 v0.4.33 2026-04-28 12:45:02 -04:00
Miguel Ángel 84d58011f1 ci: address CLI smoke review feedback 2026-04-28 11:02:27 -04:00
Miguel Ángel 82ce413fd9 ci: install ffmpeg in CLI smoke job 2026-04-28 10:57:50 -04:00
Miguel Ángel 9c7983211a fix: validate CLI smoke paths and warn on oversized compositions 2026-04-28 10:57:50 -04:00
Vance IngallsandClaude Opus 4.6 8e5593b6ba feat(render): auto-detect HDR from media probes, add --sdr flag (#526)
* feat(render): auto-detect HDR from media probes, add --sdr flag

Replace the --hdr opt-in model with automatic detection. When no flags
are passed, the renderer probes all video/image sources and enables HDR
output if any HDR color space is detected. Existing --hdr flag becomes
a force override. New --sdr flag forces SDR output.

Behavior matrix:
  (no flags) + HDR content → HDR output
  (no flags) + SDR content → SDR output
  --hdr → force HDR (defaults to HLG if no HDR sources)
  --sdr → force SDR (skips probing)
  --hdr --sdr → error

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: align HDR auto-detect docs and tests

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-28 01:39:51 -07:00
James Russo 4d0e262eb3 Merge pull request #511 from heygen-com/renovate/google-genai-1.x
chore(deps): update dependency @google/genai to ^1.50.1
2026-04-27 22:34:28 -07:00
James Russo 2d8a29e076 Merge pull request #510 from heygen-com/renovate/github-actions
chore(deps): pin dependencies
2026-04-27 22:33:47 -07:00
James Russo d01685d695 Merge pull request #517 from heygen-com/skill/r2hf-skill-body
feat(skills): remotion-to-hyperframes SKILL.md + orchestrator (7/7)
2026-04-27 22:19:03 -07:00
James Russo f22d9bfabe Merge pull request #516 from heygen-com/skill/r2hf-references
feat(skills): remotion-to-hyperframes references (6/7)
2026-04-27 22:18:44 -07:00
James Russo 40339a65b9 Merge pull request #515 from heygen-com/skill/r2hf-corpus-t4
feat(skills): remotion-to-hyperframes corpus T4 (5/7)
2026-04-27 22:18:14 -07:00
James Russo 12945238cc Merge pull request #509 from heygen-com/skill/r2hf-corpus-t3
feat(skills): remotion-to-hyperframes corpus T3 (4/7)
2026-04-27 22:17:55 -07:00
James Russo 4ab4576adf Merge pull request #508 from heygen-com/skill/r2hf-corpus-t1-t2
feat(skills): remotion-to-hyperframes corpus T1+T2 (3/7)
2026-04-27 22:17:37 -07:00
James Russo b27385ba1a Merge pull request #507 from heygen-com/skill/r2hf-eval-harness
feat(skills): remotion-to-hyperframes eval harness (2/7)
2026-04-27 22:14:29 -07:00
James Russo 3fa094c5c5 Merge pull request #506 from heygen-com/skill/r2hf-scaffold
feat(skills): scaffold remotion-to-hyperframes skill (1/7)
2026-04-27 22:12:11 -07:00
Miguel Ángel a18f66db18 Merge pull request #525 from heygen-com/fix/shader-audio-worker-fallback
fix: budget workers for expensive captures
2026-04-28 05:32:03 +02:00
Miguel Ángel 36b3fc8cd9 fix: budget workers for expensive captures 2026-04-27 22:53:27 -04:00
Miguel Ángel 87fe549ff1 Merge pull request #524 from heygen-com/docs/video-editor-cheatsheet
docs: add Video Editor Cheatsheet guide
2026-04-28 04:02:45 +02:00