1094 Commits
Author SHA1 Message Date
Miguel Ángel 27efcd0f80 chore: release v0.6.22 v0.6.22 2026-05-18 14:23:43 -04:00
Miguel Ángel 4c29b43b85 Merge pull request #935 from heygen-com/worktree-fix+canvas-zoom-improvements
fix(studio): canvas zoom improvements — zoom to cursor, reset button, border fix
2026-05-18 20:07:20 +02:00
Miguel Ángel e25bcf989a fix(studio): address PR review — split pan clamp, pin invariant, drop dead guard
- Split pan clamping: clampPreviewPan (drag/wheel-pan) stays narrow
  (Math.max(0,...) — content pins to center when smaller than viewport).
  New clampPreviewPanForZoom (Math.abs) gives the wide range only to
  cursor-anchored zoom, preventing middle-mouse drag from pushing content
  off-screen at low zoom levels.

- Pin transform-origin invariant: comment on the stage div noting that
  resolvePreviewWheelZoom cursor math depends on center-center pivot.
  New test verifies a non-center cursor keeps the same content-space
  point fixed across a zoom step.

- Remove dead Math.abs(oldScale) > 1e-6 guard — oldScale >= 0.25 always
  (clampPreviewZoomPercent floors at MIN_PREVIEW_ZOOM_PERCENT = 25).

- Skip setSettledZoom re-render when the value didn't change — uses a
  functional updater that returns the previous state object when all
  three fields match, avoiding a React re-render cascade through Player.
2026-05-18 14:04:53 -04:00
Miguel Ángel 3af7f1cba9 Merge pull request #934 from heygen-com/feat/texture-caption-any-texture
feat(registry): make caption-texture-lava work with any texture
2026-05-18 20:00:48 +02:00
Miguel Ángel 0150a0a1b4 fix(studio): canvas zoom improvements — zoom to cursor, reset button, border fix
- Zoom anchors to cursor position instead of always zooming toward center.
  The resolvePreviewWheelZoom function now accepts cursorX/cursorY (offset
  from viewport center) and uses the standard zoom-to-point formula to
  adjust pan so the content point under the cursor stays fixed.

- Add visible "Reset" button (bottom-right) showing current zoom % when
  not at fit zoom. Driven by settledZoom state that updates after the
  200ms settle debounce, so no re-renders during active zoom gestures.

- Fix border-expands-inward bug: scaleIframeToFit in the player now uses
  offsetWidth/offsetHeight instead of getBoundingClientRect. The latter
  returns values inflated by ancestor CSS zoom, causing double-scaling
  that made the iframe appear smaller than its container.

- Fix zoom HUD appearing during pan: split applyZoom (shows HUD) from
  applyPan (silent) so trackpad/middle-mouse panning no longer flashes
  the zoom percentage overlay.

- Fix stale closure performance regression: replace stageSize in effect
  dependency arrays with stageSizeRef pattern. The old deps caused wheel
  and pointer handlers to re-register on every viewport resize.

- Widen pan clamp range (Math.abs instead of Math.max(0,...)) so content
  can float within the viewport when zoomed below fit — required for
  zoom-to-cursor to work correctly at any zoom level.

Closes #900
2026-05-18 13:24:17 -04:00
Miguel Ángel 09af2f9cc1 feat(registry): rename caption-texture-lava to caption-texture with multi-texture support
Rename component to caption-texture and bundle 6 popular textures
(lava, marble, metal, wood, concrete, rock). The texture is configurable
via the texture composition variable (default: lava).

Usage: hyperframes render --variables '{"texture":"marble-012"}'

Tested: lava, marble-012, metal-046-b all render correctly with
distinct visual patterns.
2026-05-18 12:40:48 -04:00
Miguel Ángel 8163f38077 chore: release v0.6.21 v0.6.21 2026-05-18 11:29:01 -04:00
Miguel Ángel 4b6ed3197f Merge pull request #928 from heygen-com/worktree-feat+registry-us-map
feat(registry): add us-map choropleth block
2026-05-18 17:17:09 +02:00
Miguel Ángel 9f18425eae fix(lint): detect Three.js loaded via importmap or ES module import
The missing_three_script rule only checked <script src> attributes
for Three.js. Now also detects:
- importmap entries defining "three"
- ES module import/from statements referencing "three"

Closes #931
2026-05-18 11:06:51 -04:00
Miguel Ángel 15c2d7644d ci: re-trigger regression shards 2026-05-18 10:42:16 -04:00
Miguel Ángel 4bf2fa5cd1 fix: revert flattenInnerRoot, use host-level authored-id + count-based rebind
Three changes to fix regression failures without breaking baselines:

1. Revert flattenInnerRoot in producer — use the original innerHTML
   inlining that preserves the existing DOM structure. Instead, set
   data-hf-authored-id on the HOST element so the scoped proxy can
   still rewrite #id selectors for sub-composition scripts.

2. Revert compiled.html baselines to main (no DOM structure changes).

3. Use timeline-count comparison instead of poll duration to decide
   whether to call __hfForceTimelineRebind. Compare timeline count
   before vs after the poll — rebind only when new timelines appeared
   during polling. This correctly identifies async compositions
   regardless of fetch speed, while leaving sync compositions
   untouched.
2026-05-18 10:20:17 -04:00
Miguel Ángel 0ff6296d64 fix(core): remove late-bind polling from runtime — engine handles it
The setInterval-based late-bind polling in init.ts caused visual
regressions across all style-prod tests. Even with the sawMissing
guard, the mere presence of the interval registration altered
event loop timing enough to shift rendered frames.

The engine's pollSubCompositionTimelines + conditional
__hfForceTimelineRebind already handles async timeline detection
for renders. The runtime only needs to expose the rebind hook —
it shouldn't poll on its own.

For studio preview of async compositions, the engine's rebind
call (via __hfForceTimelineRebind) is the correct mechanism.
2026-05-18 05:50:08 -04:00
Miguel Ángel d10b2f4ded fix(core): only rebind timelines when late arrivals were actually detected
The late-bind polling was unconditionally rebinding on its first
check even when all timelines were already present, causing visual
regressions across style-prod tests. Now tracks sawMissing flag —
only rebinds if the poll previously detected missing timelines that
subsequently appeared. Compositions with synchronous timeline
registration exit the poll immediately with no side effects.
2026-05-18 05:24:33 -04:00
Miguel Ángel 04c35ce24c fix: regression fixes — conditional rebind + updated compilation baselines
1. Only call __hfForceTimelineRebind() when the timeline poll actually
   had to wait (pollDuration > 2 intervals). For compositions with
   synchronous timeline registration, the rebind was unnecessary and
   shifted render timing, causing PSNR regressions in chat and
   gsap-letters-render-compat.

2. Regenerate compiled.html baselines for missing-host-comp-id and
   overlay-montage-prod to match the new flattenInnerRoot behavior
   (data-composition-id stripped from inlined inner roots, replaced
   with data-hf-authored-id).

3. Add late-bind polling to runtime init.ts — after external
   compositions load, poll for 5s to detect async timelines that
   register after initial binding (e.g. from fetch callbacks).
2026-05-18 03:46:58 -04:00
Miguel Ángel 0f1c64dcae fix: address review feedback — observability, dedup, query-strip, catalog
Review items addressed:

1. Mirror video-failure warning in beginFrame path (was screenshot-only)
2. Fix resolveProjectRelativeSrc escape-fallback to use query-stripped
   cleanSrc instead of raw src for the normalize/strip arm
3. Export prepareFlattenedInnerRoot from @hyperframes/core/compiler and
   consume in the producer instead of duplicating the implementation
4. Use typed Window cast instead of (window as any) for __hfForceTimelineRebind
5. Regenerate docs/public/catalog-index.json with all 6 map blocks
6. Restore Maps nav group in docs.json (catalog generator had merged
   them into Data)
2026-05-18 01:41:15 -04:00
Miguel Ángel cf2addfb92 chore: remove accidentally committed producer node_modules 2026-05-18 01:28:31 -04:00
Miguel Ángel 8b4c994611 style: format us-map and world-map after stagger change 2026-05-18 01:24:30 -04:00
Miguel Ángel fe32622748 docs: point us-map preview to new filename to bypass CDN cache 2026-05-18 01:21:35 -04:00
Miguel Ángel 4b9abaaf6f fix: deterministic stagger, lint importmap/module, cache-bust previews
- Replace from:"random" with from:"center" stagger in us-map,
  world-map, spain-map — random stagger is non-deterministic across
  parallel render workers, causing visual jumps at chunk boundaries.

- Exempt type="importmap" and type="module" inline scripts from the
  invalid_inline_script_syntax lint rule. The rule used new Function()
  to parse, which rejects import statements and JSON import maps.
  Closes #929.

- Cache-bust all map MDX preview video URLs after re-rendering with
  the deterministic stagger fix.
2026-05-18 01:18:24 -04:00
Miguel Ángel 8777c18870 docs: cache-bust us-map preview video URL 2026-05-18 01:10:19 -04:00
Miguel Ángel 27c8b68bf5 docs: switch map MDX preview URLs to S3 production paths
Assets are uploaded to static.heygen.ai — switch from local
/images/ paths back to the canonical S3 URLs for production docs.
2026-05-18 00:55:31 -04:00
Miguel Ángel 8525bfdec9 fix(engine): strip query strings from video src when resolving on disk
resolveProjectRelativeSrc now strips query parameters (e.g. ?v=4)
before joining with the project directory. Browsers ignore query
strings when loading local files, but the filesystem resolver was
looking for the literal path including the query — causing video
extraction to silently skip the file and render frozen first frames.
2026-05-18 00:52:03 -04:00
Miguel Ángel b8715ce168 fix(engine): gracefully handle missing or errored video sources during render
Previously, a missing video file (404) caused the renderer to hard-fail
after a 45-second timeout waiting for readyState >= 2. Now:

1. pollVideosReady treats errored videos (v.error set or
   NETWORK_NO_SOURCE) as ready, so 404'd sources don't block
2. Screenshot mode downgrades the video timeout from a throw to a
   console.warn listing affected sources, then continues rendering
3. The composition renders with the missing video as a blank area
   instead of failing entirely
2026-05-18 00:45:11 -04:00
Miguel Ángel 2c84c9a55d fix(engine,core): wait for async timelines and force rebind before capture
Two fixes for compositions that register timelines after async data
loading (e.g. fetch for TopoJSON map data):

1. engine/frameCapture: remove the hosts.length <= 1 early return
   so the timeline readiness poll runs for ALL compositions, not just
   multi-composition galleries. Single-composition pages with async
   setup were silently skipped.

2. core/runtime/init: expose window.__hfForceTimelineRebind() which
   resets childrenBound and re-runs bindRootTimelineIfAvailable().
   The renderer calls this after all timelines are confirmed present,
   ensuring the root player discovers late-registered timelines from
   fetch callbacks.

Without these fixes, compositions using fetch() to load data at
runtime would render blank frames because the root player bound
timelines before the async setup completed, and seek() never
reached the unbound composition timeline.
2026-05-18 00:39:10 -04:00
Miguel Ángel 5aff328a9b fix(producer): preserve inner root element when inlining sub-compositions
The producer's inlineSubCompositions was not passing flattenInnerRoot,
causing sub-composition inner root elements to be unwrapped during
compilation. Scripts using #id selectors (rewritten to
[data-hf-authored-id] by the scoping proxy) could not find their DOM
root because the authored-id attribute was never set.

The core bundler (bundleToSingleHtml) already passed flattenInnerRoot
correctly. This aligns the producer's render compilation with the
same behavior: clone the inner root, strip timing/composition attrs,
replace id with data-hf-authored-id, and mark with
data-hf-inner-root.
2026-05-18 00:27:20 -04:00
Miguel Ángel 3482d163b2 fix(engine): poll for sub-composition timeline readiness before capture
The renderer now waits for all sub-composition timelines to be
registered in window.__timelines before starting frame capture.
Previously only window.__hf root readiness was checked, causing
blank frames when sub-compositions use async data loading (fetch)
or when the headless renderer starts capturing before scripts
complete.

Adds pollSubCompositionTimelines() to both screenshot and
beginFrame render paths, with a diagnostic warning listing which
composition IDs are missing if the timeout expires.
2026-05-18 00:01:54 -04:00
Miguel Ángel ae1716d4c1 feat(registry): add spain-map block + fix MDX preview paths
New block: spain-map — animated Spain choropleth by autonomous
community using D3 conic conformal projection with GDP per capita
data and red-to-amber color scale.

Also switches all map MDX preview URLs from S3 to local paths
so they render in mintlify dev without needing S3 upload first.
2026-05-17 23:25:47 -04:00
Miguel Ángel dba158dfc1 feat(registry): add maps section with 4 new map blocks + docs
New blocks: world-map (D3 Natural Earth choropleth), us-map-bubble
(proportional city markers), us-map-hex (hexagonal tile grid),
us-map-flow (animated connection arcs between cities).

All blocks share the same dark theme and are composable — layer
bubble or flow on top of the choropleth via track indexes.

Adds "Maps" section to the catalog docs with MDX pages for all 5
map blocks (including the us-map from the previous commit).
2026-05-17 23:16:41 -04:00
Miguel Ángel b443e7e076 feat(registry): add us-map choropleth block
Animated US population density choropleth using D3 geoAlbersUsa
projection with TopoJSON. Includes staggered state reveals, label
fade-ins, gradient legend, and highlight pulses on densest states.
2026-05-17 23:03:35 -04:00
Miguel Ángel 3ec0aa456f docs: point gradient-fill preview to v3 filename 2026-05-17 21:34:24 -04:00
Miguel Ángel 0be66f9446 fix(registry): replace gradient-fill with Siri-style rainbow shimmer 2026-05-17 21:31:52 -04:00
Miguel Ángel 693876ed0e docs: cache-bust preview video URLs for updated captions
Upload re-rendered videos with -v2 filenames to bypass CloudFront
immutable cache. Replace gradient-fill with improved version from
sandbox composition.
2026-05-17 21:24:28 -04:00
Miguel Ángel 5fbbc0ce5f docs: point weight-shift preview to v2 filename to bypass CDN cache 2026-05-17 21:11:19 -04:00
Miguel Ángel 5beeb4227e Merge pull request #927 from heygen-com/fix/caption-polish
fix(registry): polish caption timing and add highlight style
2026-05-18 03:06:57 +02:00
Miguel Ángel c54ebd7880 docs: cache-bust preview video URLs for updated captions 2026-05-17 21:05:33 -04:00
Miguel Ángel d8b98cf9ab chore: update preview cache-bust versions 2026-05-17 20:44:07 -04:00
Miguel Ángel c8e8fdcf6d fix(producer): fetch missing font weights from Google Fonts at render time
The deterministic font system now supplements its embedded font bundle
with Google Fonts fetches for any weights not in the pre-bundled set.
This fixes compositions that request font weights (e.g. Montserrat 300)
not included in the CANONICAL_FONTS faces array — previously those
weights were silently dropped, causing invisible text in renders.

Also replaces caption-glitch-rgb and caption-weight-shift with improved
versions from avatar preview compositions, adapted to 1920x1080 with
standard demo transcript.
2026-05-17 20:41:30 -04:00
James Russo 4f274d3605 Merge pull request #920 from heygen-com/chore/aws-lambda-publish-ready
chore(lambda): publish-readiness for @hyperframes/aws-lambda
2026-05-17 19:41:04 -04:00
Miguel Ángel c3c2129d17 fix(registry): use improved highlight caption with gradient glow 2026-05-17 19:39:33 -04:00
Miguel Ángel 0580783c93 fix(registry): load full Montserrat weight range for weight-shift 2026-05-17 19:32:18 -04:00
Miguel Ángel f23dd4b541 fix(registry): slow down matrix-decode scramble and extend hold times 2026-05-17 19:27:07 -04:00
Miguel Ángel 4e883e20f8 fix(registry): remove caption-typewriter component 2026-05-17 19:24:26 -04:00
James 187dfd5b6c fix(producer): indirect lambda-local import path so tsc can't resolve it
The tsconfig `exclude` list isn't enough to keep producer's tsc emit pass
from pulling `regression-harness-lambda-local.ts` (and its
`@hyperframes/aws-lambda` static imports) into the program — tsc still
statically resolves the path in
`await import("./regression-harness-lambda-local.js")` from
`regression-harness.ts`, walks into the excluded file, and fails on
the missing aws-lambda type declarations.

Reproduction (clean workspace, no aws-lambda dist yet, mirrors CI):

  rm -rf packages/{aws-lambda,producer,core}/dist
  bun run build
  # @hyperframes/producer build: src/regression-harness-lambda-local.ts(36,70):
  # error TS2307: Cannot find module '@hyperframes/aws-lambda' or its
  # corresponding type declarations.

Fix: route the dynamic import path through a top-level string constant
so tsc can't statically resolve the target. tsc keeps the type-only
imports (`RunLambdaLocalRender` from the no-aws-lambda types file) and
treats the dynamic-import target as opaque. `tsx` resolves the path
normally at runtime, so `--mode=lambda-local` is unchanged.
2026-05-17 23:11:45 +00:00
Miguel Ángel 20a6ff6505 Merge pull request #925 from heygen-com/fix/regenerate-style-baselines
test: regenerate style-1-prod and style-12-prod baselines
2026-05-18 01:08:38 +02:00
James 6935eaabc4 chore(lambda): bump initial version to 0.6.20 + add to set-version
Two follow-ups to keep the new package in lockstep with the rest of the
@hyperframes/* release cadence from day one:

- Bump packages/aws-lambda/package.json version 0.6.18 → 0.6.20 so it
  matches what main released while this PR was in review. Without this,
  the package would land below the rest of the lockstep and the next
  release-bump would jump aws-lambda from 0.6.18 → 0.6.21 in one step.

- Add packages/aws-lambda to PACKAGES in scripts/set-version.ts so the
  next `chore: release vX.Y.Z` commit bumps aws-lambda alongside the
  other publishable packages. Without this, set-version silently skips
  aws-lambda — package.json stays frozen, pnpm publish would re-publish
  the same version on every release, and the npm-view precheck in
  publish.yml would skip-with-success and never actually push a new
  version of the package.
2026-05-17 23:06:19 +00:00
Miguel Ángel 47c520d02e fix(registry): polish caption timing and add highlight style
- clip-wipe: slower reveal (0.3s), longer hold, smoother exit
- glitch-rgb: 2.5x larger RGB split, stronger scanlines, more dramatic jitter
- gradient-fill: smoother word transitions (0.15s), longer exit
- typewriter: extended group hold times so text lingers on screen
- weight-shift: per-word font-weight animation (200→900), was broken
  with only line-level shift that never triggered on single-line groups
- Add caption-highlight: red background sweep behind active word (TikTok-style)
- Re-rendered and uploaded preview videos for all 6 components
2026-05-17 18:42:17 -04:00
Miguel Ángel 6c533c0b0f chore: release v0.6.20 v0.6.20 2026-05-17 18:07:59 -04:00
Miguel Ángel 8ffbfc3aa7 fix(registry): use project-root-relative path for lava texture mask 2026-05-17 18:05:49 -04:00
Miguel ÁngelandClaude Sonnet 4.6 4d403b0d73 test: regenerate style-1-prod and style-12-prod baselines in Docker
Sub-comp visibility fix (PR #918) changed rendered output for these two
tests but the baselines on main were stale. Regenerated inside
Dockerfile.test to match CI's Chrome + ffmpeg build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 22:03:17 +00:00
Miguel Ángel 04aa6a644f chore: release v0.6.19 v0.6.19 2026-05-17 17:55:32 -04:00