mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 04:38:33 +00:00
f761ee26243801511d0d1b4984cb483c95cdd784
17
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
73966cd53b |
feat(core): add 4k canvas resolution presets (#660)
## What Adds `landscape-4k` (3840×2160) and `portrait-4k` (2160×3840) presets to `CanvasResolution` and `CANVAS_DIMENSIONS` in `@hyperframes/core`. Foundation for end-to-end 4K rendering support. ## Why There is no codified way today to mark a composition as 4K. The string union `CanvasResolution = "landscape" | "portrait"` is the only enum used by templates, generators, and stage-zoom math; without 4K members, scaffolds and helpers always emit 1080p dimensions even when the underlying engine + encoder pipeline can already handle larger viewports (Chrome `setViewport`, ffmpeg `libx264`/`libvpx-vp9`/`prores_ks` all scale fine). This is PR 1 of a 3-PR stack making 4K a first-class option: 1. **PR #660 (this)** — core types/constants + parser detection. 2. **PR #661** — `hyperframes init --resolution 4k` flag to scaffold 4K projects. 3. **PR #662** — byte-budget the frame data-URI cache so 4K renders don't OOM. ## How - `CanvasResolution` extended additively (no breaking change). - `CANVAS_DIMENSIONS` gains `landscape-4k` / `portrait-4k` entries. - `parseResolutionFromHtml` accepts `data-resolution="landscape-4k|portrait-4k"` and infers 4K from `data-composition-width`/`data-composition-height` (long side ≥ 2560 → UHD variant). - `parseResolutionFromCss` reuses the same dimension-aware classifier so inline `#stage { width/height }` styles are detected too. - Helper extracted: `resolveResolutionFromDimensions(w, h)`. - `cli/info.ts` cleanup: replaces a nested `parsed.resolution === "portrait" ? 1080 : 1920` ternary with a `CANVAS_DIMENSIONS[parsed.resolution]` lookup so it stays correct for 4K. Stage-CSS generators (`templates/base.ts`, `generators/hyperframes.ts`) already index `CANVAS_DIMENSIONS[resolution]`, so they pick up the new presets automatically. ## Test plan - [x] Unit tests added/updated — 4 new parser tests, 1 expanded constants test - [x] Manual testing performed — `bun run --cwd packages/core test` (679 pass), `bun run --cwd packages/cli test` (277 pass) - [ ] Documentation updated (deferred to PR #661 where the user-facing flag lands) |
||
|
|
0e7e33cf7d |
docs: add deployment guide for Vercel and Cloudflare templates (#653)
## What Adds a new guide at `docs/guides/deploy.mdx` covering the two official one-click deployment templates: - [heygen-com/hyperframes-vercel-template](https://github.com/heygen-com/hyperframes-vercel-template) (Vercel Sandbox + Vercel Blob) - [heygen-com/hyperframes-cloudflare-template](https://github.com/heygen-com/hyperframes-cloudflare-template) (Cloudflare Containers + R2) Wires the new page into `docs.json` under Guides, slotted right after `guides/rendering` (logical follow-on: render locally → deploy to the cloud). ## Why The two templates currently only exist as GitHub READMEs, so they're invisible to anyone reading the docs site. New users who want a hosted preview + render endpoint have no entry point in the docs to discover them. ## How Single guide with: - A comparison table (compute / storage / deploy button) so readers can pick at a glance. - `<Tabs>` for per-platform details (deploy button, what you get, performance, pricing, "why this primitive"). - Shared architecture diagram and the common "pre-baked renderer" cost pattern. - "Swapping the composition" steps that work for both templates. - "When to use a template vs. roll your own" framing for queues, multi-tenant, self-hosted. Single-page approach (vs. one page per template) chosen because content overlaps heavily — easier to discover and lower maintenance until more templates land. ## Test plan - [x] No code changes — docs only - [x] `bunx oxfmt --check` and `bunx oxlint` pass on changed files (no rules apply to `.mdx` / `.json` here) - [ ] Render the docs site locally to verify nav placement and Mintlify components (`<Tabs>`, `<Steps>`, `<CardGroup>`, `<Note>`) render correctly - [ ] Verify the Vercel and Cloudflare deploy buttons in the page open the correct template URLs |
||
|
|
f1d408eed3 |
test(producer): add variables-prod regression for the variables stack (PR 5/5) (#604)
## What End-to-end Docker regression test that exercises the **full variables chain** shipped in PRs #600-#603. Closes the loop between unit-tested seams and the actual rendered output. This is **PR 5 of 5**, the regression cap. Stacked on `feat/get-variables-skills` (PR #603). ## Why PRs 1-4 ship unit tests that cover the seams independently: - Engine: \`evaluateOnNewDocument\` injection (mocked Puppeteer) - Helper: \`getVariables()\` merge (jsdom) - CLI: \`parseVariablesArg\` validation (pure function) - Loader: \`__hfVariablesByComp\` population (jsdom) - Validator: \`validateVariables\` type-checking (pure) But none of those check that the chain actually works front-to-back inside the production Chrome+ffmpeg+harness combo. A type signature change on \`CaptureOptions.variables\`, a regression in \`evaluateOnNewDocument\` ordering, a bug in the runtime helper's attribute parsing — any of those could pass unit tests and silently render the wrong text. This regression catches it. ## How **Fixture** (\`packages/producer/tests/variables-prod/\`): - \`src/index.html\` — composition with three declared variables (\`title\`, \`subtitle\`, \`bgColor\`) read via \`window.__hyperframes.getVariables()\` and rendered as positioned text on a colored background. **No animation** — keeps the regression frame-stable so it isolates "did the variables flow through?" from motion concerns. - \`meta.json\` — tags \`[\"variables\", \"composition\"]\` (runs in the existing fast shard's tag filter, no workflow YAML changes needed). \`renderConfig.variables\` provides override values that the baseline reflects (\"Override Title\", \"Override subtitle\", \`#0a3d62\`). **If variables don't propagate**, the rendered frame shows declared defaults (\"Default Title\", black) — visibly different from the baseline, so PSNR fails on dozens of frames. - \`output/output.mp4\` — Docker-generated baseline per the project's CLAUDE.md golden-baseline rule. Host renders drift across Chrome/font versions and would fail PSNR even on green code. - \`src/silence.wav\` — copied from \`missing-host-comp-id\`'s silence track to satisfy the audio-correlation check. **Harness change** (\`packages/producer/src/regression-harness.ts\`): - \`TestMetadata.renderConfig\` gains an optional \`variables: Record<string, unknown>\` field, validated as a JSON object (not array, not null) in the \`meta.json\` validator. - The \`createRenderJob\` call site forwards \`renderConfig.variables\` to \`RenderConfig.variables\`, which the engine already consumes via \`evaluateOnNewDocument\` (PR #600). ## Test plan - [x] **\`docker:test variables-prod\` PASSED** — 100/100 visual checkpoints, audio correlation 1.000. - [x] **Defeated the bug it's meant to catch** — generated a baseline against an old image (without the harness change) and confirmed it shows defaults. After the harness change + image rebuild, the baseline correctly shows overrides. - [x] **CI auto-includes** — fast shard's \`--exclude-tags slow,render-compat,hdr\` lets \`[variables, composition]\` through. No \`.github/workflows/regression.yml\` edits needed. ## Backwards compatibility Additive. Existing fixtures don't set \`renderConfig.variables\` and behave identically. The harness validator only fires on the new field if it's present. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
62c2589839 |
docs(skills): document variables system in SKILL.md + docs (PR 4/4) (#603)
## What Distribution PR for the variables feature stack. Tells agents how to declare, read, and override variables across the four authoring surfaces — the two skill files agents load (`hyperframes`, `hyperframes-cli`), the public docs (`docs/packages/core.mdx`), and the in-CLI docs (`npx hyperframes docs compositions`). This is **PR 4 of 4**, the final PR in the stack. Stacked on `feat/get-variables-validation` (PR #602). ## Why PRs 1–3 added the runtime helper, sub-comp scoping, and schema validation, but the only places that mention them are the docs in those PRs. Agents loading `/hyperframes` or `/hyperframes-cli` skills won't know the new attributes/flags exist. This PR closes the loop. ## How - **`skills/hyperframes/SKILL.md`** — new "Variables (Parametrized Compositions)" section right after "Composition Structure" with: declare/read/override pattern, full worked example (with enum), sub-comp per-instance pattern (two hosts sharing a source), rules of thumb (defaults always, read-once, `--strict-variables` in CI, type validation behavior). Also added `data-variable-values` + `data-composition-variables` rows to the existing data-attributes tables. - **`skills/hyperframes-cli/SKILL.md`** — added `--variables`, `--variables-file`, `--strict-variables` to the render flag table; short paragraph forwarding to the hyperframes skill for the full pattern. - **`docs/packages/core.mdx`** — added a code snippet showing `getVariables<T>()` and `validateVariables` / `formatVariableValidationIssue` for tooling that validates CLI / host overrides. - **`packages/cli/src/docs/compositions.md`** — replaced the obsolete `JSON.parse(host.dataset.variableValues)` example with the modern `getVariables()` pattern. The `openai/plugins` mirror is intentionally out of scope. Skills in this repo are the source of truth; the downstream mirror is updated after each release as a separate workflow. ## Test plan - [x] Doc-only PR — no source code, no tests. - [x] Format check passes via `bunx oxfmt --check` on the touched markdown files. - [x] Manual review confirms each example compiles in head against the runtime/CLI surface that PRs 1–3 ship. ## Backwards compatibility Doc-only — no behavior change. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
1c9d726b5e |
feat(core,cli): variable schema validation + lint rules (PR 3/4) (#602)
## What Adds two lint rules + render-time validation for the variable system shipped in PR #600 + PR #601. Authors get fast feedback when JSON is malformed, declarations are missing required fields, or `--variables` values don't match the declared schema. This is **PR 3 of a 4-PR stack** — based on `feat/get-variables-subcomp` (PR #601). Will retarget to `main` after PRs 1 + 2 merge. ## Why The runtime today silently masks several classes of mistake: - A typo in `data-variable-values` JSON makes the parser return `{}` and the script reads stale declared defaults, with no visible signal. - A typo in a `data-composition-variables` declaration (missing `id`, wrong `type`) gets silently filtered out. - `--variables '{"titel":"x"}'` instead of `"title"` renders fine and produces the wrong output. These are exactly the cases lint + schema validation are good at catching. ## How **Lint rules** (`packages/core/src/lint/rules/composition.ts`): - `invalid_variable_values_json` — host's `data-variable-values` must parse as a JSON object. - `invalid_composition_variables_declaration` — root `<html>`'s `data-composition-variables` must parse as an array of objects with `id`, `type` (one of string/number/color/boolean/enum), `label`, and `default`. Per-entry findings report which fields are missing or invalid. Both rules read via a new `readJsonAttr` helper in `lint/utils.ts`. The existing `readAttr`'s regex `["']([^"']+)["']` truncates JSON-in-attribute values at the first internal quote — `data-variable-values='{"x":"y"}'` would capture only `{`. The new helper alternates double-vs-single-quoted branches with quote-specific char classes. A second helper `findHtmlTag` returns the `<html>` open tag (where `data-composition-variables` lives), distinct from `findRootTag` which returns the first in-body composition element. **Render-time validation** (`packages/core/src/runtime/validateVariables.ts`): - `validateVariables(values, declarations)` returns a structured array of `VariableValidationIssue`s — `undeclared`, `type-mismatch`, or `enum-out-of-range`. Pure / sync; works in any environment. - `formatVariableValidationIssue` renders one-line user-facing strings for CLI output. - Both exported from `@hyperframes/core`. **CLI integration** (`packages/cli/src/commands/render.ts`): - New `--strict-variables` flag. Default: print warnings, continue. Strict: print warnings, exit 1. - New `validateVariablesAgainstProject(indexPath, values)` helper reads the project's `index.html`, pulls the declared schema via `extractCompositionMetadata`, validates the CLI payload. Uses the existing `ensureDOMParser` polyfill (same pattern as `compositions.ts`). ## Test plan - [x] Unit tests added/updated - **11 `validateVariables` unit tests** — happy path, undeclared keys, type mismatches (every type), enum range, multi-issue aggregation, formatter output. - **11 `composition.test.ts` cases** — both lint rules: parse errors, shape errors, per-entry validation, unknown types, positive cases for valid declarations. - **5 `render.test.ts` cases** — `validateVariablesAgainstProject`: no-declarations, happy path, undeclared, type-mismatch, missing-file. - All existing tests green: core 646, cli 213. - [x] Manual flow walkthrough - `--variables '{"title":"x"}'` against an index that declares `title` as string → no warnings. - `--variables '{"count":"three"}'` against `count: number` → warning printed, render continues. - Same with `--strict-variables` → exit 1 before render starts. - [x] Documentation updated - `docs/packages/cli.mdx` — added `--strict-variables` flag row. ## Backwards compatibility Fully additive. Existing compositions emit zero new lint findings (the rules only fire on malformed JSON or invalid declarations, which the runtime would have silently dropped anyway). Existing `hyperframes render` invocations behave identically without the new flag. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
da92a17754 |
feat(core): scope getVariables() per sub-comp instance (PR 2/4) (#601)
## What Building on **PR #600** (`getVariables()` helper + `--variables` flag), this PR scopes the helper so embedded sub-compositions see their own per-instance values. The same composition source can now be embedded N times with different content via `data-variable-values` on each host. This is **PR 2 of a 4-PR stack** — based on `feat/get-variables`. Will retarget to `main` after PR #600 merges. ## Why `data-variable-values` was already documented as the per-instance attribute for nested compositions, but readers had to hand-roll `JSON.parse(host.dataset.variableValues)` and there was no scoping system — every sub-comp script had to re-implement the same pattern. This PR routes the values to a scoped `getVariables()` so authors use one API in both top-level and sub-comp contexts. ## How ``` [host element] [sub-comp source HTML] data-variable-values='{...}' + <html data-composition-variables='[...]'> ^ declared defaults ↓ ↓ └──────────── compositionLoader ────────────────────┘ ↓ window.__hfVariablesByComp[compId] = merged ↓ scripts wrapped by compositionScoping ↓ __hyperframes.getVariables() → scoped lookup ``` Three small surgical changes: - **`compositionLoader.ts`** — before injecting wrapped scripts, parse the host's `data-variable-values` JSON, merge it over `readDeclaredDefaults(doc.documentElement)` (reused from PR 1's runtime helper), and write the result to `window.__hfVariablesByComp[compositionId]`. Skipped when both sides are empty so the table only grows when there's actual data. Inline templates (no separate `<html>` root) get host overrides only. - **`compositionScoping.ts`** — wrapper IIFE now takes a fourth parameter `__hyperframes` alongside the existing scoped `document` / `gsap` / `window`. Same shadowing pattern that already works for the other three. The scoped `__hyperframes` overrides `getVariables` to read from `__hfVariablesByComp[__hfCompId]` and returns a fresh object each call so script mutations don't leak into the shared table. - **`getVariables.ts`** — `readDeclaredDefaults` becomes a named export (was a private helper) so the loader reuses the exact same defaults-extraction logic the top-level helper uses. Top-level scripts that aren't wrapped by `compositionScoping` keep calling `window.__hyperframes.getVariables()` and get the unscoped path from PR 1 (declared defaults + CLI `--variables` override). ## Test plan - [x] Unit tests added/updated - **3 new `compositionScoping.test.ts`** — scoped `getVariables` invocation routes to `__hfVariablesByComp[compId]`; missing-entry returns `{}`; mutation of the returned object doesn't leak into the shared table. - **5 new `compositionLoader.test.ts`** — merge order (host overrides win); declared-only path when host has no `data-variable-values`; empty-skip when neither side has data; invalid-host-JSON falls through to declared defaults; per-instance scoping across two hosts that share a source. - **3 new `getVariables.test.ts`** — covering the newly-public `readDeclaredDefaults` export (null root, valid attribute, invalid JSON / non-array). - All 622 existing core tests green. - [x] Manual flow walkthrough — host with `data-variable-values='{"title":"Pro"}'` → sub-comp's `__hyperframes.getVariables()` returns `{title:"Pro", ...declaredDefaults}`. Two hosts pointing at the same source with different overrides → each script sees its own values. - [x] Documentation updated - `docs/concepts/compositions.mdx` — switched the sub-comp example from `JSON.parse(host.dataset.variableValues)` to `__hyperframes.getVariables()`; added declared-defaults pattern and per-instance scoping note. - `docs/concepts/data-attributes.mdx` — clarified per-instance behavior on `data-variable-values`. ## Backwards compatibility Fully backwards compatible. Compositions that read `host.dataset.variableValues` directly keep working — the host attribute is still set as before. The new path is a strict addition. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
03b82e6ff8 |
feat(core,cli,engine,producer): getVariables() helper + --variables render flag (PR 1/4) (#600)
## What Adds the parametrized-render primitive from [hf#592](https://github.com/heygen-com/hyperframes/issues/592) by introducing a `getVariables()` runtime helper plus a CLI `--variables` / `--variables-file` flag. Compositions declare variables once on the root `<html>` element (the existing `data-composition-variables` attribute, which already drives Studio editing UI), read them at runtime via `window.__hyperframes.getVariables()`, and CLI users override them at render time without touching the composition source. This is **PR 1 of a 4-PR stack**: 1. **PR 1 (this one)** — runtime helper + CLI flag + engine injection (top-level renders). 2. PR 2 — sub-comp per-instance scoping (carry the host's `data-variable-values` into the inlined sub-comp's `getVariables()`). 3. PR 3 — schema validation + lint rules (warn on undeclared variable IDs, optional `--strict-variables`). 4. PR 4 — skill / scaffold distribution (SKILL.md, AGENTS.md scaffolds, openai/plugins mirror). ## Why The existing `data-composition-variables` schema declares variable types and defaults but isn't readable from composition scripts and can't be overridden at render time. To produce N variations of a composition today, an agent has to fork the composition or edit the source HTML before each render. `--variables` collapses that into one render call per variation, matching Editframe's `--data` UX without copying their `getRenderData` framing — `getVariables()` is named for the codebase's existing "variables" terminology and works equally in dev preview and at render time. ## How - **Runtime helper** (`packages/core/src/runtime/getVariables.ts`): reads `data-composition-variables` from `document.documentElement`, extracts `{id: default}` defaults, merges `window.__hfVariables` (override) on top, returns `Partial<T>`. Same code path in dev preview (no override) and at render (with override). Generic parameter for typed editor ergonomics. Exposed both as a named export from `@hyperframes/core` and on `window.__hyperframes.getVariables` for vanilla compositions. - **CLI flag** (`packages/cli/src/commands/render.ts`): `--variables '<json>'` and `--variables-file <path>`. `parseVariablesArg` is split out as a pure function (returns a discriminated `{ ok: true } | { ok: false }` union) so all validation paths are unit-testable; the side-effecting `resolveVariablesArg` wraps it with `errorBox` + `process.exit`. Mutually exclusive with `--variables-file`; fail-fast on conflicts, missing file, unparseable JSON, or non-object payloads (string, number, array, null). - **Engine injection** (`packages/engine/src/services/frameCapture.ts`): added an `evaluateOnNewDocument` step right after the `__name` polyfill that sets `window.__hfVariables` to the parsed JSON before any page script runs. Skipped when payload is empty so we don't add pointless init scripts. Plumbed through `CaptureOptions.variables` and `RenderConfig.variables`. Docker mode forwards the flag to the in-container CLI via `dockerRunArgs`. - **Why a separate `__hfVariables` global** instead of writing into `__hyperframes.getVariables()` directly: the helper is an IIFE that has to be defined before composition scripts execute, but the *override* needs to land before *that*. `evaluateOnNewDocument` is the only reliable hook that runs before the runtime IIFE evaluates. Storing the raw value on `__hfVariables` and merging in the helper keeps both paths order-independent. ## Test plan - [x] Unit tests added/updated - 9 jsdom tests for `getVariables()` covering empty state, declared defaults only, override merge, override-wins, declared-only, invalid JSON, non-array payloads, non-object overrides, typed generic. - 7 tests for `parseVariablesArg` covering all validation paths. - 2 integration tests for `renderLocal` confirming `variables` reach `createRenderJob`. - 3 new `dockerRunArgs` assertions for `--variables` passthrough (set / not-set / empty-object). - All existing tests green: core 611, cli 208, engine 519. - [x] Manual testing performed - `npx tsx packages/cli/src/cli.ts render --help` shows both flags + the two new examples. - [x] Documentation updated - `docs/packages/cli.mdx` — added flags to the table and a "Parametrized renders" section with a worked example. - `docs/concepts/data-attributes.mdx` — added `data-composition-variables` row. ## Backwards compatibility Fully backwards compatible. Compositions without `data-composition-variables` work unchanged; `getVariables()` returns `{}` and the engine skips the injection step. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
a68e840dda |
docs(remotion-skill): only trigger on explicit migration ask (#581)
## Summary Tightens the `remotion-to-hyperframes` SKILL.md trigger so the skill only fires when the user *explicitly* asks to migrate / port / convert a Remotion composition to HyperFrames — not when they merely have or mention Remotion code. ## Why User feedback on X from [@jasonpurdy](https://x.com/jasonpurdy/status/2049985508701556855): > I understand why you have the remotion migration skill, but I would encourage you to not have that on by default, it was basically the same video as remotion, I turned it off and like the native version more. He was A/B-testing HyperFrames vs Remotion. The migration skill auto-triggered, produced a translated output (essentially the same video as his Remotion one), and only after disabling the skill did he get a *native* HyperFrames composition that he preferred. The previous SKILL.md `description` listed four triggering conditions, three of which were context-detection patterns: 1. *the user provides Remotion source* (.tsx files using `useCurrentFrame`, `Sequence`, …) and asks to port 2. *the user pastes a Remotion entry point* and wants HTML 3. *the user links a Remotion repo* and asks for the HyperFrames equivalent 4. the user says "port my Remotion project", "translate this Remotion code", … Conditions (1)-(3) gave agents enough latitude to fire the skill when the user shared Remotion code as reference material or A/B-test context, even if they hadn't actually asked for a migration. Condition (4) is the only explicit-ask gate. ## Fix - Remove the context-detection conditions; gate strictly on *explicit migration verbs* (port, convert, migrate, translate, rewrite as HyperFrames) plus concrete trigger-phrase examples. - Add explicit NOT clauses for the common false-positive cases: - authoring a NEW HyperFrames composition (even with similar Remotion code in the user's history) - mentioning Remotion in passing - sharing Remotion code as reference material - the *specific* @jasonpurdy case: "the same video as my Remotion one" — treat as a fresh build, not a migration - Default recommendation when uncertain: route to the `hyperframes` skill instead. The body of the SKILL.md is unchanged — translation guidance is correct once the gate is passed; this PR only tightens the gate itself. ## Distribution note Per `project_hyperframes_plugin_distribution.md`, hyperframes-oss skills auto-propagate to Cursor + Claude Code (which consume this repo directly), but openai/plugins is a manual mirror that needs a sync PR after merge. Adding to my follow-up list. ## Test plan - [x] SKILL.md frontmatter description updated; body unchanged - [x] `bunx oxfmt --check skills/remotion-to-hyperframes/SKILL.md` passes - [x] commitlint conventional-commit format passes - [ ] After merge: sync to `openai/plugins/plugins/hyperframes/skills/remotion-to-hyperframes/SKILL.md` — Rames Jusso |
||
|
|
d01685d695 |
Merge pull request #517 from heygen-com/skill/r2hf-skill-body
feat(skills): remotion-to-hyperframes SKILL.md + orchestrator (7/7) |
||
|
|
f22d9bfabe |
Merge pull request #516 from heygen-com/skill/r2hf-references
feat(skills): remotion-to-hyperframes references (6/7) |
||
|
|
40339a65b9 |
Merge pull request #515 from heygen-com/skill/r2hf-corpus-t4
feat(skills): remotion-to-hyperframes corpus T4 (5/7) |
||
|
|
12945238cc |
Merge pull request #509 from heygen-com/skill/r2hf-corpus-t3
feat(skills): remotion-to-hyperframes corpus T3 (4/7) |
||
|
|
4ab4576adf |
Merge pull request #508 from heygen-com/skill/r2hf-corpus-t1-t2
feat(skills): remotion-to-hyperframes corpus T1+T2 (3/7) |
||
|
|
b27385ba1a |
Merge pull request #507 from heygen-com/skill/r2hf-eval-harness
feat(skills): remotion-to-hyperframes eval harness (2/7) |
||
|
|
3fa094c5c5 |
Merge pull request #506 from heygen-com/skill/r2hf-scaffold
feat(skills): scaffold remotion-to-hyperframes skill (1/7) |
||
|
|
2915b68633 |
fix(cli): handle port collisions in dev server with auto-increment (#85)
## Summary - Fix silent failure when `hyperframes dev` port (default 3002) is already in use (e.g., by Cursor IDE) - Replace TOCTOU-prone `isPortAvailable()` probe with `serveWithPortFallback()` that binds the real server directly - Auto-increment to next available port with a visible yellow warning, or show a clear error when all ports (range of 10) are exhausted ## What changed The old approach used a throwaway `net.createServer()` to test port availability, closed it, then opened the real Hono server — a classic TOCTOU race. The fallback also silently returned the original port when all 10 were taken. Now we use `createAdaptorServer()` (creates the Hono HTTP server without binding) and manually call `.listen(port)`, catching `EADDRINUSE` to try the next port. This eliminates the race entirely. **Before:** `hyperframes dev` says "Studio running at http://localhost:3002" even when port 3002 belongs to another process. **After:** - Port available: works as before - Port taken: `Port 3002 is in use, using 3003 instead` (yellow warning) - All ports taken: `Ports 3002–3011 are all in use. Use --port to specify a different port.` (error + exit) ## Testing - Verified TypeScript compiles cleanly (`tsc --noEmit`) - All pre-commit hooks (lint, format, commitlint) pass - Manual test: run another server on 3002, then `hyperframes dev` → confirms auto-increment message appears 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
d845068f16 |
feat(cli): add opt-out anonymous telemetry via PostHog (#52)
## Summary - Add anonymous usage telemetry to the CLI via PostHog's HTTP batch API (zero new dependencies) - Track command invocations, render performance, template choices, and environment info - Add `hyperframes telemetry [enable|disable|status]` command for user control - Config stored at `~/.hyperframes/config.json` — future-proofed for more settings ## Design Decisions | Decision | Rationale | |---|---| | **Raw `fetch` instead of `posthog-node`** | Zero new dependencies. Node 22 has built-in `fetch`. Can swap to SDK later if needed. | | **Opt-out with first-run disclosure** | Industry standard (Next.js, Homebrew, .NET CLI). Opt-in gets <3% participation. | | **Disabled in dev mode** | Uses `.ts` extension detection (shared `utils/env.ts`). Running via `tsx` = dev. | | **`phc_` prefix check** | Safety net — if the API key is ever reverted to a placeholder, telemetry silently disables. | | **5-second timeout, fail-silent** | Telemetry must never slow down or break the CLI. | | **Detached spawn for exit flush** | `flushSync` spawns a detached child process so `process.exit()` paths don't block. | ## What's Collected - Command names (init, render, dev, etc.) - Render metrics (duration, fps, quality, workers, docker/gpu) - Template choices during init - OS, architecture, Node.js version, CLI version ## What's NOT Collected - File paths, project names, or video content - IP addresses — `$ip: null` on every event payload (client-side) + "Discard client IP data" enabled in PostHog project settings (server-side) - Any personally identifiable information ## Opt-Out Mechanisms - `hyperframes telemetry disable` - `HYPERFRAMES_NO_TELEMETRY=1` - `DO_NOT_TRACK=1` - Automatically disabled in CI (`CI=true`) ## Files Changed **New files:** - `packages/cli/src/telemetry/config.ts` — Config read/write at `~/.hyperframes/config.json` (dir 0700, file 0600) - `packages/cli/src/telemetry/client.ts` — PostHog HTTP client (queue, batch, flush, detached flushSync) - `packages/cli/src/telemetry/events.ts` — Typed event helpers - `packages/cli/src/telemetry/index.ts` — Barrel exports - `packages/cli/src/commands/telemetry.ts` — `hyperframes telemetry` command - `packages/cli/src/utils/env.ts` — Shared `isDevMode()` (extracted from dev.ts) **Modified files:** - `packages/cli/src/cli.ts` — Wire telemetry at entry point + add telemetry subcommand - `packages/cli/src/commands/render.ts` — Track render success/failure metrics - `packages/cli/src/commands/init.ts` — Track template selection - `packages/cli/src/commands/browser.ts` — Track browser download events - `packages/cli/src/commands/dev.ts` — Use shared `isDevMode()` from utils/env.ts ## Testing - Verified typecheck passes (`tsc --noEmit`) - Verified lint passes (`oxlint`) - Verified format passes (`oxfmt --check`) - Tested `hyperframes telemetry status/enable/disable` commands - Verified first-run notice is suppressed in dev mode - Verified `--help`/`--version` don't trigger telemetry - Verified config file creation with correct permissions - Verified telemetry is no-op when API key lacks `phc_` prefix 🤖 Generated with [Claude Code](https://claude.com/claude-code) |