Commit Graph
3042 Commits
Author SHA1 Message Date
James cb74ba7e71 fix(cli): use "with" instead of "in" for agent references 2026-03-27 22:45:45 +00:00
James f96d357c9a feat(cli): improve FTUX to guide users toward AI agent workflow
- Init "next steps" now leads with opening in an AI agent as step 1,
  followed by dev preview and render as steps 2 and 3
- Interactive init shows a tip about AI agent workflow after scaffolding
- Dev command output hints that compositions can be edited with an
  AI agent and changes reload automatically in the studio
2026-03-27 22:44:42 +00:00
James fff87300f1 fix(cli): point agents to docs CLI and llms.txt instead of guessing URLs
The shared CLAUDE.md in scaffolded projects mentioned
hyperframes.heygen.com alongside doc topic names, causing AI agents
to guess incorrect URLs like /compositions instead of using the local
`hyperframes docs` CLI command or the correct /concepts/compositions
path. Now explicitly directs agents to use the CLI for quick reference
and llms.txt for full doc URL discovery.
2026-03-27 22:22:47 +00:00
James b6e2d74cb7 chore: release v0.1.9 2026-03-27 22:16:04 +00:00
James c091891fdd fix(cli): make init interactive by default, default template to blank
- Interactive wizard is now the default when running in a TTY terminal
- Non-interactive mode (for CI/agents) uses --non-interactive flag
- Template defaults to "blank" when not specified in non-interactive mode
- --template flag skips the template picker prompt in interactive mode
- Replaces --human-friendly flag with --non-interactive (inverted logic)
2026-03-27 22:15:53 +00:00
James 8b784cca3d chore: release v0.1.8 2026-03-27 22:09:23 +00:00
James 8d7c33a4aa fix(publish): add repository.url to all packages for npm provenance
npm's sigstore provenance verification requires package.json
repository.url to match the GitHub repo. Without it, publish
fails with E422 "expected to match https://github.com/heygen-com/hyperframes".
2026-03-27 22:07:55 +00:00
James Russo 42cca2c909 Merge pull request #99 from heygen-com/chore/release-v0.1.7
chore: release v0.1.7
2026-03-27 15:03:57 -07:00
James 4a49d461df chore: release v0.1.7 2026-03-27 22:03:09 +00:00
James Russo 4f44bfc72e Merge pull request #98 from heygen-com/feat/cli-smart-worker-default
feat(cli): smart default worker count based on CPU cores
2026-03-27 13:47:17 -07:00
JamesandClaude Opus 4.6 9012a89ae8 refactor(cli): resolve worker count once and pass downstream
- Compute CPU_CORE_COUNT once at module level instead of calling cpus()
  multiple times
- Make RenderOptions.workers required (number, not optional) — the
  caller resolves the default, callees don't re-derive it
- Remove redundant existsSync guard before mkdirSync({recursive})
- Trim oversized JSDoc on defaultWorkerCount

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:44:52 +00:00
JamesandClaude Opus 4.6 91cedae7ea chore(cli): remove third-party references from code comments and docs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:41:44 +00:00
JamesandClaude Opus 4.6 957acbd538 feat(cli): smart default worker count based on CPU cores
Replace the hardcoded default of 4 workers with a CPU-aware heuristic:
half of available CPU cores, capped at 4. Each worker spawns a separate
Chrome browser process (~256MB RAM each), so the previous default of 4
caused resource contention on smaller machines.

The new defaults:
  2-core laptop  → 1 worker
  4-core laptop  → 2 workers
  8-core desktop → 4 workers
 16-core server  → 4 workers (capped)

Also adds --workers auto flag support, improves help text to explain
what workers do, and adds a Workers section to the rendering docs with
guidance on when to increase or decrease parallelism.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 20:39:04 +00:00
Miguel Ángel 5388a48adf fix(core): lint rule for timeline ID mismatches (#93)
## What

Added three new lint rules to the Hyperframe HTML linter to catch common runtime errors and invalid script references.

## Why

These lint rules prevent silent failures and runtime errors that can break Hyperframe compositions:

1. Timeline assignments without initialization guards cause silent failures when `window.__timelines` is undefined
2. Mismatched timeline IDs between `data-composition-id` attributes and `window.__timelines` keys prevent proper auto-nesting
3. Hallucinated script sources referencing non-existent `@hyperframe/` packages result in 404 errors

## How

Implemented three new lint rules with corresponding error codes:

- `timeline_registry_missing_init`: Detects timeline assignments without proper initialization guard using regex pattern matching
- `timeline_id_mismatch`: Cross-references composition IDs from HTML attributes against timeline registry keys to identify mismatches
- `hallucinated_script_src`: Checks script `src` attributes against known bad patterns for non-existent CDN packages

Each rule provides specific error messages and fix hints to guide developers toward correct implementations.

## Test plan

- [x] Unit tests added/updated
- [x] Manual testing performed
- [ ] Documentation updated (if applicable)

Added comprehensive test coverage for all three new lint rules, including both positive and negative test cases to ensure proper detection and avoid false positives.
2026-03-27 21:23:48 +01:00
JamesandClaude Opus 4.6 4accfd72ef refactor(cli): simplify path resolution and install-skills control flow
- Extract `resolveAssetDir()` helper to eliminate copy-paste across
  getStaticTemplateDir, getSharedTemplateDir, getBundledSkillsDir
- Remove `counted` boolean in fallbackInstall() — collect installed
  skills from first target explicitly, then copy to remaining targets
- Consolidate duplicate `installed.length > 0` check in runInstall()
  into a single early return

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 19:20:47 +00:00
JamesandClaude Opus 4.6 09518890ea refactor(cli): migrate skills install to npx skills add
Replace custom git clone + copy logic with `npx skills add` from the
vercel-labs/skills ecosystem. This is the standard used by GSAP,
Remotion, and other skill providers.

- Primary path: `npx skills add heygen-com/hyperframes` and
  `npx skills add greensock/gsap-skills` with `-g -y -a <agent>` flags
- Git clone + copy kept as fallback if npx is unavailable
- Added `skillsAgent` field to targets mapping CLI flags to the correct
  agent names (e.g., gemini → gemini-cli)
- Removes ~80 lines of custom git/copy infrastructure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 19:16:08 +00:00
JamesandClaude Opus 4.6 42c79f3bd3 feat(cli): scaffold CLAUDE.md and project-level skills into init
New HyperFrames projects created via `hyperframes init` now include:

- CLAUDE.md + AGENTS.md — teaches AI agents about skills, commands,
  project structure, and framework rules (class="clip", timeline
  registration, determinism). Agents know to invoke /compose-video
  before writing compositions.
- .claude/skills/{compose-video,captions} — project-level skills for
  immediate availability in the current agent session (global skills
  require a session restart to discover).
- Updated next-steps output with `hyperframes docs <topic>` and a
  link to hyperframes.heygen.com.
- Updated README with "AI Agent Skills" section documenting
  `npx hyperframes skills` and `npx skills add` install paths.
- Repo-level CLAUDE.md for framework contributors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 19:15:54 +00:00
Miguel Ángel 1593055482 fix(core): filter decorative elements from timeline clip collection (#92)
## What

Enhanced timeline collection to discover GSAP-animated scene elements and persistent overlays through runtime introspection.

## Why

The existing timeline collection only captured elements with explicit timing attributes (`data-start`, `data-track-index`) or media elements, missing scene elements that are animated purely through GSAP tweens and persistent overlay elements that should appear for the full composition duration.

## How

Added two new discovery mechanisms to `collectRuntimeTimelinePayload`:

1. **GSAP Timeline Introspection**: Walks the master timeline's tweens using `getChildren()` to find animated elements, calculates absolute time ranges by traversing parent timelines, and bubbles child tween ranges up to their nearest scene-level ancestors (direct children of root with IDs).
2. **Persistent Overlay Detection**: Identifies direct children of the root composition that weren't captured by DOM queries or GSAP introspection, treating them as full-duration overlay elements while filtering out non-visual elements (script, style, meta tags) and hidden elements.

Both mechanisms respect existing track assignments and create new tracks when needed to avoid conflicts.

## Test plan

- [x] Unit tests added/updated
- [x] Manual testing performed
- [ ] Documentation updated (if applicable)

Added comprehensive test coverage for:

- GSAP-animated scene element discovery via timeline introspection
- Time range bubbling from child elements to scene ancestors
- Persistent overlay inclusion as full-duration clips
- Proper filtering of non-visual elements (script/style tags)

![image.png](https://app.graphite.com/user-attachments/assets/106ea699-e243-493d-aa76-a74f303b80c3.png)

![image.png](https://app.graphite.com/user-attachments/assets/2d124d15-c933-4e12-891c-06100e6241c3.png)
2026-03-27 18:31:46 +01:00
James Russo b7ce417745 Merge pull request #86 from heygen-com/release/v0.1.6
chore: release v0.1.6
2026-03-27 00:23:29 -07:00
James Russo 651e004a6c Merge pull request #88 from heygen-com/fix/blank-template-full-html-document
fix(cli): make blank template a full HTML document
2026-03-27 00:23:12 -07:00
Miguel ÁngelandClaude Opus 4.6 d52ea88df5 fix(cli): make blank template a full HTML document
The blank template was a bare `<div>` fragment without `<!DOCTYPE>`,
`<head>`, or `<body>`. This caused:
- Blank preview (bundler/runtime can't initialize from a fragment)
- "Failed to run lint" (parsing errors on the malformed document)

All other templates (swiss-grid, vignelli, warm-grain, play-mode) are
proper HTML documents — blank was the only outlier.

Also improves lint error reporting to show the actual error message
instead of the generic "Failed to run lint."

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 02:50:53 -04:00
JamesandClaude Opus 4.6 89beb95a87 fix(cli): exit on Ctrl+C during hyperframes dev
The SIGINT handlers that were meant to do graceful cleanup (close server,
remove symlinks) override Node's default exit behavior. If the cleanup
hangs (e.g. server.close() blocked by open connections), the process is
stuck and Ctrl+C does nothing.

Fix: don't intercept SIGINT at all. Node's default behavior exits the
process immediately on Ctrl+C. The OS reclaims the port and file handles.
Use process.on("exit") for best-effort symlink cleanup instead.

Also fixes running the CLI via `tsx` in dev mode — __CLI_VERSION__ is a
tsup build-time define that crashes at runtime without a fallback.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 06:35:41 +00:00
github-actions[bot] 55ff721552 chore: release v0.1.6 2026-03-27 06:04:18 +00:00
JamesandClaude Opus 4.6 f3964f3e45 fix(cli): handle port collisions in dev server with auto-increment
The embedded dev server (hyperframes dev) silently reported success even
when the requested port was already in use (e.g., by Cursor IDE on 3002).
This happened because the old isPortAvailable() probe had a TOCTOU race
and findAvailablePort() silently fell back to the original port on exhaustion.

Replace with serveWithPortFallback() that binds the real Hono server
directly via createAdaptorServer + manual listen(), retrying on EADDRINUSE.
Shows a yellow warning when auto-incrementing and a clear error when all
ports are exhausted.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 05:15:30 +00:00
James Russo e0ee983e19 Merge pull request #81 from heygen-com/feat/webm-transparency
feat(render): WebM output with VP9 alpha transparency
2026-03-26 22:07:57 -07:00
JamesandClaude Opus 4.6 83d11ac595 refactor: simplify review fixes for WebM PR
- Use static import for copyFileSync (was unnecessary dynamic import)
- Shallow-copy config before mutating forceScreenshot (prevents
  caller-provided config from being permanently modified)
- Consolidate isWebm/isWebmRender/outputFormat into single early
  declaration in renderOrchestrator
- Fix debug output extension for WebM (was hardcoded .mp4)
- Log unexpected audio extraction errors instead of silently swallowing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 03:40:35 +00:00
Miguel Ángel dc0d69a21b feat(producer): support entryFile for rendering individual compositions (#42)
## Changes

- Add optional `entryFile` parameter to render API endpoints (`/v1/render` and `/v1/render-stream`)
- Enable rendering individual sub-compositions by extracting them from index.html context when the entry file is a `<template>` wrapper
- Change base64 audio/video linting from detecting "fabricated" media to prohibiting all inline base64 media
- Add manifest path resolution for bundled producer deployments

## API Changes

- `RenderConfig` — new optional `entryFile` field for specifying HTML file to render
- `server.ts` — parses `entryFile` from request body, validates file exists in project directory
- `executeRenderJob` — uses `entryFile` instead of hardcoded `"index.html"`

## Template Extraction

- `extractStandaloneEntryFromIndex` — extracts sub-composition hosts from index.html and creates standalone render context
- Handles `<template>` entry files by finding matching `data-composition-src` in index.html and isolating that host
- Resets `data-start` to 0 for standalone rendering

## Linting Updates

- Change rule #3.7 from detecting "fabricated" base64 media to prohibiting all inline base64 audio/video
- Lower detection threshold from 100+ to 20+ base64 characters
- All base64 media now triggers error severity with clearer messaging about file size bloat

## Usage

```json
POST /v1/render-stream
{ "projectDir": "/path/to/project", "entryFile": "compositions/intro.html" }
```

Omit `entryFile` for default behavior (renders `index.html`).
2026-03-27 04:28:51 +01:00
James Russo 244a9cbe60 Merge pull request #80 from heygen-com/docs/update-for-recent-features
docs: update CLI docs for dev server, version checks, and agent output
2026-03-26 20:13:15 -07:00
JamesandClaude Opus 4.6 684b103ba4 docs: add WebM transparency docs to engine, producer, and CLI examples
- Engine: document getEncoderPreset() for MP4/WebM, VP9 alpha flags,
  Opus audio in mux step
- Producer: document format field in RenderConfig, WebM usage example,
  pipeline steps updated for WebM
- CLI: add render command examples in --help (including WebM overlay)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 02:45:09 +00:00
JamesandClaude Opus 4.6 8d47665149 fix(render): update WebM golden baseline with working alpha
The VP9 alpha encoding works correctly — verified by overlaying on a
green background with explicit VP9 decoder. FFmpeg's default decoder
doesn't expose VP9 alpha through ffprobe, but browsers and VP9-aware
decoders read it correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 02:42:16 +00:00
JamesandClaude Opus 4.6 efc7b82755 fix(render): fix WebM transparency — use screenshot mode + proper CDP setup
- Force screenshot capture mode for WebM (beginFrame doesn't support
  alpha channel in chrome-headless-shell)
- Set Emulation.setDefaultBackgroundColorOverride once during session
  creation (matching experiment-framework's approach)
- Fix acquireBrowser to pass executable path in screenshot mode on
  Linux (was setting undefined, causing puppeteer-core to fail)
- Add Page.captureScreenshot params: fromSurface, captureBeyondViewport,
  optimizeForSpeed (matching experiment-framework)
- Fix regression harness extractMonoPcm16 for videos without audio
- Add getEncoderPreset unit tests
- Add webm-transparency regression test with golden baseline

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 02:35:03 +00:00
James Russo b02017f8e2 Merge pull request #79 from heygen-com/feat/version-check-system
feat(cli): version check system with agent-friendly output
2026-03-26 19:25:39 -07:00
JamesandClaude Opus 4.6 a146c9e527 test(render): add WebM regression test and getEncoderPreset unit tests
- New regression test `webm-transparency`: minimal transparent composition
  rendered to WebM, validates VP9 codec and visual quality at 100
  checkpoints against golden baseline
- Extend regression harness: `renderConfig.format` field ("mp4" | "webm"),
  format-aware output paths and snapshot filenames
- Fix `extractMonoPcm16` to gracefully handle videos without audio
  streams (WebM without audio was throwing instead of returning empty)
- Unit tests for `getEncoderPreset()`: VP9/yuva420p for WebM,
  h264/yuv420p for MP4, preset mapping, quality preservation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 02:19:43 +00:00
JamesandClaude Opus 4.6 15f6b86ac0 feat(render): add WebM output with VP9 alpha transparency
Support rendering compositions with transparent backgrounds via
`--format webm`. VP9+alpha is the standard format for overlayable
video (captions, lower thirds, overlays).

Changes by layer:
- CLI: `--format mp4|webm` flag on render command
- Producer: threads format through RenderConfig, switches to PNG
  capture and VP9 encoding when webm
- Engine: getEncoderPreset() returns VP9 config with yuva420p;
  transparent page background via CDP when capturing PNG;
  mux uses Opus audio for WebM; VP9 flags from production:
  -row-mt 1, -auto-alt-ref 0, alpha_mode=1 metadata
- Frame capture: Emulation.setDefaultBackgroundColorOverride a=0

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 02:12:39 +00:00
Miguel Ángel 9262d01109 fix(producer): fall back to data-duration when GSAP timeline is empty (#78)
## What

When a composition has an empty GSAP timeline (no animations), `window.__hf.duration` was always 0, causing `hyperframes render` to time out after 45 seconds waiting for `duration > 0`.

## Why

The HF bridge script reads duration from `window.__player.getDuration()`, which returns the GSAP timeline duration. An empty timeline has duration 0. The render engine waits for `window.__hf.duration > 0` to confirm the runtime is ready — so compositions with no animations would always deadlock.

This hits the `--template blank` scaffold immediately: it generates an empty GSAP timeline and relies solely on `data-duration="10"` for composition timing.

## How

One-line change to the bridge script: when `getDuration()` returns 0, fall back to reading `data-duration` from the root `[data-composition-id]` element. This is the same value the static compiler already extracted — so we get a correct duration without any extra browser round-trips.

```js
get duration() {
  var d = p.getDuration();
  return d > 0 ? d : getDeclaredDuration(); // reads data-duration from root element
}
```

## Test plan

- [x] `hyperframes init my-video --template blank && hyperframes render my-video` completes successfully
- [x] Output: `output.mp4` — 10s, 1920×1080, 30fps ✓  
- [x] Compositions with actual GSAP animations unaffected (fallback only triggers when timeline duration is 0)
- [x] Build passes, lint/format clean
2026-03-27 02:56:52 +01:00
JamesandClaude Opus 4.6 31aa45ba3a docs: update CLI docs for dev server, version checks, and --port flag
- Document the three dev server modes (embedded/local studio/monorepo)
- Add --port flag to dev command
- Document _meta envelope on all --json commands
- Document upgrade --check --json for agent consumption
- Document passive update notices and HYPERFRAMES_NO_UPDATE_CHECK
- Update doctor output example with Version check row
- Fix README default port from 3000 to 3002

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 01:44:28 +00:00
JamesandClaude Opus 4.6 cd15c68a2e feat(cli): add version check system with agent-friendly output
- New `updateCheck.ts` utility: cached npm registry check (24h TTL),
  sync `getUpdateMeta()` for _meta envelope, `printUpdateNotice()` for
  passive stderr banner
- `upgrade --check --json`: machine-readable version check for AI agents
  Returns { current, latest, updateAvailable }
- `_meta` envelope on all --json commands (info, lint, benchmark,
  compositions): includes version, latestVersion, updateAvailable
- `doctor` shows version check as first row
- Passive update notice on stderr after command completes (skipped in
  CI, non-TTY, --json, --quiet)
- Background check fires on startup (non-blocking, populates cache)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 01:41:34 +00:00
github-actions[bot]andgithub-actions[bot] ffd0fb678f chore: release v0.1.5 (#77)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-27 01:50:05 +01:00
Miguel ÁngelandClaude Sonnet 4.6 9d2362990b fix(cli): inject version from package.json, fix docker hint, add --port to dev
- version.ts: replace hardcoded "0.1.0" with __CLI_VERSION__ injected by
  tsup at build time from package.json — fixes version mismatch where
  `hyperframes --version` reported 0.1.0 while package was 0.1.4
- tsup.config.ts: add define.__CLI_VERSION__ using package.json version
- render.ts: renderDocker error handler showed "Try --docker" even when
  already using --docker — changed to "Check Docker is running: docker info"
- dev.ts: add missing --port arg to embedded mode; findAvailablePort now
  starts from the user-supplied port instead of hardcoded 3002

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 00:45:36 +00:00
JamesandClaude Opus 4.6 c34cbedbc7 fix(cli): resolve typecheck errors in studioServer
Add nullish coalescing for regex match groups that TypeScript flags as
possibly undefined.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 23:56:14 +00:00
JamesandClaude Opus 4.6 80cc643ac5 feat(cli): add render endpoint to embedded studio server
Wire up the "Export MP4" button in the studio UI. The render runs
async in the same process using @hyperframes/producer's executeRenderJob,
with SSE progress streaming and MP4 download on completion.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 23:53:29 +00:00
JamesandClaude Opus 4.6 5ace89d634 feat(cli): implement embedded dev server for hyperframes dev
When installed via npx, `hyperframes dev` now starts a standalone
Hono HTTP server that serves the pre-built studio SPA and implements
the project API (file listing, read/write, preview bundling,
sub-composition rendering, runtime serving, SSE file watching).

Three modes are auto-detected:
1. Monorepo dev (running from .ts source) → spawn Vite (existing)
2. Local @hyperframes/studio installed → spawn Vite via package (new)
3. Default → embedded Hono server (new, zero extra deps needed)

Also patches the studio SPA to use EventSource SSE fallback when
Vite HMR is unavailable (production/embedded builds).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 23:34:00 +00:00
Miguel Ángel e554710646 fix(producer): propagate data-start to inner composition element during compilation (#73)
## Summary
- copy data-start from the host sub-composition node to the inlined inner composition root
- preserve the correct runtime offset lookup for nested compositions after producer compilation
- avoid nested GSAP timelines snapping to their end state when the host starts later than t=0
2026-03-27 00:20:16 +01:00
github-actions[bot] 87fc3e3d8f chore: release v0.1.4 2026-03-26 22:09:12 +00:00
JamesandClaude Opus 4.6 e746debb1a fix(ci): generate font data in Docker build instead of committing
The generated font data is a pure function of the generator script +
@fontsource package versions — no reason to store 566KB of base64
blobs in git. Generate it during the Docker test image build instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:34:25 +00:00
JamesandClaude Opus 4.6 879a1a1ae5 fix(ci): commit generated font data for regression tests
The regression CI runs the producer source directly via tsx (not the
bundled CLI), so it needs fontData.generated.ts to exist at import
time. Remove from .gitignore and commit the generated file.

Mark as linguist-generated in .gitattributes so GitHub collapses it
in PR diffs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:22:32 +00:00
JamesandClaude Opus 4.6 c926985b63 fix(cli): copy pre-built runtime artifacts instead of regenerating
The previous approach called loadHyperframeRuntimeSource() to regenerate
the runtime IIFE, but its output lacked the trailing newline present in
the pre-built artifact, causing a SHA256 checksum mismatch with the
manifest. Copy the pre-built files from core/dist directly instead.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:15:56 +00:00
JamesandClaude Opus 4.6 2280273f79 fix(cli): remove empty src attrs from swiss-grid audio elements
Empty src="" on <audio> elements causes the browser to fetch the
current page URL as the audio source, producing 404 errors in the
console during rendering. These are placeholder sound effect slots
whose src should be set dynamically when audio is configured.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:06:00 +00:00
JamesandClaude Opus 4.6 e4a145a809 fix(cli): pass resolved browser path to engine for rendering
The CLI's ensureBrowser() finds Chrome via env var, cached download,
or system paths (including /Applications/Google Chrome.app on macOS).
But the result was discarded — the engine's acquireBrowser() only
checked the puppeteer cache for chrome-headless-shell, passing
undefined executablePath on macOS without headless-shell installed.

Bridge the two by setting PRODUCER_HEADLESS_SHELL_PATH from the CLI's
resolved browser path before creating the render job, so the engine's
resolveConfig() picks it up.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:05:36 +00:00
JamesandClaude Opus 4.6 68f86f66ac fix(cli): ship runtime manifest alongside CLI bundle
The hyperframeRuntimeLoader uses import.meta.url to resolve
hyperframe.manifest.json as a sibling file. When bundled into the CLI
via tsup, import.meta.url points to dist/cli.js, so the sibling lookup
checks dist/hyperframe.manifest.json — which wasn't being shipped.

Copy the manifest and the canonical-named runtime IIFE into dist/ during
the build-runtime step so the loader's sibling-path resolution works in
published npm packages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-26 21:02:36 +00:00