Commit Graph
1424 Commits
Author SHA1 Message Date
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
Miguel Ángel e87f5bb769 fix(engine): widen VFR test frame count tolerance for cross-platform FFmpeg
FFmpeg's VFR-to-CFR normalization produces slightly different frame
counts across versions due to timestamp rounding in the fps filter.
The ±1 tolerance was too tight for Linux FFmpeg builds. Widen to ±3
frames — still catches the 25% shortfall regression these tests
guard against.
2026-05-22 23:42:49 -04:00
Miguel Ángel a54953b936 fix: clean up orphaned Chrome and ffmpeg processes on preview exit
The preview command's shutdown handler only closed the HTTP server,
leaving Chrome (browser pool) and ffmpeg processes alive. This caused
silent resource leaks — orphaned processes consuming CPU and RAM with
no parent.

Root cause: preview.ts never called drainBrowserPool() or killed
tracked ffmpeg processes. The thumbnail browser in studioServer.ts
registered its own competing signal handlers that raced with
preview's shutdown.

Fix:
- Add a central process tracker (processTracker.ts) that registers
  every spawned ffmpeg across engine and producer packages
- Centralize thumbnail browser cleanup via exported
  closeThumbnailBrowser() instead of scattered signal handlers
- Wire preview shutdown to call closeThumbnailBrowser(),
  drainBrowserPool(), and killTrackedProcesses() before closing the
  HTTP server (embedded mode)
- Add killProcessTree() for dev/local modes where Chrome runs in a
  child process tree
- Add startup orphan detection that finds and kills orphaned
  chrome-headless-shell/Puppeteer Chrome processes (PPID=1) from
  previously crashed sessions

Closes #1038
2026-05-22 23:31:00 -04:00
Miguel Ángel f2e2311efd Merge pull request #1012 from heygen-com/fix/portrait-video-bottom-gap
refactor(studio): split oversized files and raise line limit to 600
2026-05-23 04:57:40 +02:00
Miguel Ángel ea4d920589 refactor(studio): split oversized files and raise line limit to 600
Split PlayerControls.tsx into focused sub-components (SeekBar,
WorkAreaOverlay, MuteButton, LoopButton, FullscreenButton,
ShortcutsPanel, SpeedMenu) and extracted seek bar drag/progress
tracking into useSeekBarDrag hook.

Split manualEditsDom.ts patch-builder functions into
manualEditsDomPatches.ts with data-driven helpers to reduce
duplication and complexity.

Extracted per-type reapply helpers from reapplyPositionEditsAfterSeek
and factored out identity-matrix check from
stripGsapTranslateFromTransform.

Raised file-size limit from 500 to 600 lines, removed
.filesize-allowlist.
2026-05-22 22:57:12 -04:00
Miguel Ángel 06e4db8e7b Merge pull request #1036 from heygen-com/feat/registry-parallax-zoom-unzoom
feat(registry): add parallax-zoom and parallax-unzoom components
2026-05-23 01:48:34 +02:00
Miguel ÁngelandKanyini 618ac7f5b3 fix(registry): dark body background eliminates visible grid gaps
The #f6f6f4 off-white background was showing through the 30px grid
gaps and behind translated cards during the zoom/unzoom transitions,
creating visible white strips in the rendered video. Changed to
#1a1a20 (near-black) so gaps read as intentional dark separators.

Also added a .zoom-backdrop div behind the grid in the zoom demo that
fades to the focus card's gold gradient during the transition, covering
any gaps left by sibling cards translating off-screen.

Co-authored-by: Kanyini <onebenson@gmail.com>
2026-05-22 19:42:53 -04:00
Miguel ÁngelandKanyini fa58903eb4 fix(registry): work around CDP subpixel capture artifact
The renderer's Page.captureScreenshot can introduce a 1-2px offset
at viewport boundaries due to compositor subpixel rounding. Grid rows
are now 341px (3×341 + 2×30 = 1083), overflowing the 1080 viewport
by 3px. The overflow is clipped by overflow: hidden, but ensures any
capture offset still sees grid content rather than the body background.

Also removed flex centering from .demo-canvas — unnecessary now that
the grid fills the viewport, and it was a source of non-deterministic
positioning under multi-worker rendering.

Co-authored-by: Kanyini <onebenson@gmail.com>
2026-05-22 19:28:52 -04:00
Miguel ÁngelandKanyini f0b0b977e0 fix(registry): edge-to-edge grid eliminates background bleed
Cards 360×340 with 30px gap = exactly 1920×1080. No body background
visible at any frame. Focus scale drops from 9 to 6 (360×6 = 2160,
still overshoots viewport by 240px).

Co-authored-by: Kanyini <onebenson@gmail.com>
2026-05-22 19:19:29 -04:00
James 258bd6256c chore: release v0.6.37 v0.6.37 2026-05-22 23:17:08 +00:00
JamesandClaude Opus 4.7 e2ad165c6c fix(telemetry): drop unverified vendor rules, fix Codex markers, add Pi
Audit of every detection rule in the registry against actual vendor
source code. Rules that lacked a public-source citation were guesses
and have been removed; surviving rules now all cite the file + line
that emits the marker.

Codex — replace per @magi's investigation:
- Drop CODEX_HOME (config override read at startup, NOT propagated to
  child processes — would miss most Codex invocations).
- Drop CODEX_SANDBOX (macOS Seatbelt only; covered by the others).
- Add CODEX_THREAD_ID (set unconditionally on every spawned shell
  command — codex-rs/protocol/src/shell_environment.rs:6 +
  codex-rs/core/src/unified_exec/process_manager.rs:1010).
- Add CODEX_CI (hardcoded in UNIFIED_EXEC_ENV — process_manager.rs:70).
- Keep CODEX_SANDBOX_NETWORK_DISABLED (default-on sandbox marker —
  codex-rs/core/src/sandboxing/mod.rs:135-138).

Cursor — drop unverified CURSOR_TRACE_ID and CURSOR_AGENT guesses.
Keep TERM_PROGRAM=cursor (set by Cursor's integrated terminal).

Pi — new rule. https://github.com/earendil-works/pi
packages/coding-agent/src/cli.ts:13 unconditionally executes
  process.env.PI_CODING_AGENT = "true";
at module entry, so every subprocess Pi spawns sees this marker.
Same propagation pattern as Hermes.

Removed (no source-cited marker found in this audit):
- aider — verified Aider sets no AIDER_* env vars; only OR_SITE_URL and
  OR_APP_NAME (OpenRouter integration). No reliable marker.
- gemini_cli — GEMINI_SANDBOX/GEMINI_CLI_TRUST_WORKSPACE are conditional
  on CLI flags; no unconditional marker found.
- jules, devin — closed source, no public marker documentation.

These vendors can be re-added later with a source citation; absence
in the registry will silently false-negative (events land in the null
bucket), but won't false-positive on other vendors.

Per @james-russo's review: do source-level research before shipping
detection rules. Memory updated to enforce this for future work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 19:10:30 -04:00
JamesandClaude Opus 4.7 d7ff692f9f refactor(telemetry): address remaining PR #1035 review feedback
Three follow-ups from @miguel-heygen's review:

1. HERMES_QUIET — switch to existence check.
   `env["HERMES_QUIET"] === "1"` was brittle vs. future Hermes changes
   (e.g. if cli.py ever sets it to "true"). The var name itself is
   specific enough that existence is the right signal.

2. CI_PROVIDERS — convert to a discriminated union.
   `mode: "truthy" | "presence"` is stricter than the previous pair of
   optional boolean flags (which allowed entries with neither set).

3. Sandbox detection tests — add coverage.
   - Docker positive: /.dockerenv present → docker.
   - Negative case: plain Linux laptop with no markers → null.

Together with the gVisor 4.4.0 fix in the previous commit, that addresses
all three actionable callouts (the discriminated-union nit was non-blocking
but worth doing while in the file).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 19:10:30 -04:00