Commit Graph
535 Commits
Author SHA1 Message Date
Miguel Ángel 9dc17ae30d fix: scope studio playback shortcuts 2026-04-28 22:32:23 -04:00
Miguel Ángel a45f900af7 feat: add Studio NLE playback controls 2026-04-28 17:51:38 -04: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
Miguel Ángel 37827cdaec chore: release v0.4.32 v0.4.32 2026-04-27 21:18:36 -04:00
Miguel Ángel 8918ba748d docs: add Video Editor Cheatsheet guide
Fast reference for non-technical video editors and creatives — covers the
fast loop, terminal shortcuts, Studio keyboard shortcuts, CLI commands,
timing attributes, render presets, publish/share, and quick fixes.
2026-04-28 00:57:01 +00: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 b0f2c81cfd Merge pull request #519 from yusoufu/feat/transparent-video-export
feat(producer): true alpha output for webm, mov, and png-sequence
2026-04-28 00:30:08 +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
Miguel Ángel 5397431d00 Merge pull request #500 from heygen-com/fix/animation-map-package-resolution
fix(skills): load helper dependencies outside repo installs
2026-04-27 22:12:40 +02:00
Miguel Ángel 6d4b091cc0 Merge pull request #520 from heygen-com/docs/alpha-prs-target-next
docs: clarify alpha PR target branch
2026-04-27 22:12:07 +02: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 2c9aee2b8e docs: clarify alpha PR target branch 2026-04-27 16:00:51 -04:00
Miguel Ángel 35b7043efa fix: harden skill dependency bootstrap 2026-04-27 15:57:28 -04: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
Miguel Ángel 2935be6bf6 Merge pull request #505 from afanty2021/main
fix: resolve build race condition by ensuring core builds first
native-renderer-demo-v1 v0.0.0-native-renderer-demo
2026-04-27 05:59:29 +02:00
afanty2021andClaude Opus 4.7 1f2ddc347a fix: resolve build race condition by ensuring core builds first
Change build order from concurrent to staged to prevent @hyperframes/engine
from starting TypeScript compilation before @hyperframes/core generates
src/generated/runtime-inline.ts.

This fixes intermittent "Cannot find module './generated/runtime-inline'"
errors when running bun run build.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-27 11:34:20 +08:00
Miguel Ángel 6e19d88e5f chore: release v0.4.31 v0.4.31 2026-04-26 19:41:11 -04:00
Miguel Ángel 4af64d8adc Merge pull request #504 from heygen-com/fix/codex-plugin-preview-handoff
docs(skills): clarify preview handoff URL
2026-04-27 01:39:56 +02:00
Miguel Ángel 343bb8ea81 docs(skills): clarify preview handoff URL 2026-04-26 19:28:39 -04:00
Miguel Ángel 9588a6dc06 fix: load skill helper dependencies 2026-04-26 02:29:52 -04:00
James 2b836cc224 chore: release v0.4.30 v0.4.30 2026-04-26 05:17:13 +00:00
Miguel Ángel 9832ce6a6d Merge pull request #499 from heygen-com/fix/snapshot-runtime-path 2026-04-26 07:09:45 +02: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 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 v0.4.28 2026-04-25 17:20:25 -04:00
Ular Kimsanov bdc1012b9a Merge pull request #496 from heygen-com/fix/docs-claude-design-links
fix(docs): use claude.ai/design link, remove raw download option
2026-04-25 17:09:21 -04:00
ukimsanovandClaude Opus 4.6 67ed767641 fix(docs): use claude.ai/design link, remove raw download option
- Link to claude.ai/design instead of claude.ai
- Remove raw.githubusercontent download links (just GitHub with ↓ button)
- Fix stale SKILL.md link text in prompting guide

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-25 17:02:58 -04:00
Miguel Ángel a65c0ce22e chore: release v0.4.27 v0.4.27 2026-04-25 16:53:48 -04:00
Ular Kimsanov 9322ff9c74 refactor: move Claude Design instructions from skills/ to docs/ (#495) 2026-04-25 22:50:16 +02: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 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 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 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
Miguel Ángel ef45f653ff ci: guard release channel publishing (#488) 2026-04-25 06:04:10 +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
Mu-Tsun Tsai bdc7061f98 fix(cli): shut down preview embedded-mode server on Ctrl+C (#483)
* fix(cli): shut down preview embedded-mode server on Ctrl+C

runEmbeddedMode awaited a promise that never resolved, relying on Node
to exit on SIGINT. Two things kept that from working in practice:

1. @hono/node-server's listening handle keeps the event loop alive after
   the signal fires, so the process hangs even when SIGINT does arrive.
2. On Windows, some terminals (Git Bash / MSYS) don't deliver Ctrl+C to
   the Node process as a SIGINT at all — the keystroke is eaten at the
   TTY layer.

Register a SIGINT/SIGTERM handler that closes the server explicitly and
resolves the promise, with a 2s force-exit fallback. On Windows, run a
readline interface on stdin to catch Ctrl+C at the TTY and re-emit it
as SIGINT so the same handler fires.

Print "Shutting down studio..." as soon as the signal is received —
server.close() can take a second or two to drain keep-alive connections
and an unmarked pause reads as "stuck".

Exit code 0 because a user-initiated Ctrl+C isn't an error; non-zero
codes make pnpm print ELIFECYCLE right where the user just asked the
process to stop.

* fix(cli): close readline interface in shutdown to honour exit-code intent

After the SIGINT handler removes itself, the Windows readline interface
is still alive and listening. A second Ctrl+C during the 2s grace
period would re-emit SIGINT with no registered handler, triggering
Node's default exit-130 behaviour and contradicting the explicit
exit(0) we chose for clean teardown.

Hoist the readline handle out of the win32 branch so shutdown can
close it before invoking server.close(). Also pass the signal name
to process.emit("SIGINT", "SIGINT") to match Node's ProcessEvents
overload — runtime behaviour is unchanged.
2026-04-25 05:49:26 +02:00