Commit Graph
122 Commits
Author SHA1 Message Date
James Russo b05a22e69e feat(producer): add --mode=lambda-local to the regression harness (#913)
* feat(producer): add --mode=lambda-local to the regression harness

Third harness mode that drives the OSS @hyperframes/aws-lambda handler
through the exact event sequence Step Functions produces in
production:

  handler({Action: "plan"})             → planDir tarball on fake S3
  handler({Action: "renderChunk"}) × N  → chunk artifacts on fake S3
  handler({Action: "assemble"})         → final mp4/mov/png-sequence

The S3 client is a filesystem-backed fake (every s3://<bucket>/<key>
URI maps to <tempRoot>/s3/<key>), so the harness exercises the
handler's event-parsing + tar/S3 conventions + dispatch logic on top
of the underlying producer primitives. Regressions in event JSON
shape, S3 key layout, or plan-hash boundary checks now surface in
the same CI run as the in-process and distributed-simulated modes
without paying for a real AWS round-trip.

Deliberately NOT a Docker/RIE invocation — that would gate the
producer test suite on Docker-in-Docker support which most CI
runners lack. Real-ZIP-via-RIE tests live in
packages/aws-lambda/scripts/ (probe:beginframe) and the
maintainer-run smoke.sh.

Wired up via:
  - HarnessMode union extended to include "lambda-local"
  - parseHarnessModeFlag accepts --mode=lambda-local
  - regression-harness.ts dispatches to runLambdaLocalRender for
    the new mode, sharing the distributed-support gate +
    pathology-floor threshold with distributed-simulated mode
  - package.json scripts: test:lambda-local + docker:test:lambda-local
  - producer.devDependencies += @hyperframes/aws-lambda (workspace)
  - producer/tsconfig.json gains path mappings to self so the type
    cycle through aws-lambda's source resolves at typecheck time
    without needing producer to be pre-built

Tests: 3 new unit tests on parseHarnessModeFlag + resolveMinPsnrForMode
cover the new mode. End-to-end PSNR contract still runs through
Dockerfile.test (manual + CI).

* refactor(producer): /simplify pass on lambda-local harness imports

Three small cleanups on top of the lambda-local harness:

  - Drop the unused createReadStream import + its `void` workaround
    comment. The aws-lambda handler's tar / S3 transport pulls
    createReadStream from its own imports; this file never references
    it directly.

  - Hoist the dynamic `await import("node:fs")` calls for
    writeFileSync out of FilesystemBackedFakeS3.send into the static
    import block. Repeated PutObject calls don't need to repay the
    dynamic-import cost.

  - Hoist the dynamic `await import("@hyperframes/aws-lambda")` call
    for untarDirectory similarly. Drops the now-redundant duplicate
    aws-lambda import statement.

The PutObject body branch also collapses: `body instanceof Buffer`
and `typeof body === "string"` both call writeFileSync identically,
so they share one branch.

No behavior changes.

* fix(producer): lazy-import lambda-local harness module

The static import of regression-harness-lambda-local.ts pulled
@hyperframes/aws-lambda (and its @aws-sdk/* + @sparticuz/chromium
transitive deps) at module-load time. Dockerfile.test only copies
the producer's own files into the container, so aws-lambda's src
isn't present at runtime — and even `--mode=in-process` failed:

  Error [ERR_MODULE_NOT_FOUND]: Cannot find module
  '/app/packages/producer/node_modules/@hyperframes/aws-lambda/src/index.ts'
  imported from /app/packages/producer/src/regression-harness-lambda-local.ts

Load the module on demand instead. `--mode=lambda-local` callers
pay the import cost; the existing in-process and distributed-
simulated modes don't.

* fix(producer): address PR review on lambda-local harness

Three review items from Vai:

  - `Config.width`/`Config.height` are now plumbed through
    RunLambdaLocalInput rather than hardcoded inside
    runLambdaLocalRender. Lambda-local's whole point is to catch
    event-shape drift; if the handler ever starts honouring
    Config.width/height (e.g. for canvas sizing), having those
    values flow from the caller means the harness sees what the
    fixture authored. The interface change makes the eventual
    upgrade-to-real-fixture-resolution a one-line dispatch swap.

  - Drop the dead `export type { Fps }` and its unused import
    from @hyperframes/core. The module never re-exports it.

  - The dispatch site in regression-harness.ts now passes 1920×1080
    explicitly with a comment marking it as a placeholder until
    the harness compiles the composition HTML up-front to surface
    the authored data-width/data-height. distributed-simulated
    mode uses the same placeholder internally, kept for parity.

No behavior change in the existing modes; lambda-local now has a
clear extension point for honouring fixture dimensions.
2026-05-17 14:04:49 -04:00
Miguel ÁngelandClaude Sonnet 4.6 78fce8bd8a chore: release v0.6.18
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 15:32:53 +00:00
Miguel ÁngelandClaude Sonnet 4.6 3f976d454c chore: release v0.6.17
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-17 15:15:54 +00:00
James b30fd29695 chore: release v0.6.16 2026-05-17 08:20:08 +00:00
James 5f8391bd96 chore: release v0.6.15 2026-05-16 23:30:38 +00:00
Miguel Ángel 1fca35b625 chore: release v0.6.14 2026-05-16 13:02:23 -07:00
Miguel ÁngelandClaude Sonnet 4.6 883260aae3 chore: release v0.6.13
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 16:35:46 +00:00
Miguel Ángel 2355d505e1 chore: release v0.6.12 2026-05-16 00:48:57 -07:00
Miguel Ángel 4212a28312 chore: release v0.6.11 2026-05-15 23:43:21 -07:00
Miguel Ángel d3c32a0b4d chore: release v0.6.10 2026-05-15 21:25:26 -07:00
Miguel Ángel 82c9b6b5ea chore: release v0.6.9 2026-05-15 19:45:01 -07:00
Miguel Ángel 4b501762e4 chore: release v0.6.8 2026-05-15 19:20:28 -07:00
Miguel Ángel e8e2e81730 chore: release v0.6.7 2026-05-14 21:54:56 -07:00
James 415ad8b5a6 feat(producer): add harness mode --mode=distributed-simulated 2026-05-14 04:27:12 +00:00
James 91a91f66ba feat(producer): export distributed render primitives 2026-05-14 03:40:44 +00:00
terencecho 27ae55a5c7 chore: release v0.6.6 (#818) 2026-05-13 17:01:15 -07:00
Miguel Ángel 7703122a4d chore: release v0.6.5 2026-05-13 13:40:37 -07:00
Miguel Ángel 9fe356be14 chore: bump version to 0.6.4 2026-05-13 00:49:09 -07:00
Miguel Ángel 636db23197 chore: bump version to 0.6.3 2026-05-13 00:46:36 -07:00
James 067bc722e3 fix(deps): align @types/node + esbuild + tsx across workspace
The Windows install failures (`ENOENT: failed copying files from cache to
destination for package @types/node` / `esbuild`) are caused by bun creating
workspace-scoped nested installs under
`node_modules/@hyperframes/<pkg>/node_modules/...`. Those nested paths only
exist because each workspace package pinned a different `@types/node` /
`esbuild` major:

- root: `@types/node ^25.0.10`, core: `^24.10.13`, cli/engine/producer: `^22`
- core/cli: `esbuild ^0.25.x`, producer: `^0.27.2`

Each major-version gap forces bun to install a workspace-scoped copy in a
deep `node_modules/@hyperframes/<pkg>/node_modules/<dep>/node_modules/...`
tree that bun can't reliably materialize on Windows GHA runners. Aligning
versions lets bun dedup to a single root-hoisted install per dep, and the
nested workspace block disappears from `bun.lock` entirely.

## Alignment

- `@types/node` → `^25.0.10` across root, core, cli, engine, producer
- `esbuild` → `^0.25.12` across cli, core, producer
- `tsx` → `^4.21.0` across producer (matches root + core)

## Source-level v25 compat (already in this PR)

@types/node v25 declares `File` as an interface (not a class) and exposes a
conditional global where `FormData.entries()` narrows to `[string, string]`
when an `onmessage` global is in scope. `packages/core/src/studio-api/routes/files.ts`'s
`value instanceof File` check was relying on the v24 class declaration —
already cast the iterator to `Iterable<[string, FileLike | string]>` in the
prior commit.

Two more v25 source fixes here:
- `packages/cli/src/commands/init.ts`
- `packages/cli/src/whisper/normalize.ts`

`Dirent.path` was removed in @types/node v25 (deprecated alias for
`parentPath` since Node 20.12). Drop the `?? e.path` fallback.

## Verification

Both install layouts now build clean end-to-end:

- `bun install` (isolated, default): full build green, 853 core tests pass,
  typecheck green across all 7 packages
- `bun install --linker=hoisted` (Windows CI): same result
- `bun.lock` no longer contains any `@hyperframes/<pkg>/<dep>` nested
  workspace entries — 70+ lines of nested install blocks gone
2026-05-13 03:35:47 +00:00
Miguel ÁngelandClaude Opus 4.6 86c5fd28e8 chore: release v0.6.2
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 01:35:21 +00:00
Miguel ÁngelandClaude Opus 4.6 82fd2967c4 chore: release v0.6.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-13 00:27:13 +00:00
Miguel Ángel 91bdffffe6 fix(ci): scope LOC check to studio, split useTimelinePlayer + hyperframes-player under 500 LOC (#750)
* refactor: split useTimelinePlayer.ts and hyperframes-player.ts into focused modules (<500 LOC each)

* fix(ci): scope 500 LOC check to packages/studio, add allowlist for grandfathered files

* feat(cli): Linux ARM64 support — auto-install Chromium on DGX Spark / GB10 / Jetson

Chrome Headless Shell has no Linux ARM64 binary. On arm64 Linux:
- Detects the platform automatically
- Tries to auto-install system Chromium via apt-get (works on Ubuntu/Debian ARM)
- Falls back to clear manual instructions with exact commands
- 'hyperframes browser ensure' guides through the setup interactively
- After setup, all render commands work without any flags

* fix(ci): disable Windows Defender real-time monitoring to prevent EPERM builds

Path exclusions are insufficient — Defender re-scans new files created
during bun install before the exclusion takes effect. Disable real-time
monitoring for the entire job duration instead (standard CI practice).

* refactor(studio): split all files >500 LOC + extract useToast, delete allowlist

All 11 large files split into focused modules under 500 LOC.
App.tsx extracted toast logic into useToast hook (493 LOC now).
.filesize-allowlist deleted — no longer needed.

* fix: remove unused imports from split files, extract useToast from App.tsx

App.tsx: 504 → 493 lines (toast logic extracted to useToast hook)
timelineDOM.ts: remove unused imports from re-export pattern
MotionPanel.tsx: remove unused clampStudioCustomEasePoints import
studioMotionOps.ts: remove unused StudioGsapMotionDirection import

* fix(ci): use Set-MpPreference to fully disable Windows Defender (both jobs)

* fix(producer): use node --experimental-strip-types instead of tsx for build:fonts

Eliminates the tsx binary dependency that Windows Defender locks during
bun install, causing EPERM errors. Node 22.6+ strips TypeScript types
natively with no external binary.

* chore: remove .filesize-allowlist — App.tsx is now 493 lines (<500)

* fix(ci): disable Windows Defender before checkout to prevent all EPERM races

* fix(producer): skip build:fonts if fontData.generated.ts already exists

The generated file is tracked in git, so CI doesn't need to regenerate
it. This avoids @fontsource/inter node_modules access on Windows which
triggers EPERM from Defender scanning during bun install.
2026-05-13 01:48:12 +02:00
Miguel Ángel e25a3b3a4b chore: release v0.6.0 2026-05-12 11:28:30 -07:00
Miguel Ángel 57ea5641fe chore: release v0.5.7 2026-05-10 18:34:43 +00:00
Miguel Ángel bd7bbae42d chore: release v0.5.6 2026-05-10 05:40:30 +00:00
Miguel ÁngelandClaude Opus 4.6 ae343bfdc8 chore: release v0.5.5
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-08 15:00:29 +00:00
Miguel Ángel 8de7ad7f61 chore: release v0.5.4 2026-05-07 23:22:15 -07:00
Miguel Ángel aa524f43c9 chore: release v0.5.3 2026-05-06 11:45:59 -07:00
Miguel Ángel 7174c4cdcd chore: release v0.5.2 2026-05-06 10:27:07 -07:00
Miguel Ángel 64f3a4ed5f chore: release v0.5.1 2026-05-06 10:14:00 -07:00
James 94b8acf3b0 chore: release v0.5.0 2026-05-06 16:12:18 +00:00
James 584627546a chore: release v0.4.45 2026-05-05 04:41:23 +00:00
Miguel Ángel 20895eecdd chore: release v0.4.44 2026-05-04 14:37:16 -07:00
Miguel Ángel 1d15845a13 chore: release v0.4.43 2026-05-03 22:53:04 -07:00
Miguel Ángel db9cffb203 chore: release v0.4.42 2026-05-01 21:35:29 -07:00
Miguel Ángel 8b8dcf543e chore: release v0.4.41 2026-04-30 22:52:55 -04:00
Miguel Ángel 4fa2633e82 chore: release v0.4.40 2026-04-30 13:04:39 -04:00
Miguel Ángel 2045e21f70 chore: release v0.4.39 2026-04-30 01:18:15 -04:00
Miguel Ángel 4ab304e22f chore: release v0.4.38 2026-04-29 21:10:23 -04:00
Miguel Ángel b9a9998ff0 chore: release v0.4.37 2026-04-29 16:02:09 -04:00
Miguel Ángel 857b870459 chore: release v0.4.36 2026-04-29 14:55:45 +00:00
Miguel Ángel eb065260dc chore: release v0.4.35 2026-04-29 13:47:22 +00:00
Miguel Ángel 31c4f974ea chore: release v0.4.34 2026-04-28 23:39:28 +00:00
Miguel Ángel 46a4cacea2 chore: release v0.4.33 2026-04-28 12:45:02 -04:00
Miguel Ángel 37827cdaec chore: release v0.4.32 2026-04-27 21:18:36 -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 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
Miguel Ángel 970367f5e6 chore: release v0.4.29 2026-04-25 19:11:53 -04:00