Commit Graph
6 Commits
Author SHA1 Message Date
James a18fc04bf4 fix(producer): break aws-lambda↔producer build cycle for lambda-local harness
The aws-lambda publish-readiness changes earlier in this PR moved
aws-lambda's types from `./src/index.ts` → `./dist/index.d.ts`. That
flipped producer's emit pass from "always works" to "needs aws-lambda
built first," because producer's `regression-harness-lambda-local.ts`
imports `@hyperframes/aws-lambda{,/handler}`. aws-lambda's own emit
pass in turn imports `@hyperframes/producer{,/distributed}` → circular
build dependency, so neither side can emit declarations in a single
pass. CI's first run on this PR failed Build, Typecheck, CLI smoke,
windows tests, and every perf job for this reason.

Fix: extract the public surface of `regression-harness-lambda-local.ts`
into a new types-only file that has no aws-lambda imports, point
`regression-harness.ts` at that types file, and exclude
`regression-harness-lambda-local.ts` from producer's tsconfig
`include`. The implementation file is still loaded at runtime via
`tsx` (lambda-local mode runs the harness through tsx, not from
producer's dist/), so the runtime contract is unchanged — producer's
tsc just no longer has to type-check it.

  - `regression-harness-lambda-local-types.ts` (new): exports
    `RunLambdaLocalInput` + `RunLambdaLocalRender` with zero
    aws-lambda imports.
  - `regression-harness-lambda-local.ts`: re-exports
    `RunLambdaLocalInput` from the new types file (so the public
    name stays stable for any future direct imports).
  - `regression-harness.ts`: drops the `typeof import("...")` trick
    and uses the explicit `RunLambdaLocalRender` signature for the
    dynamically-loaded function.
  - `tsconfig.json`: excludes `src/regression-harness-lambda-local.ts`
    so producer's emit pass never resolves `@hyperframes/aws-lambda`.

Verified:

  bun run build                   # full root build green
  bun run verify:packed-manifests # all packages publish-safe
2026-05-17 21:43:46 +00:00
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
James 47fe69aff0 test(producer): extend cross-worker idempotency to non-zero chunks + dedupe soft-skip regex 2026-05-15 03:51:11 +00:00
Vance Ingalls 5a3fde19d4 feat(engine): add HDR video output pipeline (#265)
## Summary

Adds the ability to render HDR video output (H.265 10-bit, BT.2020) from HyperFrames compositions. When the renderer detects HDR source video, it automatically switches to the HDR output pipeline — no flags needed.

## What it does

- **Auto-detection** — Probes each video source with `ffprobe`. If any has bt2020/PQ/HLG color metadata, the output switches to H.265 10-bit with correct color tags. SDR-only compositions are unaffected (H.264, bt709).
- **HLG pass-through** — Native HLG pixels from FFmpeg extraction are piped directly to the encoder without conversion. This avoids brightness loss from HLG→linear→PQ conversion (which requires an OOTF system gamma we can't reliably apply).
- **Encoder HDR support** — Both chunk and streaming encoders accept HDR presets: `libx265`, `yuv420p10le`, BT.2020 color primaries, `hvc1` codec tag (required for Apple playback).
- **WebGPU HDR capture (gated)** — A complete WebGPU float16 readback pipeline is implemented and tested but gated behind headed Chrome (headless doesn't expose WebGPU). Ready for future use with WebGPU canvas content.
- **HDR utilities** — `detectTransfer()` (PQ vs HLG), `getHdrEncoderColorParams()`, `analyzeCompositionHdr()`. 15 unit tests.

## Key design decisions

| Decision | Why |
|----------|-----|
| No `--hdr` flag | SDR content encoded as HDR causes orange shift in browsers. Auto-detect eliminates this. |
| HLG pass-through (not HLG→PQ) | Conversion loses brightness without OOTF. Pass-through matches source exactly. |
| `hvc1` codec tag | Apple QuickTime requires `hvc1` (not `hev1`) for HEVC playback. |
| 1-hour streaming timeout | HDR capture at ~6fps needs more time than the default 10-minute FFmpeg timeout. |

## Files changed

| File | What changed |
|------|-------------|
| `packages/engine/src/utils/hdr.ts` | **NEW** — HDR detection, transfer types, encoder params (15 tests) |
| `packages/engine/src/services/hdrCapture.ts` | **NEW** — WebGPU readback, HLG conversion, PQ encode |
| `packages/engine/src/services/streamingEncoder.ts` | HDR presets, raw rgb48le input, color tags |
| `packages/engine/src/services/chunkEncoder.ts` | HDR presets, conditional color tags |
| `packages/producer/src/services/renderOrchestrator.ts` | Auto-detection loop, HDR pass-through capture path |

## How to test

Render a composition with an HDR video source. The output should be H.265 10-bit with HDR metadata visible in `ffprobe` (bt2020, arib-std-b67 or smpte2084). Plays correctly in QuickTime and on HDR displays.

## Stack position

**2 of 6** — Stacked on #258 (SDR/HDR normalization). Provides the encoder infrastructure that phases 1-5 build on.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-19 15:10:59 -07:00
JamesandClaude Opus 4.6 f6c6b58c4c fix(producer): exclude test files from tsc build
The producer's tsconfig.json included all src/**/* which caused tsc
to fail on test files that import vitest (not a producer dependency).
Exclude *.test.ts from the declaration build — vitest handles its own
tsconfig for running tests.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 02:18:44 +00:00
Vance IngallsandClaude Opus 4.6 9f8e5ba5a1 initial code (#2)
* feat: initial code port from hyperframes-internal

Port all OSS-ready packages from the internal monorepo:
- @hyperframes/core — shared types, HTML generation, GSAP utilities, runtime
- @hyperframes/cli — CLI for creating, previewing, and rendering compositions
- @hyperframes/engine — framework-agnostic rendering engine (BeginFrame + FFmpeg)
- @hyperframes/producer — video rendering pipeline (Puppeteer + FFmpeg)
- @hyperframes/ui-player — browser-based video player component
- @hyperframes/studio — composition editor (React frontend + Hono backend)

Includes regression test suite with Docker-based test harness.

All HeyGen-internal references, deployment infrastructure, and
proprietary assets have been removed. Package names migrated
from @app/* to @hyperframes/*.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: scrub internal codenames and stale references from OSS port

- Replace static.heygen.ai runtime URLs in test fixtures
- Remove internal CDN publish script (publish-hyperframe-runtime.ts)
- Replace sandbox-studio, sandbox-interceptor, __magicEditRuntime
  with neutral names (studio, hyperframe-runtime, __hyperframeRuntime)
- Fix stale Vault API / localhost references in docs
- Remove broken deprecated_studio link

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove remaining internal codenames and stale references

- Delete stale producer README.md and PIPELINE.md (referenced nonexistent files)
- Replace "Cerberus" codename with "HyperFrames" in test design reviews
- Replace magic-edit postMessage identifiers with hf-preview/hf-parent
- Rename debug-magic-edit-timeline.ts to debug-timeline.ts
- Replace "Motion Cut" with "HyperFrames" in Timeline comments
- Fix studio/CLI references to nonexistent archive package
  (use local data/projects/ dir, stub render proxy)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 22:43:56 -07:00