Commit Graph
1585 Commits
Author SHA1 Message Date
Miguel Ángel b2828e48e5 fix(core,cli): defer __renderReady until root timeline is bound
The runtime set __renderReady at the same time as __playerReady,
before the root timeline was bound. Consumers waiting for
__renderReady (the render-safe signal) could observe a player with
no captured timeline, making renderSeek a no-op.

Root cause: init.ts set both flags together, but timeline binding
happens later — synchronously via bindRootTimelineIfAvailable(),
via a deferred setTimeout(0) for bundled compositions, or
asynchronously via loadExternalCompositions().

Fix in init.ts:
- Remove __renderReady from the __playerReady assignment
- Set it after bindRootTimelineIfAvailable() when timeline is found
- Set it in the setTimeout(0) deferred path
- Set it in the external compositions .finally() path

Fix in snapshot.ts:
- Wait for __renderReady (truthful signal) not __timelines
- Use renderSeek() with frame quantization, not seek()
- Tick the GSAP ticker after seeking
- Await document.fonts.ready before capturing

Closes #1047
2026-05-24 13:13:28 -04:00
Miguel Ángel b8d521edfb Merge pull request #1045 from heygen-com/feat/vfx-liquid-glass-v2
feat(registry): Apple Liquid Glass components — iOS 26 + macOS Tahoe
2026-05-24 12:33:37 -04:00
Miguel Ángel 7eb92badb2 Merge pull request #1058 from kiyeonjeon21/fix/aws-lambda-build-zip-linux-ffmpeg
fix(aws-lambda): fail build-zip when ffmpeg-static binary isn't Linux x86-64
2026-05-24 12:30:00 -04:00
Miguel Ángel c9d5dc5ff6 Merge pull request #1056 from kiyeonjeon21/fix/aws-lambda-handle-plan-chromium-init
fix(aws-lambda): resolve Chromium for handlePlan before invoking probe
2026-05-24 12:28:36 -04:00
Miguel Ángel 7397702f3a Merge pull request #1060 from func25/f/preserve-static
fix(core): stop binding class values in composition scoped window
2026-05-24 12:27:16 -04:00
func25 d3127a7507 fix(core): preserve static methods on classes exposed through scoped window 2026-05-24 22:50:40 +07:00
Kiyeon Jeon bc20b87b9a fix(aws-lambda): resolve Chromium for handlePlan before invoking probe
The producer's probe stage launches Chromium when Plan has to resolve
browser-only data: root duration unknown, unresolved sub-compositions, or
data-hf-auto-start media. Only handleRenderChunk was setting
PRODUCER_HEADLESS_SHELL_PATH, so a cold Plan invocation launched
puppeteer-core with no executablePath and failed before writing plan.tar.gz.

Mirror the renderChunk env-var guard inside handlePlan so the bundled
Sparticuz binary gets resolved on the first Plan invocation and reused on
warm starts. The skipChromeResolution dep stays honored for SAM-local RIE
smokes.

A warm Lambda environment can mask this only if it previously served a
renderChunk from another execution and left the env var sticky. Within a
single Step Functions execution, Plan still runs before RenderChunks.

A new dispatch test exercises the guard path by pre-seeding
PRODUCER_HEADLESS_SHELL_PATH and asserting Plan does not overwrite it.
2026-05-24 16:22:31 +09:00
Kiyeon Jeon 9b34114dd1 fix(aws-lambda): fail build-zip when ffmpeg-static binary is not Linux x86-64
`ffmpeg-static` materializes a single platform-selected binary at install
time. By default that follows the install host, so a default macOS/arm64
or linux/arm64 install can stage a binary that Lambda's x86-64 runtime
cannot execute.

Verify the ELF header (ELFCLASS64, EM_X86_64) before copying the binary
into `bin/ffmpeg`. When the check fails, surface the canonical workarounds:
run the build inside a linux/amd64 container, or pre-install with
`npm_config_platform=linux npm_config_arch=x64`.

In the distributed pipeline this mismatch can fail as early as Plan's
`ffmpeg -version` probe after browser probing and before chunks are
scheduled. Later encode/assemble spawns would fail for the same reason.

ffprobe already goes through the platform-segmented
`ffprobe-static/bin/linux/x64` path, so that side doesn't need the same
check.
2026-05-24 16:21:01 +09:00
Miguel Ángel d97935b336 fix(engine): scope WebGPU flag to hardware mode 2026-05-24 01:53:24 -04:00
Miguel Ángel b37236ed97 fix(registry): match Tahoe notification motion 2026-05-24 01:19:24 -04:00
Miguel Ángel 4819d84786 feat(registry): polish macOS Tahoe liquid glass 2026-05-24 00:44:21 -04:00
James 90bf485db8 fix(distributed): reject cfr:true with h265 codec (per review)
The cfr re-encode pass hardcodes `-c:v libx264`. Pairing it with
`codec: "h265"` would silently transcode the h265 chunks to h264.
Detect the encoder discriminant in `meta/encoder.json` and throw a
typed error parallel to the existing non-mp4 format guard, so callers
surface the conflict instead of producing a wrong-codec deliverable.

— Rames Jusso
2026-05-24 00:24:30 -04:00
James 71d1889da6 feat(distributed): add optional cfr flag for exact constant frame rate
Distributed-render output today uses -c:v copy through concat → mux →
faststart, which means PTS timestamps from each chunk pass through
unchanged. Container r_frame_rate is exact (#1040 + this PR's parent),
but stream-level avg_frame_rate stays PTS-derived and can land on
fractional rationals like 27648000/921677 over a 60s render. Same for
sub-ms duration drift.

This is the achievable bar within -c copy stream-copy concat. For most
consumers (browser playback, YouTube, etc.) the difference is invisible.
For downstream tools that strict-check avg_frame_rate or
ms-precision duration (broadcast workflows, frame-accurate compositors,
some third-party transcoders), it matters.

Adds an opt-in cfr config flag (default false). When true, the
assemble step's final pass re-encodes with -fps_mode cfr -r <fps>
instead of -c copy, producing exact CFR output. Trade-off: ~2-5x the
stitch time for a 60s 1080p clip; second-generation H.264 quality loss
is negligible at -crf 18 but is non-zero.
2026-05-24 00:24:30 -04:00
James Russo 4729254b7e Merge pull request #1053 from heygen-com/fix/distributed-single-chunk-fps-flag
fix(distributed): apply -r <fps> to single-chunk pass-through path
2026-05-23 23:50:08 -04:00
Miguel Ángel 83dc57ad77 feat(registry): frost liquid glass widgets 2026-05-23 23:25:44 -04:00
James 49281a5c17 fix(distributed): apply -r <fps> to single-chunk pass-through path
The v0.6.39 fix added -r <fps> to the multi-chunk concat ffmpeg
invocation but didn't reach the single-chunk pass-through path,
which is taken when totalFrames * fpsDen / fpsNum fits in one
chunk. Result: 1-chunk renders shipped with fractional
r_frame_rate (e.g. 359/12) while multi-chunk renders shipped
with exact 30/1.

Single-chunk path now goes through the same -r <fps> + -c copy
ffmpeg invocation as the concat path, ensuring uniform exact
r_frame_rate metadata across all chunk-count configurations.

Adds a regression test exercising the 1-chunk path and asserting
r_frame_rate === "<fpsNum>/<fpsDen>" exact.
2026-05-24 03:15:56 +00:00
Miguel Ángel f9fcf33c08 feat(registry): polish liquid glass previews 2026-05-23 22:37:37 -04:00
Miguel Ángel 4913bf3782 feat(registry): refine iOS Liquid Glass home screen 2026-05-23 20:52:30 -04:00
Miguel Ángel f63c2d40fb docs: remove stale liquid glass catalog entry 2026-05-23 19:49:56 -04:00
Miguel Ángel 07c9367e35 chore: retrigger docs preview 2026-05-23 19:40:36 -04:00
Miguel Ángel 3224a5d581 feat(registry): polish Liquid Glass catalog blocks 2026-05-23 19:34:00 -04:00
Miguel Ángel eb7ca3c1c0 fix: fully remove glass lens, zoom camera closer to iPhone screen 2026-05-23 16:51:50 -04:00
Miguel Ángel ccf0812c95 fix: remove glass lens from iOS 26, improve background, fix macOS Tahoe layout 2026-05-23 16:49:22 -04:00
Miguel Ángel 92bec1b395 fix: macOS Tahoe camera focuses on MacBook, zoom-out animation 2026-05-23 16:42:49 -04:00
Miguel Ángel 5f02161ec1 fix: iOS 26 zoom-out camera, notification glass paint cycle, engine WebGPU flag 2026-05-23 16:35:50 -04:00
Miguel Ángel 1891578dd6 feat(engine): add --enable-unsafe-webgpu flag for WebGPU glass rendering
Adds WebGPU support to the Chrome launch args alongside the existing
CanvasDrawElement flag. Use PRODUCER_HEADLESS_SHELL_PATH to point to
Brave for full WebGPU + drawElementImage support.

Also fixes flicker in liquid glass blocks by removing onpaint/requestPaint
callbacks that conflicted with GSAP's deterministic onUpdate rendering.

Adds macos-tahoe-liquid-glass block (WIP).
2026-05-23 16:23:32 -04:00
Miguel Ángel d88df39613 feat(registry): iOS 26 liquid glass home screen on 3D GLTF iPhone
Replaces the phone screen content in vfx-iphone-device with an iOS 26
home screen: glass app icons (Weather, Stocks, ChatGPT, Slack, X, etc.),
status bar with battery/signal, search pill, dock with badges. All on a
real GLTF iPhone model with camera choreography.
2026-05-23 16:13:10 -04:00
Miguel Ángel 0845dc9e56 Merge pull request #1052 from heygen-com/fix/htmlincanvas-single-worker
fix(producer): force single worker for html-in-canvas compositions
2026-05-23 16:10:38 -04:00
Miguel Ángel 61c7e4ab74 fix(producer): address review feedback on htmlInCanvas worker clamp
- Always log when html-in-canvas pins to 1 worker, not just on
  explicit --workers override (Vance, James)
- Assert recommendScreenshot is true for htmlInCanvas detection —
  pins the load-bearing coupling with the screenshot paint-force
  protocol (Vance, Magi)
- Skip capture calibration for htmlInCanvas auto-sized renders to
  avoid wasting 600ms–3s on an estimate that gets thrown away (Vance)
- Add TODO documenting Chrome's two root-cause mechanisms: paint
  cache race and SwiftShader contention (James, Magi)
2026-05-23 16:08:27 -04:00
Miguel Ángel 5b8fc0107c feat(registry): iOS 26 liquid glass home screen block (WIP — 3D rendering) 2026-05-23 15:57:14 -04:00
Miguel Ángel 497f220c5f fix(producer): force single worker for html-in-canvas compositions
Chrome's drawElementImage API does not support concurrent usage across
multiple browser instances — running >1 capture worker causes flickering
artifacts. Detect the layoutsubtree canvas attribute during compilation
and unconditionally pin workers to 1, overriding both auto-sizing and
explicit --workers flags.
2026-05-23 15:48:02 -04:00
Miguel Ángel 23037e7f0d feat(registry): liquid glass blocks + iOS 26 home screen (WIP)
- 4 liquid glass component blocks with WebGPU glass via
  liquid-glass-html-in-canvas (25KB): notification, context menu,
  media controls, widgets
- iOS 26 liquid glass home screen block (WIP): 3D iPhone with
  layoutsubtree canvas showing app grid with glass icons
- All blocks use 3-layer architecture: Three.js shader (z:0),
  glass panels in layoutsubtree canvas (z:1), CSS text overlay (z:2)
- Renders via Brave with WebGPU + drawElementImage flags
2026-05-23 15:38:57 -04:00
Miguel Ángel 66c40dac94 Merge pull request #1051 from Konadu-Akwasi-Akuoko/fix/set-version-plugin-manifests
fix(release): bump plugin manifests in set-version
2026-05-23 15:38:08 -04:00
Akwasi Konadu Akuoko de6aac6163 chore: sync plugin manifests to v0.6.40 2026-05-23 19:36:28 +00:00
Miguel Ángel 9b9e49c5f8 fix(registry): notification block — top-right positioning, working glass panels 2026-05-23 15:18:10 -04:00
Miguel Ángel 77588b0759 feat(registry): rewrite liquid glass blocks with liquid-glass-html-in-canvas
Complete rewrite of all 4 liquid glass registry blocks using
jeantimex/liquid-glass-html-in-canvas for real WebGPU glass rendering.

Architecture: Three.js aurora shader (z:0) + empty glass panels in
layoutsubtree canvas (z:1) + CSS text overlay (z:2). Text is crisp
and never passes through the glass shader.

- Renders via Brave with WebGPU + drawElementImage flags
- Continuous motion throughout — panels sweep across the screen
- liquid-glass.iife.js bundle (25KB) replaces liquid-dom (88KB)
2026-05-23 15:10:10 -04:00
Akwasi Konadu Akuoko e3a7740306 chore: sync plugin manifests to v0.6.39
Catch the three plugin manifests up to the current release version so
/plugin update is unfrozen immediately, rather than waiting for the next
release to sync them via the fixed-versioning script.
2026-05-23 19:02:53 +00:00
Akwasi Konadu Akuoko 1ee920b535 fix(release): bump plugin manifests in set-version
scripts/set-version.ts only bumped the npm package.json files, so the
Claude Code / Codex / Cursor plugin manifests stayed at 0.1.0 across every
release. Claude Code gates /plugin update on plugin.json's version, so users
never received accumulated changes (closes #1048).

Add a PLUGINS list and a parallel loop that rewrites each manifest's version,
and include the manifests in the clean-tree guard and the staged file set.
The loop replaces only the version string (not a JSON round-trip) to preserve
each file's exact formatting, since oxfmt keeps their short arrays inline and
JSON.stringify would expand them and fail the pre-commit format check.
2026-05-23 19:02:21 +00:00
Miguel Ángel 47d57bff10 chore: bump version to 0.6.40 v0.6.40 2026-05-23 15:01:38 -04:00
Miguel Ángel f7cd18d45a Merge pull request #1050 from heygen-com/fix/inner-root-height-percent
fix(core): set explicit dimensions on data-hf-inner-root wrapper
2026-05-23 15:00:17 -04:00
Miguel Ángel 3983d4e7bf fix(core): set explicit dimensions on data-hf-inner-root wrapper
The prepareFlattenedInnerRoot function creates a wrapper div when
inlining sub-compositions. This wrapper had no width/height, which
broke CSS height:100% chains — any sub-composition using percentage
heights with flexbox centering would collapse to 0px and render
content at the top instead of centered.

Read data-width/data-height from the inner root and set matching
pixel dimensions on the wrapper's inline style. Applied in both the
compiler (server-side bundling) and the runtime (browser-side
composition loader).

Adds a producer regression test with a centered card sub-composition
that fails without this fix.
2026-05-23 14:53:16 -04:00
Miguel Ángel 793a2405b5 Merge pull request #1049 from heygen-com/fix/studio-import-meta-env-guard
fix(studio): guard import.meta.env for non-Vite bundlers
2026-05-23 14:00:03 -04:00
Miguel Ángel 377f081941 fix(studio): guard import.meta.env access for non-Vite bundlers
import.meta.env is undefined in Next.js Turbopack/Webpack, causing
"Cannot read properties of undefined" when the studio telemetry client
loads. Wrap accesses in try-catch so they gracefully fall back.

Also hardcode the PostHog API key and host — they're public write-only
values with no reason to be overridable via env.
2026-05-23 13:59:08 -04:00
James 179b09ec9d chore: release v0.6.39 v0.6.39 2026-05-23 17:30:05 +00:00
Kiyeon Jeon 711c4ff9f9 docs: update rendering comparison and license wording 2026-05-23 17:20:18 +09:00
James a4c4b2ff03 fix(distributed): enforce exact framerate at concat + mux boundaries
When the distributed render path stitches chunks with `-c copy`,
ffmpeg averages the container framerate from PTS rather than
carrying the source's exact rational rate, producing values like
`360000/12001` instead of `30/1` and ~5ms duration drift over
60s.

This is a known ffmpeg behavior at the concat-demuxer-copy
boundary. The industry-standard fix is `-r <fps>` as an input
flag on the concat step plus an output flag on the subsequent
mux step — both with `-c copy` retained, no re-encode required.

Three sites updated:
- `assemble.ts` concat step: `-r <fps>` input flag.
- `chunkEncoder.muxVideoWithAudio`: `-r <fps>` output flag.
- `chunkEncoder.applyFaststart`: same, threaded from caller.

Adds `r_frame_rate` + duration-equivalence assertions to
`assemble.test.ts` to close the regression hole.
2026-05-23 01:12:19 -04:00
Miguel Ángel 3560678bb2 chore: bump version to 0.6.38 v0.6.38 2026-05-23 00:13:50 -04:00
Miguel Ángel 26e8ef596b Merge pull request #1039 from heygen-com/fix/orphaned-child-processes
fix: clean up orphaned Chrome/ffmpeg on preview exit
2026-05-23 06:12:32 +02:00
Miguel Ángel 7e4ce96ba8 fix: SIGKILL escalation in killProcessTree + unit tests
Remaining review follow-ups:

- killProcessTree now escalates to SIGKILL after 500ms if SIGTERM
  doesn't kill the process (same pattern as killTrackedProcesses).
  Covers orphan cleanup and dev/local mode tree kill.

- Added unit tests for both new modules:
  - processTracker.test.ts (6 tests): track/remove on exit/error,
    kill running processes, SIGKILL escalation for SIGTERM-resistant
    processes, idempotency.
  - orphanCleanup.test.ts (5 tests): tree kill with children,
    SIGKILL escalation, non-existent PID handling, orphan detection
    returns 0 when clean.
2026-05-23 00:10:30 -04:00
Miguel Ángel 84edce908a fix: address code review feedback on process cleanup
- Blocker: arm 3s force-exit timer BEFORE awaiting cleanup, not
  inside .finally(). Prevents hang if drainBrowserPool() blocks on
  dead Chrome.
- Reorder cleanup: killTrackedProcesses() (sync, fast) runs first,
  then async browser drain. Ffmpeg dies immediately instead of
  surviving if the hard timer fires early.
- SIGKILL escalation: processTracker now SIGTERMs all tracked
  processes, then SIGKILLs survivors after 500ms grace period.
- Scope pgrep to current user (pgrep -u $(id -u)) so orphan
  detection doesn't touch other users' Chrome on shared machines.
- Add process.on('exit') handler for crash paths (unhandled
  exceptions/rejections that bypass signal handlers).
- Document Windows no-op behavior on killProcessTree handlers.
2026-05-22 23:53:46 -04:00