Commit Graph
405 Commits
Author SHA1 Message Date
Miguel Ángel 31c4f974ea chore: release 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 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 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 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 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 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
Miguel Ángel 36b3fc8cd9 fix: budget workers for expensive captures 2026-04-27 22:53:27 -04:00
Miguel Ángel 37827cdaec chore: release v0.4.32 2026-04-27 21:18:36 -04:00
Miguel Ángel 31afb4c1b3 Merge pull request #518 from heygen-com/fix/studio-preview-runtime-visibility
fix: isolate Studio sub-composition previews
2026-04-28 01:51:09 +02:00
Miguel Ángel 613f97793e test: add preview regression gate 2026-04-27 18:16:09 -04:00
Miguel Ángel 6ea2e54fcf fix: preserve anonymous inlined composition roots 2026-04-27 18:16:01 -04:00
Miguel Ángel d3b2900d6b fix: preserve inferred composition ids when inlining 2026-04-27 16:57:39 -04:00
Miguel Ángel c58b995cb0 refactor: use postcss for composition CSS scoping 2026-04-27 16:42:42 -04:00
Youssef Toufik 9e05322531 test(transparency): paint body background in fixture so it actually fails on the base SHA
Per Miguel's review: the previous fixture had no body / root background, so it
passed against both the buggy and fixed code. The fix this PR makes (the
initTransparentBackground stylesheet injection in initializeSession) only
matters when a composition paints over the CDP default-background-color
override — exactly what we tell users not to do, but exactly what a
regression test must do.

Reproduced locally:

- base SHA (2935be6): pixel (10,10) decodes as rgba [16,16,16,255]
  (opaque #111 body bg leaks through the pre-navigation override that
  Chrome resets on goto)
- this head: pixel (10,10) decodes as rgba [0,0,0,0]
  (initTransparentBackground injects [data-composition-id]{background:transparent !important}
  AFTER navigation, force-overriding the body bg)

The pixel-level assertions in transparency-test.ts are unchanged — they
already require alpha=0 at (10,10). With the body bg painted, that
assertion now fails on any code path that doesn't actually preserve alpha
end-to-end.
2026-04-27 21:05:56 +01:00
Miguel Ángel 3701bb9eeb fix: flatten inlined composition roots 2026-04-27 15:53:24 -04:00
Miguel Ángel c32db3ea0a fix: isolate studio sub-composition previews 2026-04-27 15:51:53 -04:00
Youssef Toufik fe017b48c7 feat(producer): true alpha output for webm, mov, and png-sequence
Extends RenderConfig.format with "png-sequence" and patches two correctness
gaps so the existing "webm" / "mov" values actually preserve the alpha
channel end-to-end.

Engine fixes:
- screenshotService.pageScreenshotCapture: drop optimizeForSpeed for PNG
  captures. The fast path uses an alpha-unaware codec that crushes real
  alpha values; kept for opaque jpeg captures where it is harmless.
- frameCapture: replace the inline setDefaultBackgroundColorOverride
  block (which fired pre-navigation and was reset by page.goto) with a
  proper initTransparentBackground() call inside initializeSession,
  after the window.__hf readiness poll. This also injects the
  html/body/[data-composition-id]{background:transparent !important}
  stylesheet so compositions with custom body / #root backgrounds do not
  defeat the override. Wired into both screenshot-mode and beginframe-mode
  branches.

Producer:
- RenderConfig.format extended to "mp4" | "webm" | "mov" | "png-sequence"
  with full JSDoc.
- Streaming encode is bypassed for png-sequence (frames go straight to
  disk). FORMAT_EXT extended.
- New Stage-5 png-sequence branch: mkdir outputPath, copy captured PNGs as
  frame_NNNNNN.png, copy audio.aac sidecar when audio is present.
- Stage-6 mux/faststart and the debug copy are wrapped in !isPngSequence.
- README.md: new "Transparent Video Output" section.

Tests:
- New fixture tests/transparency-regression/ tagged "transparency".
- New tsx script src/transparency-test.ts asserts pixel-level alpha for
  webm + png-sequence outputs. Wired as "test:transparency".
- Default "test" / "test:update" scripts pass --exclude-tags transparency
  so the golden-MP4 harness ignores the new fixture.

Verified locally on macOS arm64: typecheck clean across engine + producer,
producer renderOrchestrator vitest 10/10, transparency-test passes for
both webm and png-sequence with end-to-end pixel assertions.
2026-04-27 20:33:45 +01:00
renovate[bot] 2ed47eb076 chore(deps): update dependency @google/genai to ^1.50.1 2026-04-27 07:39:37 +00:00
Miguel Ángel 6e19d88e5f chore: release v0.4.31 2026-04-26 19:41:11 -04:00
James 2b836cc224 chore: release v0.4.30 2026-04-26 05:17:13 +00:00
ukimsanov 8cc2084669 fix(cli): snapshot resolves runtime from own dist, not monorepo layout
The snapshot command resolved the HyperFrames runtime IIFE via a
relative path that walked up three directories to packages/core/dist/.
This only worked in the monorepo dev layout — npm/npx installs have
a flat dist/ folder with cli.js and the runtime side by side.

Without the runtime, window.__player was never created and the
snapshot fell back to seeking every __timelines entry to the same
absolute time. Sub-composition timelines expect relative time
(offset from their data-start), so all beats rendered beat-1 content.

Fix: resolve("hyperframe.runtime.iife.js") from __dirname (the dist/
folder itself), where the build already copies the runtime IIFE.
2026-04-26 00:53:06 -04:00
Miguel Ángel 970367f5e6 chore: release v0.4.29 2026-04-25 19:11:53 -04:00
Miguel Ángel a00161d01c Merge pull request #497 from alexcraviotto/feat/no-ref/server-side-waveform-generation 2026-04-26 01:01:56 +02:00
alexcraviotto 894f6e38f1 feat(studio): server-side waveform generation with caching 2026-04-26 00:45:12 +02:00
Miguel Ángel 34c710c44a chore: release v0.4.28 2026-04-25 17:20:25 -04:00
Miguel Ángel a65c0ce22e chore: release v0.4.27 2026-04-25 16:53:48 -04:00
Mu-Tsun Tsai 9b72a87c17 fix(lint): remove root_composition_missing_data_duration (#490)
* fix(lint): remove root_composition_missing_data_duration

Lint cannot statically observe the runtime's true Infinity-emission
condition: it requires a finite GSAP timeline duration AND a finite
media/sub-comp window AND timeline > floor + 1, none of which are
visible to the static linter. The looping shapes that drive the
condition are already covered by `gsap_infinite_repeat` and
`gsap_repeat_ceil_overshoot` (both from #243), which point at the
real authoring mistake — flagging the missing duration separately
was a noisy proxy for the same signal.

Per #490 review discussion, deprecate the static rule and let those
two GSAP rules carry the pre-render coverage. If perfect precision
on `durationInFrames = Infinity` is needed, that belongs on the
runtime/render path where `shouldEmitNonDeterministicInf` is
actually known.

Add regression tests pinning the removal: a docs-compliant root
without `data-duration` no longer warns, and the canonical
loop-inflated shape now surfaces only via `gsap_infinite_repeat`
instead of two duplicate findings.

* docs(skills): update step-6 build checklist after rule removal

Drops the `root_composition_missing_data_duration` reference now that
the rule is gone. Keeps the authoring recommendation (and explains the
runtime Infinity case) but points authors at the GSAP rules that
actually carry the lint signal: `gsap_infinite_repeat` and
`gsap_repeat_ceil_overshoot`.
2026-04-25 17:52:12 +02:00
Miguel Ángel 45f70004a1 chore: release v0.4.26 2026-04-25 11:14:36 -04:00
Miguel Ángel b92341eb98 fix(cli): publish projects through staged uploads (#491)
* fix(cli): publish projects through staged uploads

* fix(cli): honor signed upload length header
2026-04-25 17:09:16 +02:00
Miguel Ángel 8ac46b4596 chore: release v0.4.25 2026-04-25 10:59:45 -04:00
Mu-Tsun Tsai 1782cebfc4 fix(cli): resolve sub-composition <audio> src relative to its own file (#489)
`lintAudioSrcNotFound` resolves every `<audio src>` against the project
root, which is correct for index.html but wrong for sub-compositions —
their srcs are written relative to the sub-composition file (e.g.
`../assets/foo.mp3`), and the bundler rewrites them at compile time.

Carry the sub-composition path alongside each html source and run
`<audio src>` strings starting with `../` through the existing
`rewriteAssetPath` helper before checking existence on disk. Mirrors the
runtime/bundler behaviour so the lint check sees the same path the
renderer will fetch.

Original (un-rewritten) src is still surfaced in the finding message so
authors can grep for it in their HTML.
2026-04-25 16:55:28 +02:00
Miguel Ángel 82fab98e69 chore: release v0.4.24 2026-04-25 00:39:03 -04:00
Miguel Ángel 2f60dd3727 fix(producer): serve symlinked render assets (#486) 2026-04-25 06:36:27 +02:00
Miguel Ángel 5e1db03fe7 fix: sequence multi-file timeline drops (#487) 2026-04-25 06:22:52 +02:00
Mu-Tsun Tsai bb2e64ced1 fix(studio): pin user-agent color scheme to dark (#482)
The studio shell paints a #0a0a0a body but never declares `color-scheme`,
so browsers render native UA chrome (scrollbars, form controls, focus
rings) in the light palette and the mismatch is obvious — especially
scrollbars, which appear as light tracks sitting on top of a near-black
panel.

Studio doesn't expose a theme toggle; the UI is dark-only. Declaring
`color-scheme: dark` on `:root` lines up the browser-native surfaces
with the rest of the chrome.
2026-04-25 06:12:06 +02:00
Mu-Tsun Tsai 28b84ad8de fix(studio): prevent NLE timeline scrollbar from clipping below viewport (#481)
* fix(studio): restore flex layout inside the NLE timeline panel

Without `flex flex-col`, the toolbar and Timeline children render as
block elements and Timeline's `h-full` takes the panel's entire height.
The toolbar still occupies its own ~45px of flow, pushing the scroll
area below the viewport and clipping the scrollbar at the bottom of the
right-side panel.

* fix(studio): pin toolbar height with flex-shrink-0 and trim comment

Wrap the toolbar slot in a flex-shrink-0 div so Timeline back-pressure
can't squeeze the toolbar below its natural height. The visible bug
doesn't manifest at current sizes, but in a flex-col container both
children are flex items and the toolbar has no shrink guard of its own.

Trim the inline comment to a single line — the rationale belongs in
the commit message, not at the call site.
2026-04-25 05:50:46 +02:00