Commit Graph
85 Commits
Author SHA1 Message Date
JamesandClaude Opus 4.7 b8b82fa8d2 docs(remove-background): broaden framing from avatar-specific to any person video
The model removes background from any video with a person — we tested
with avatars because they were convenient, but anyone can bring a
talking-head clip, presenter footage, vlog, etc. Replace avatar-specific
filenames (avatar.mp4 / brandon.mp4) with neutral subject.mp4 (or
presenter.mp4 in the text-behind-subject example) and rephrase
copy that read as if avatars were the only use case.

Touches docs/guides/remove-background.mdx, hyperframes-media SKILL.md,
and hyperframes/patterns.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:34:37 -07:00
JamesandClaude Opus 4.7 5fca4becbc docs(remove-background): document compositing patterns and pitfalls
Skill (hyperframes-cli): three-pattern table (cutout-over-different-scene
vs over-its-own-source vs over-different-take) + the two non-obvious rules
(wrap video in non-timed div for opacity control, both videos data-start=0
for sync). Skill (hyperframes/patterns): worked text-behind-subject example.
Docs: --quality flag, compositing pitfalls section, quality preset table.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:29:33 -07:00
James 94dc6c895e fix(skills): purge stale tts/transcribe references from CLI skill pointers
Review on PR #619 caught two places that still pointed transcribe/tts
at hyperframes-cli — directly undercutting the description-trigger
goal of the split:

- skills/hyperframes/SKILL.md description ended with "For CLI commands
  (init, lint, preview, render, transcribe, tts) see the
  hyperframes-cli skill." Now splits the redirect: dev-loop commands
  (init, lint, inspect, preview, render) → hyperframes-cli; asset
  preprocessing (tts, transcribe, remove-background) →
  hyperframes-media.
- packages/cli/src/templates/_shared/CLAUDE.md is the skills table
  baked into every project bootstrapped by `hyperframes init`. Its
  hyperframes-cli row still listed transcribe/tts. Trimmed to the
  dev-loop commands and added a hyperframes-media row beside it, so
  new projects pick up the correct mapping.

Also caught by greppping for stale skill lists:

- .codex-plugin/plugin.json longDescription bundled transcribe/tts
  into "use the CLI for ...". Split into "use the CLI for the dev
  loop (init/preview/render), preprocess assets
  (tts/transcribe/remove-background)" so the Codex plugin store
  surface matches reality.

Confirmed `npx hyperframes skills` shells out to `npx skills add
heygen-com/hyperframes --all` (packages/cli/src/commands/skills.ts),
so the skill list is read dynamically from the repo and picks up
hyperframes-media without code changes.
2026-05-05 03:16:14 +00:00
James 4413d25b0e refactor(skills): consolidate tts/whisper guidance into hyperframes-media
Code review found the new hyperframes-media skill was parallel
content with skills/hyperframes/references/tts.md and the "Whisper
Model Guide" section of transcript-guide.md — same voice table, same
.en-translates-non-English warning, same TTS→transcribe chain in
both places. Plus some scope creep in hyperframes-media (audio/video
HTML snippets that duplicate the canonical track docs in
hyperframes/SKILL.md:265+).

Consolidation:

- hyperframes-media is now the single source of truth for CLI
  invocation, voice selection, multilingual phonemization, whisper
  model selection, and the .en gotcha. Picked up the multilingual
  prefix decoding from the deleted tts.md.
- skills/hyperframes/references/tts.md deleted; the bullet in
  hyperframes/SKILL.md is removed (no replacement — agents land on
  hyperframes-media via its own description).
- skills/hyperframes/references/transcript-guide.md keeps only the
  caption-side concerns: input-format table, mandatory quality
  check, cleaning JS, external-API import path, and the
  "if no transcript exists" flow. The intro bash recipe and Whisper
  Model Guide section both moved to hyperframes-media. Top of the
  file now points to hyperframes-media for CLI/model details.

Other tightening in hyperframes-media:

- Dropped WHAT-narration filler and the inline <audio>/<video> HTML
  snippets — they duplicate the canonical track-attribute docs in
  hyperframes/SKILL.md.
- Added the `id` field (`w0`, `w1`, ...) to the transcript output
  shape — the actual Word interface in
  packages/cli/src/whisper/normalize.ts includes it (optional for
  backwards compat), used by caption override logic.
- Compressed the TTS → Transcribe → Captions chain section.

Net: hyperframes-media 147 → 136 lines, transcript-guide.md 152 →
106 lines, tts.md gone (-75 lines).
2026-05-04 22:06:02 +00:00
James 051e985868 refactor(skills): split asset preprocessing out of hyperframes-cli
Move tts/transcribe/remove-background guidance into a new
hyperframes-media sibling skill so the CLI skill stays focused on
the dev loop (init/lint/inspect/preview/render/doctor).

Two motivations:

1. Description bloat. The CLI skill listed every subcommand as a
   trigger keyword, which made agents auto-load it for any mention
   of audio, transcription, or backgrounds — even when the task
   was just rendering a composition.
2. Body bloat. Voice tables, the .en-translates-non-English
   whisper rule, and codec selection guidance all loaded on
   every CLI invocation. With three preprocessing commands now
   in the CLI (tts, transcribe, remove-background), this is only
   going to grow.

The split keeps a single sibling (hyperframes-media), not three:
the commands share a workflow (preprocess asset → drop into
composition) and the same first-run-downloads-a-model pattern,
so they belong together. CLI skill now references hyperframes-media
from a one-paragraph "Asset Preprocessing" stub.

Doc references updated in README.md, CLAUDE.md,
docs/quickstart.mdx, and docs/guides/prompting.mdx.
2026-05-04 21:59:35 +00:00
JamesandClaude Opus 4.7 21243b6957 docs: lead with shape contrast for variable attributes
Follow-up on the PR #603 review. The previous fix named both attributes
but didn't make their distinct shapes / roles obvious; a reader could
still wonder "are these two views of the same data?". Now the doc
opens with the shape contrast (array of declarations vs object of
values) and the section closes with a numbered precedence layering so
the merge order is unambiguous.

- compositions.md: replaced the bullet list with a shape-first
  description ("JSON array of declarations" vs "JSON object keyed by
  variable id"), an explicit "they aren't redundant" line, and a
  numbered list of the three precedence layers (declared default →
  host data-variable-values → CLI --variables).
- skills/hyperframes-cli/SKILL.md: highlighted the same shape contrast
  inside the parametrized-renders paragraph (declarations array vs
  values object).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:26:20 +00:00
JamesandClaude Opus 4.7 22bcd7a18b docs: clarify declaration vs override attributes (PR #603 review)
James pointed out (compositions.md:33, SKILL.md:121) that the prose
referenced `data-variable-values` while the example below showed
`data-composition-variables`, leaving readers to wonder if the two
names referred to the same thing. They don't: one declares, the other
overrides per-instance. Both are now named at first mention and the
declare-vs-override split is called out explicitly.

- packages/cli/src/docs/compositions.md: replaced the single intro
  sentence with a two-bullet list ("data-composition-variables
  declares, data-variable-values overrides per-instance") and a
  follow-up explaining where the CLI fits in.
- skills/hyperframes-cli/SKILL.md: rewrote the parametrized-renders
  paragraph so declaration (data-composition-variables) and override
  (--variables) are distinct sentences, with the per-instance attribute
  parenthetical for completeness.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:25:42 +00:00
JamesandClaude Opus 4.7 211a9214d0 docs(skills): teach agents the variables system across SKILL.md + docs
Distribution PR for the variables feature stack: tells agents how to
declare, read, and override variables across the four authoring
surfaces.

skills/hyperframes/SKILL.md:
- Added data-variable-values + data-composition-variables to the
  data-attributes tables (host element + <html> root respectively).
- New "Variables (Parametrized Compositions)" section right after
  "Composition Structure". Three-step pattern (declare / read /
  override), full worked example with enum variable, sub-comp
  per-instance pattern with two hosts sharing a source, and rules
  of thumb (always provide defaults; read once, not in frame loops;
  use --strict-variables in CI; type validation behavior).

skills/hyperframes-cli/SKILL.md:
- Added --variables, --variables-file, --strict-variables to the
  render flag table.
- Short paragraph below the table explaining the parametrized-render
  pattern with a forward reference to the hyperframes skill.

docs/packages/core.mdx:
- Added a code snippet showing getVariables<T>() inside a composition
  and validateVariables/formatVariableValidationIssue for tooling.

packages/cli/src/docs/compositions.md (the in-CLI `npx hyperframes
docs compositions` content):
- Replaced the hand-rolled JSON.parse(host.dataset.variableValues)
  pattern with the modern getVariables() pattern.

This is PR 4 of the 4-PR stack. The openai/plugins mirror is a
separate follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 20:25:42 +00:00
JamesandClaude Opus 4.7 d2ca45ef75 feat(cli): add remove-background command for transparent video
Adds `hyperframes remove-background` — a local-AI subcommand that mattes a
video or image with the u2net_human_seg ONNX model and emits a transparent
WebM (VP9-alpha), ProRes 4444 .mov, or RGBA PNG. Drops directly into any
composition's <video> tag — no green screen, no API keys, no upload.

Auto-picks the fastest available execution provider via onnxruntime-node:
CoreML on Apple Silicon, CUDA when HYPERFRAMES_CUDA=1, CPU otherwise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-04 04:17:51 +00:00
Miguel Ángel 15ee63c6e7 fix: harden CLI edge-case repros (#591)
## Problem

I reproduced the selected open issue batch one by one and confirmed the reports were valid. The fixes all touch the CLI/runtime capture boundary, then the follow-up regression run exposed one over-broad runtime change in sub-composition host visibility and one CI-only baseline trap.

Closes #590, #589, #588, #587, #586, and #584.

## What this fixes

### CLI/runtime edge cases

- Makes the GSAP infinite-repeat lint rule ignore JavaScript comments, so literal `repeat:-1` text in comments is not flagged.
- Lets the compositions CLI inspect `<template>` content, count visual-only template descendants, estimate simple GSAP durations, and suppress root `data-start` warnings in sub-composition lint mode.
- Preserves runtime bootstrap scripts when body scripts are coalesced, and injects the runtime into a real `<head>` when source HTML has no head.
- Keeps #589 fixed by loading and rendering template-wrapped sub-composition content, while restoring host visibility to the shorter of the authored parent clip window and the child composition live timeline.
- Resolves snapshot/validate viewport size from root `data-width` / `data-height` instead of falling back to 1920x1080.
- Skips fully off-frame text boxes during contrast sampling and bounds-checks ring samples so contrast output no longer emits `null:1` / `NaN:1`.
- Marks muted videos as `data-has-audio="false"` in the core timing compiler, which fixes the same-src muted `<video>` + separate `<audio>` StaticGuard case.
- Keeps user-authored `hf-seek` listeners reachable during capture by preventing author scripts from being merged into the runtime bootstrap path.

### Shared helper cleanup

- Removes the stale producer-local timing compiler duplicate; producer compilation now consumes the core timing compiler.
- Centralizes HTML document helpers in core: fragment parsing, embedded runtime stripping, head/body script injection, and early-head injection.
- Centralizes the CLI layout/snapshot static HTML server.
- Adds browser-safe core subpath helpers for Lottie readiness and CLI screenshot clip calculation; Studio's Vite config keeps the screenshot clip helper self-contained so clean-checkout test startup does not value-import core `.ts` source.
- Replaces the engine parity-contract copy with a core re-export.
- De-duplicates render-job cleanup and Studio static file-serving callbacks.

### Regression hardening

- Replaces the embedded-runtime script stripping regex with a script-tag scanner that handles closing tags like `</script >`.
- Escapes inline script bodies before wrapping them in `<script>` tags, so authored `</script` and `<!--` text cannot break out of the injected wrapper script.
- Shares media-duration clamping between core and producer, with a 50 ms tolerance for ffprobe precision drift between local and CI media stacks.
- Pins the affected style fixture SFX durations in source so style-1 and style-9 compile deterministically.
- Restores the `vfr-screen-recording` video golden to the CI-stable baseline; the current CI failure showed the Linux render matches the old golden, while the locally refreshed macOS golden was the mismatch.

## Root cause

The CLI paths had accumulated assumptions that held for simple direct-root landscape compositions but not for current composition patterns: DOM queries did not enter template content, snapshot/validate used a fixed viewport, runtime and author scripts shared a coalescing bucket, and timing compilation treated every video as audio-bearing unless authors manually overrode it.

The style shard failures were not product regressions. Local and CI media probing disagreed on the short SFX clip duration by about 45 ms, and the compiler was clamping authored durations to the locally probed value. The shared clamp tolerance preserves explicit author/source durations for small probe precision differences while still clamping real overflows.

The vfr fast-shard failure was a bad baseline refresh: CI actual frames matched the old `vfr-screen-recording` baseline at 40+ dB PSNR, but mismatched the macOS-refreshed golden at ~18-22 dB. The fix is to keep the Docker/Linux-stable video golden and only retain the deterministic compiled snapshot change.

The sub-composition regression came from treating a host's authored parent window as the only visibility boundary. That made settled child overlays stay visible after their own live GSAP timeline ended. The corrected runtime behavior respects both contracts: parent clips still bound where the host can appear, and the child live timeline can end the host earlier.

## Verification

### Local checks

- `bunx oxfmt --check packages/core/src/runtime/init.ts packages/core/src/runtime/init.test.ts`
- `bunx oxlint packages/core/src/runtime/init.ts packages/core/src/runtime/init.test.ts`
- `bun run --cwd packages/core test src/runtime/init.test.ts`
- `bun run --cwd packages/cli test src/commands/compositions.test.ts src/utils/compositionViewport.test.ts`
- `bun run build:hyperframes-runtime`
- `bun run --cwd packages/producer test --keep-temp --sequential style-12-prod style-5-prod`
- `bun run --cwd packages/producer test --sequential vfr-screen-recording hdr-hlg-regression style-7-prod`
- `bun run --cwd packages/core test src/compiler/htmlCompiler.test.ts src/compiler/timingCompiler.test.ts src/index.test.ts`
- `bunx oxfmt --check packages/core/src/compiler/timingCompiler.ts packages/core/src/compiler/htmlCompiler.ts packages/core/src/compiler/htmlCompiler.test.ts packages/core/src/compiler/index.ts packages/core/src/index.ts packages/core/src/index.test.ts packages/producer/src/services/htmlCompiler.ts`
- `bunx oxlint packages/core/src/compiler/timingCompiler.ts packages/core/src/compiler/htmlCompiler.ts packages/core/src/compiler/htmlCompiler.test.ts packages/core/src/compiler/index.ts packages/core/src/index.ts packages/core/src/index.test.ts packages/producer/src/services/htmlCompiler.ts`
- `bun run --cwd packages/core typecheck`
- `bun run --cwd packages/producer typecheck`
- `bun run --cwd packages/producer test --sequential style-1-prod style-9-prod`
- `bun run --filter @hyperframes/studio test` with `packages/core/dist` temporarily hidden to simulate clean-checkout config loading
- `git diff --check`

### CI artifact checks

- Inspected failed run `25225854394` job `73969147096`: style-1 failed only on `click-sfx` `1.044898` vs `1` duration/end.
- Inspected failed run `25225854394` job `73969147061`: style-9 failed only on SFX `1.044898`-based duration/end mismatches.
- Inspected failed run `25225854394` job `73969147048`: `vfr-screen-recording` compilation/audio passed, visual failed after comparing against the macOS-refreshed golden.
- Compared the first 10 uploaded CI vfr failure frames against the restored old baseline; minimum PSNR was `40.444705`, above the fixture threshold of `28`.

### Repro checks

- `bun packages/cli/src/cli.ts lint /tmp/hf-590-repro` now passes without `gsap_infinite_repeat`.
- `bun packages/cli/src/cli.ts snapshot /tmp/hf-587-repro --at 0.5 --timeout 1000` now writes a 1080x1920 PNG.
- `bun packages/cli/src/cli.ts validate /tmp/hf-588-repro --timeout 500` no longer emits `null:1` / `NaN:1` contrast output.
- `bun packages/cli/src/cli.ts validate /tmp/hf-586-repro --timeout 500 --contrast false` no longer emits the muted-video StaticGuard contract error.
- `bun packages/cli/src/cli.ts compositions /tmp/hf-589-gsap-repro` now reports `foo 0.5s 1920x1080 1 element`.
- `bun packages/cli/src/cli.ts snapshot /tmp/hf-589-gsap-repro --at 0.25 --timeout 2000` captures the expected template-backed red frame.
- `bun packages/cli/src/cli.ts snapshot /tmp/hf-584-repro --at 0.5,1.5 --timeout 500` captures the expected post-seek green frame.

### Browser verification

- Refreshed the local side-by-side comparison page at `qa-artifacts/pr-591-video-compare/index.html`.
- Served the comparison page locally and used `agent-browser` to load `style-12-prod`, play both videos quickly to the failed window, pause, and inspect the side-by-side frame.
- Browser proof screenshot: `qa-artifacts/pr-591-video-compare/browser-proof/fixed-style12-labeled.png`.
- Browser proof recording: `qa-artifacts/pr-591-video-compare/browser-proof/fixed-style12.webm`.
- Earlier Studio proof artifacts remain local-only: `qa-artifacts/dedupe-refactor-preview.png`, `qa-artifacts/dedupe-refactor-preview-after-play.png`, `qa-artifacts/dedupe-refactor-preview.webm`.

## Notes

- Browser proof and CI diagnostic artifacts are intentionally local-only and not committed.
- Studio's Vite config intentionally keeps the thumbnail clip helper inline because Vite/Vitest config startup runs through Node's loader before package source `.ts` imports are transformed.
- The committed PR diff changes `vfr-screen-recording/output/compiled.html` but no longer changes `vfr-screen-recording/output/output.mp4` relative to `main`.
- I attempted a local `linux/amd64` Docker validation to mirror CI, but the local Docker build was blocked by Debian package download failures. The arm64 Docker image also cannot launch the x64 Puppeteer headless shell under OrbStack. The vfr baseline decision is therefore based on the uploaded CI artifact comparison above.
- I kept this validated issue batch in one PR because the fixes overlap the same CLI/runtime capture surfaces.
2026-05-02 00:00:08 +02:00
James 1fb4caddff docs(remotion-skill): only trigger on explicit migration ask
User feedback (jasonpurdy on X, https://x.com/jasonpurdy/status/2049985508701556855)
flagged that the remotion-to-hyperframes skill auto-triggered during an A/B
test of HyperFrames vs Remotion, producing a translated output instead of a
native HyperFrames composition. The user preferred the native version once he
disabled the skill.

The previous SKILL.md description listed four triggering conditions, three
of which were context-detection patterns (the user provides Remotion source,
pastes a Remotion entry point, links a Remotion repo). Agents could
interpret any of those as authoritative even when the user wasn't asking for
a migration.

Tighten the trigger gate so the skill only fires on an explicit migration
verb (port, convert, migrate, translate, rewrite as HyperFrames). Add
explicit NOT clauses for the common false-positive cases — including the
specific A/B-test case (the same video as my Remotion one — treat as a
fresh build). Default recommendation when uncertain: use the hyperframes
skill instead.

The body of the SKILL.md is unchanged — translation guidance is correct
once the gate is passed; this only tightens the gate itself.
2026-05-01 01:05:41 +00:00
Miguel Ángel 68bd52ac6d feat: add init tailwind flag (#577)
## Problem

Users who want Tailwind utilities in a plain HyperFrames composition currently have to know which Tailwind browser script to add and where to place it. The first pass added `--tailwind`, but review caught three production-facing gaps: the CDN version was major-only, the insertion helper could silently no-op on compact HTML, and the render pipeline did not explicitly wait for Tailwind's async browser compilation before capturing frame 0.

There is also a version-specific agent risk: HyperFrames `init --tailwind` uses Tailwind v4.2 through `@tailwindcss/browser@4.2.4`, while `packages/studio` still uses Tailwind v3. Without a dedicated skill, agents can easily mix v3 `tailwind.config.js` / `@tailwind` patterns into v4 browser-runtime composition HTML.

## What this fixes

- Adds `hyperframes init --tailwind`.
- Pins the Tailwind browser runtime to `@tailwindcss/browser@4.2.4/dist/index.global.js` with SRI and `crossorigin="anonymous"`.
- Injects a `window.__tailwindReady` promise next to the browser runtime.
- Makes frame capture wait for `window.__tailwindReady` in both screenshot and BeginFrame capture modes before capturing frame 0.
- Inserts Tailwind support before `</head>` case-insensitively, including single-line/minified heads, and falls back to prepending when there is no head tag.
- Skips recursive Tailwind injection under `.git`, `dist`, and `node_modules`.
- Tracks whether init used Tailwind in the existing `init_template` telemetry event.
- Adds a first-party `/tailwind` skill for Tailwind v4.2 browser-runtime HyperFrames composition work.
- Updates README, docs, generated project agent files, CLI skill guidance, and plugin metadata so the Tailwind skill is discoverable.
- Documents the browser-runtime tradeoff and production/offline guidance.

## Root cause

`scaffoldProject()` copied the selected example and patched media placeholders, then immediately wrote project metadata and `package.json`. There was no optional post-copy step for framework-specific HTML support. The initial Tailwind post-copy step also treated the browser runtime like a static script, but Tailwind compiles utilities asynchronously after scanning the DOM, so the capture engine needed an explicit readiness contract.

On the agent side, the repo exposed HyperFrames, CLI, GSAP, registry, and runtime adapter skills, but had no Tailwind-specific instruction to separate the v4 browser-runtime composition path from Studio's v3 internal setup.

## Verification

### Local checks

- `bunx vitest run packages/cli/src/commands/init.test.ts`
- `bun run --filter @hyperframes/cli test src/commands/init.test.ts`
- `bun run --filter @hyperframes/cli typecheck`
- `bun run --filter @hyperframes/engine typecheck`
- `bun run lint:skills`
- `bun run lint`
- `npx skills add . --list` showed 12 local skills, including `tailwind`.
- `bunx oxfmt --check packages/cli/src/commands/init.ts packages/cli/src/commands/init.test.ts packages/cli/src/telemetry/events.ts packages/engine/src/services/frameCapture.ts docs/packages/cli.mdx`
- `bunx oxfmt --check README.md docs/quickstart.mdx docs/packages/cli.mdx CLAUDE.md packages/cli/src/templates/_shared/CLAUDE.md packages/cli/src/templates/_shared/AGENTS.md skills/hyperframes-cli/SKILL.md skills/tailwind/SKILL.md .codex-plugin/plugin.json .cursor-plugin/plugin.json`
- `bunx oxlint packages/cli/src/commands/init.ts packages/cli/src/commands/init.test.ts packages/cli/src/telemetry/events.ts packages/engine/src/services/frameCapture.ts`
- `git diff --check`
- Lefthook pre-commit: lint/format/typecheck for code commit; format for docs/skill commit
- Lefthook commit-msg: commitlint

Generated-project render proof at `/tmp/hf-tailwind-render-proof`:

- `bun packages/cli/src/cli.ts init /tmp/hf-tailwind-render-proof --example blank --tailwind --non-interactive --skip-skills`
- Added a temporary Tailwind-only card using `flex`, `h-full`, `w-full`, `items-center`, `justify-center`, `bg-slate-950`, `rounded-3xl`, `bg-white`, `px-20`, `py-12`, `text-8xl`, `font-black`, `text-black`, and `shadow-2xl`.
- `bun packages/cli/src/cli.ts lint /tmp/hf-tailwind-render-proof` → 0 errors, 0 warnings.
- `bun packages/cli/src/cli.ts validate /tmp/hf-tailwind-render-proof` → 0 errors, 0 regular warnings; the temp proof still reports validator contrast warnings even though the rendered/browser pixels show black text on white background.
- `bun packages/cli/src/cli.ts render /tmp/hf-tailwind-render-proof --workers 1 --fps 24 --quality draft --output /tmp/hf-tailwind-render-proof-artifacts/output.mp4`
- Render compiler inlined both GSAP and `https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.2.4/dist/index.global.js`.
- `ffprobe -v error -select_streams v:0 -show_entries stream=codec_name,width,height,r_frame_rate,duration -of default=noprint_wrappers=1 /tmp/hf-tailwind-render-proof-artifacts/output.mp4` → H.264, 1920x1080, 24fps, 10s.
- Extracted frame-0 proof: `/tmp/hf-tailwind-render-proof-artifacts/frame-000.png`.

### Browser verification

- Started Studio preview for `/tmp/hf-tailwind-render-proof`.
- Used `agent-browser` to open `http://localhost:5194`.
- Verified the Tailwind-styled composition rendered in Studio preview.
- Captured screenshot: `/tmp/hf-tailwind-render-proof-artifacts/browser/tailwind-preview.png`.
- Captured agent-browser-driven recording: `/tmp/hf-tailwind-render-proof-artifacts/browser/tailwind-preview.webm`.
- Served the PR worktree locally and used `agent-browser` to open the new Tailwind skill proof page.
- Verified the browser-visible skill content includes `@tailwindcss/browser@4.2.4`.
- Captured screenshot: `/Users/miguel07code/.codex/worktrees/pr-577-tailwind-comments/tmp/agent-browser-proof/tailwind-skill.png`.
- Captured agent-browser-driven recording: `/Users/miguel07code/.codex/worktrees/pr-577-tailwind-comments/tmp/agent-browser-proof/tailwind-skill.webm`.

## Notes

- This still intentionally uses Tailwind's browser runtime rather than adding a generated Tailwind build pipeline. That keeps `hyperframes init --tailwind` small and compatible with the current no-install generated project workflow.
- The `/tailwind` skill cites official Tailwind v4 docs plus community skill references, but its instructions are HyperFrames-specific and tuned for the pinned v4.2 browser runtime.
- Browser proof artifacts are local-only under `/tmp/hf-tailwind-render-proof-artifacts/` and `tmp/agent-browser-proof/` and intentionally not committed.
2026-05-01 00:07:00 +02:00
Miguel Ángel 8662598a3a docs: add runtime adapter skills (#572)
* docs: add runtime adapter skills

* docs: address adapter skill review comments
2026-04-30 16:08:43 +02:00
Vance Ingalls 22f0e6a5cd feat(skills): design.md integration, shared video references, Claude Design gaps (#549)
## What

Major skill infrastructure update: design.md support, shared video-composition references, and creative direction patterns extracted from website-to-hyperframes into the base hyperframes skill.

## Changes

### design.md Integration (lightweight)
- Step 0a reads any format design.md (YAML, prose, tables) — no format mandate
- Brand colors/fonts are strict; video layout adapts per video-composition.md
- Font warning gate: warns user if design.md names fonts without local .woff2 files
- Design picker generates spec-compliant design.md with YAML frontmatter + prose
- Picker generates contextual options from user's prompt (3-4 architectures, 5-6 palettes, 3 type pairings)

### Shared Video References (extracted from website-to-hyperframes)
- `video-composition.md` — density, scale, color presence, frame composition rules. Light canvas guidance (don't override user palette). **Always read.**
- `beat-direction.md` — per-beat planning (concept → mood → choreography verbs → transition), rhythm templates by video type
- `techniques.md` — 11 visual techniques with code patterns (SVG drawing, Canvas 2D, kinetic type, Lottie, etc.)
- `narration.md` — pacing, tone, script structure, number pronunciation, hooks
- `motion-principles.md` — gained image motion treatment + load-bearing GSAP rules

### Claude Design Transfer Brief (6 gaps applied)
1. Discovery step for exploratory requests (audience, platform, priority, variations)
2. Anti-scope-creep: "build what was asked, every element earns its place"
3. Read-source discipline: "read actual files, don't guess"
4. Rhythm planning: declare scene rhythm before implementing
5. Variations as first-class output for exploratory requests
6. Two-phase verification: fast checks block, slow checks parallel

### Prompt Expansion Updated
- Uses beat-direction format (concept → mood → verbs → depth layers)
- Rhythm declaration before scene breakdown
- References video-composition.md and beat-direction.md

### Key Design Decision
**design.md = brand truth, not video layout spec.** Background color is strict from design.md (don't switch light to dark). Video-composition rules teach how to make any palette work cinematically.

## Files Changed (16)

**New shared references:**
- `skills/hyperframes/references/video-composition.md`
- `skills/hyperframes/references/beat-direction.md`
- `skills/hyperframes/references/techniques.md`
- `skills/hyperframes/references/narration.md`

**Updated:**
- `skills/hyperframes/SKILL.md` — discovery, anti-scope-creep, rhythm, variations, two-phase verify, new references
- `skills/hyperframes/references/prompt-expansion.md` — beat-direction format
- `skills/hyperframes/references/motion-principles.md` — image treatment + GSAP rules
- `skills/hyperframes/references/design-picker.md` — contextual generation
- `skills/hyperframes/visual-styles.md` — YAML token blocks per preset
- `skills/hyperframes/house-style.md` — design.md precedence
- `skills/hyperframes/templates/design-picker.html` — spec-compliant output
- `skills/website-to-hyperframes/references/*` — now reference shared files

## Test plan

- [x] Design picker generates and serves correctly
- [x] Picker output is spec-compliant design.md
- [x] Composition built from picker design.md renders in Studio
- [x] Before/after eval: 4 topics × 2 versions showing skill guidance impact
- [x] Light canvas compositions respect user palette (don't switch to dark)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-04-29 17:48:54 -07:00
James Russo d01685d695 Merge pull request #517 from heygen-com/skill/r2hf-skill-body
feat(skills): remotion-to-hyperframes SKILL.md + orchestrator (7/7)
2026-04-27 22:19:03 -07:00
James Russo f22d9bfabe Merge pull request #516 from heygen-com/skill/r2hf-references
feat(skills): remotion-to-hyperframes references (6/7)
2026-04-27 22:18:44 -07:00
James Russo 40339a65b9 Merge pull request #515 from heygen-com/skill/r2hf-corpus-t4
feat(skills): remotion-to-hyperframes corpus T4 (5/7)
2026-04-27 22:18:14 -07:00
James Russo 12945238cc Merge pull request #509 from heygen-com/skill/r2hf-corpus-t3
feat(skills): remotion-to-hyperframes corpus T3 (4/7)
2026-04-27 22:17:55 -07:00
James Russo 4ab4576adf Merge pull request #508 from heygen-com/skill/r2hf-corpus-t1-t2
feat(skills): remotion-to-hyperframes corpus T1+T2 (3/7)
2026-04-27 22:17:37 -07:00
James Russo b27385ba1a Merge pull request #507 from heygen-com/skill/r2hf-eval-harness
feat(skills): remotion-to-hyperframes eval harness (2/7)
2026-04-27 22:14:29 -07:00
James Russo 3fa094c5c5 Merge pull request #506 from heygen-com/skill/r2hf-scaffold
feat(skills): scaffold remotion-to-hyperframes skill (1/7)
2026-04-27 22:12:11 -07:00
James b7769b2364 feat(skills): remotion-to-hyperframes SKILL.md + orchestrator (7/7)
The leaf PR. Replaces the placeholder SKILL.md from PR 1 with the real
5-step workflow that loads the per-topic references on demand
(skill-creator's progressive-disclosure pattern), and adds a top-level
orchestrator that runs every tier and reports a pass/fail summary.

SKILL.md changes:
  - Frontmatter unchanged from PR 1 (already covers the trigger phrases
    and out-of-scope cases)
  - Body rewritten as a 5-step workflow:
      1. Lint (load escape-hatch.md if blockers)
      2. Plan (load api-map.md, then per-topic references on demand)
      3. Generate (HF index.html with paused GSAP timeline)
      4. Validate (render_diff.sh against per-tier threshold)
      5. Document gaps (TRANSLATION_NOTES.md if needed)
  - Includes a "Source contains -> Load reference" table so the agent
    only loads the references the source actually needs
  - Documents the validated baseline numbers (T1 0.974, T2 0.985,
    T3 0.953, T4 8/8) so reviewers can reproduce
  - Calls out the critical Remotion encoder config (PNG + BT.709) that
    avoids the ~0.05 SSIM hit from yuvj420p vs yuv420p

Orchestrator (assets/test-corpus/run.sh):
  - Iterates tier-1-* through tier-4-* directories
  - T1-T3: setup -> lint -> npm install (lazy) -> render Remotion ->
           render HF -> SSIM diff at the fixture's expected threshold ->
           generate strip on failure
  - T4: validate.sh (lint-only)
  - Emits run-report.json with per-tier pass/fail and aggregate counts
  - Accepts a single-tier argument for fast iteration: ./run.sh tier-1-title-card

Validated end-to-end on a clean checkout:
    ▶ tier-1-title-card → mean SSIM 0.9739 (≥ 0.95) ✓
    ▶ tier-2-multi-scene → mean SSIM 0.985292 (≥ 0.95) ✓
    ▶ tier-3-data-driven → mean SSIM 0.952941 (≥ 0.9) ✓
    ▶ tier-4-escape-hatch → 8/8 cases ✓
    passed 4/4, failed 0, skipped 0

Closes the 7-PR stack: scaffold, eval harness, 4 tiers of corpus,
references, and now the SKILL.md body that ties everything together.
2026-04-28 00:00:10 +00:00
James 890f305cd1 feat(skills): remotion-to-hyperframes references (6/7)
Adds 11 progressively-disclosed reference files that the skill loads on
demand during translation. Total ~1500 LOC, every file under 200 lines
(skill-creator's progressive-disclosure budget).

  api-map.md         the comprehensive Remotion -> HF translation table
                     (the index; loaded at start of translation)
  timing.md          interpolate, spring (validated configs), easing,
                     count-up, stagger
  sequencing.md      Sequence, Series, Loop, Freeze, AbsoluteFill,
                     Composition root
  media.md           Audio, Video, Img, IFrame, OffthreadVideo,
                     staticFile, asset paths
  transitions.md     @remotion/transitions presentations -> manual GSAP
                     crossfades or HF shader-transitions
  lottie.md          @remotion/lottie -> HF lottie adapter (incl. AE
                     feature limitations note)
  fonts.md           Google Fonts loading, local @font-face, system
                     fallback noise floor
  parameters.md      Zod schemas, defaultProps, sync vs async
                     calculateMetadata
  escape-hatch.md    when to bow out + the runtime interop pattern
                     from PR #214
  limitations.md     known caveat patterns (volume ramps, Loop with
                     state, custom presentations, code-split components)
  eval.md            how to run the validation harness, threshold rule
                     of thumb, what the noise floor looks like

The references are evidence-driven rather than speculative: every spring
config, easing curve, and SSIM threshold is documented from the
validated T1/T2/T3 calibration runs (mean 0.974 / 0.985 / 0.953). The
escape-hatch boundaries match the lint blockers in PR 2 and the T4
fixtures in PR 5.

Replaces the placeholder .gitkeep from PR 1.
2026-04-27 23:55:51 +00:00
James 7509916227 feat(skills): remotion-to-hyperframes corpus T4 (5/7)
Adds the escape-hatch tier — lint-only fixtures that test the skill's
ability to refuse translation cleanly when it sees patterns that don't map
to HF's seek-driven model.

Cases (8 total):
  01-use-state.tsx          blocker: r2hf/use-state
  02-use-effect-deps.tsx    blocker: r2hf/use-effect-deps (multi-line body
                            with internal commas — regression target for
                            the regex bug fix in PR 2)
  03-async-metadata.tsx     blocker: r2hf/async-metadata
  04-third-party-react.tsx  blocker: r2hf/third-party-react-ui (@mui/material)
  05-lambda-config.tsx      blocker: r2hf/lambda-import
  06-warnings-only.tsx      warnings: delayRender / useCallback / useMemo
                            (no blockers — translates after dropping wrappers)
  07-custom-hook.tsx        warning: r2hf/custom-hook (pure useFadeIn)
  08-mixed.tsx              multiple blockers + warnings (aggregate test)

Each case documents:
  - The Remotion pattern it demonstrates
  - Why it's a blocker / warning / info
  - What the skill should do (refuse / drop-and-translate / translate-as-is)

Validation harness (validate.sh):
  Runs lint_source.py against each case, asserts:
    - Each expected blocker rule fires with severity="blocker"
    - Each expected warning rule fires with severity="warning"
    - lint_source.py exit code is 1 when blockers expected, 0 otherwise

T4 has no renders to diff. The skill is graded on lint correctness — that's
the gate that decides whether to translate or recommend the runtime interop
pattern from PR #214.

Result: 8/8 cases pass.
2026-04-27 23:55:24 +00:00
James efa7164ab4 feat(skills): remotion-to-hyperframes corpus T3 (4/7)
Adds the data-driven tier — a purpose-built fixture (option 2 from the
stack discussion, not a port of PR #214's examples/remotion-full/) that
exercises the realistic shape of a production Remotion composition
without using the runtime adapter.

Stargazed.tsx (10s @ 30fps, 1280x720):
  Sequence 0-3s    TitleScene   (title + subtitle)
  Sequence 3-7s    StatsScene   (3 reused StatCards staggered 12 frames apart)
  Sequence 7-10s   OutroScene   (UnderlinedText with scaleX-from-left underline)

Composition shape exercises:
  - <Composition schema={z.object({...})} defaultProps={...} />
  - nested array prop (stats[]) materialized as repeated HTML
  - custom React subcomponents (StatCard, AnimatedNumber, UnderlinedText)
    reused with different props
  - per-instance delay via prop (delayInFrames -> GSAP timeline offset)
  - frame-driven count-up (AnimatedNumber, manual cubic ease-out)
  - two different spring configs in the same composition
    (damping:12 -> back.out(1.4), damping:14 -> back.out(1.2))
  - useCurrentFrame, useVideoConfig

Translation choices documented in README.md and expected.json:
  - Zod props -> data-* on root #stage div
  - Custom subcomponents inline as repeated HTML using prop interface
    as the template
  - AnimatedNumber's frame-driven count-up -> GSAP onUpdate tween on a
    { v: 0 } counter object, ease power3.out
  - Two different spring configs -> two different back.out overshoots
    (1.4 vs 1.2 approximates the damping difference)
  - delayInFrames={i * 12} -> GSAP offset (i * 0.4)s

Validated end-to-end: rendered Remotion baseline + HF translation, ran
scripts/render_diff.sh.
  measured mean SSIM 0.953
  measured min  SSIM 0.927
  measured p05  SSIM 0.938
  threshold 0.90 (~0.04 below p05)

The wider gap vs T1/T2 reflects T3's bigger approximation budget
(2 spring instances + count-up timing + font fallback on multiple text
sizes). Mean SSIM below 0.90 = structural mismatch (wrong durations,
wrong stagger, missing prop wiring), not approximation drift.

Same Remotion config as PR 3: setVideoImageFormat("png") +
setColorSpace("bt709") to match HF's yuv420p output.

Lint: 9 files scanned, 0 blockers / 0 warnings / 0 infos.
oxlint, oxfmt, typecheck all pass.

The fixture is not yet wired into CI; render + diff is documented in
README.md and runs by hand via the harness from PR 2. PR 7's orchestrator
will wire all four tiers into a CI eval run.
2026-04-27 23:54:43 +00:00
James 9ff46d79b7 feat(skills): remotion-to-hyperframes corpus T1+T2 (3/7)
Adds the first two test fixtures the skill is graded against. Each fixture
ships:
  - remotion-src/  full Remotion project (package.json, src/, remotion.config.ts, tsconfig.json)
  - hf-src/        hand-translated HyperFrames composition (index.html)
  - expected.json  tier metadata + SSIM threshold + translation notes + measured validation
  - README.md      human walk-through of the translation choices
  - setup.sh       (T2 only) generates binary assets (PNG, WAV) via ffmpeg

T1 — title-card-fade
- 3 s @ 30 fps, 1280x720
- Single AbsoluteFill, single useCurrentFrame interpolate
  with multi-segment input [0,15,75,90] -> [0,1,1,0]
- Validated mean SSIM 0.974, threshold 0.95
  (~0.025 gap from font-fallback divergence between Remotion's bundled
   Chromium and HF's chrome-headless-shell)

T2 — title-image-outro
- 6 s @ 30 fps, 1280x720, three Sequences (TitleScene, ImageScene, OutroScene)
- Exercises spring, interpolate, Audio, Img, staticFile
- Spring -> GSAP back.out(1.4) translation
- Validated mean SSIM 0.985, threshold 0.95
  (translation came out cleaner than predicted; spring->back.out drift was
   smaller than the ~0.05 budget I'd expected)
- setup.sh generates a 200x200 blue PNG and a 6 s silent WAV via ffmpeg
  so binaries stay out of the repo

Calibration done end-to-end: rendered Remotion baseline + HF translation,
ran scripts/render_diff.sh, set thresholds ~0.02 below measured p05.

Critical Remotion config: setVideoImageFormat("png") + setColorSpace("bt709").
The default JPEG output writes yuvj420p (full-range) which costs ~0.05 SSIM
vs HF's yuv420p (limited-range). Both fixtures' remotion.config.ts encode
this so render_diff.sh measures translation fidelity, not encoder differences.

Both fixtures lint clean (0 blockers via scripts/lint_source.py).
T2 staticFile() references correctly flagged as info-level findings.

The fixtures are not yet wired into CI — that comes with PR 7's orchestrator.
For now, render and eval are documented in each README and run by hand.
2026-04-27 23:54:28 +00:00
James 70e0b8bf87 feat(skills): remotion-to-hyperframes eval harness (2/7)
Adds the deterministic eval primitives the skill calls into:

  scripts/render_diff.sh    SSIM diff between two MP4s, JSON summary, configurable threshold
  scripts/frame_strip.sh    side-by-side comparison strip for visual debugging
  scripts/lint_source.py    pre-translation lint over Remotion source — blocks/warnings/infos

The harness is decoupled from the render pipeline: it accepts paths to
already-rendered MP4s. The skill orchestrator (PR 7) drives both renders
and feeds the outputs in. This keeps the harness usable in CI, in
sandboxes, and on any machine that has ffmpeg without needing the full
Remotion + HyperFrames toolchain.

Lint catches the patterns from the skill's out-of-scope list:
- useState / useReducer (state-machine driven animation)
- useEffect with deps (side effects)
- async calculateMetadata (Promise-returning composition metadata)
- @remotion/lambda imports
- third-party React UI libraries (MUI, Chakra, Mantine, antd, shadcn, Radix, NextUI)
- delayRender / useCallback / useMemo (warnings)
- staticFile / interpolateColors (info — translatable but flagged)

Smoke test (scripts/tests/smoke.sh) exercises all three scripts against
synthetic inputs: identical ffmpeg testsrc videos pass at threshold 0.99,
different ffmpeg testsrc videos fail at 0.99, frame_strip produces a
strip.png, lint produces 0 blockers on a clean fixture and >=3 blockers
on a fixture that uses useState + useEffect + MUI + async metadata.

Validated locally: smoke.sh exits 0.
2026-04-27 23:54:09 +00: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 35b7043efa fix: harden skill dependency bootstrap 2026-04-27 15:57:28 -04:00
James 7ed3d0485a feat(skills): scaffold remotion-to-hyperframes skill (1/7)
Adds the directory + SKILL.md frontmatter for a new skill that translates
Remotion (React) compositions to HyperFrames (HTML+GSAP). This is the
foundation PR; subsequent PRs in the stack add the eval harness, test
corpus, translation references, and finally the SKILL.md body.

The frontmatter description enumerates trigger phrases and explicit
out-of-scope cases (useState/useEffect, async metadata, @remotion/lambda)
so the skill bows out cleanly when a Remotion composition isn't a clean
translation target — those should use the runtime interop pattern from
PR #214 instead.

Validated with skill-creator's package_skill.py.
2026-04-27 05:16:02 +00: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
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 b947966a8b feat(cli): add visual inspect command (#480)
* feat: add layout audit command

* feat: refine visual inspect command
2026-04-25 02:07:47 +02:00
Ular Kimsanov 309c74e864 Merge pull request #364 from ibrews/skill-load-bearing-gsap-rules
docs(website-to-hyperframes): add load-bearing GSAP authoring rules
2026-04-24 17:21:28 -04:00
Alex Coulombe 2cb933df61 style: format 2026-04-24 14:21:34 -04:00
Alex Coulombe 924fd2f145 docs(step-6-build): sharpen Rule 2 — name from() seek-past-end reset as root cause
Per review feedback on PR #364: the 'hero vanishes' failure has two
mechanisms. Primary: second tween's immediateRender overwrites the first
at construction time. Secondary: tl.from() resets to its declared from-
state when seeked past timeline end, which the capture engine triggers.
Both are now named so the rule has precise rationale, not just a pattern
to avoid.

Ref: https://github.com/heygen-com/hyperframes/pull/364#pullrequestreview-4167523103
2026-04-24 10:56:59 -04:00
ukimsanovandClaude Opus 4.6 c81ef50e2f feat(shader-transitions): support any aspect ratio + update skill
Add dynamic resolution to shader transitions and update Skeleton A
to use shaders on vertical compositions.

shader-transitions changes:
- webgl.ts: read dimensions from params instead of hardcoded constants
- capture.ts: accept width/height for html2canvas
- hyper-shader.ts: read data-width/data-height from composition root

skill + docs changes:
- Skeleton A now has 1 shader at hero reveal (s3→s4 midpoint)
- Removed "no shaders on vertical" limitation from docs
- Updated claude-design.mdx known limitations section

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-23 21:32:09 -04:00
ukimsanov ee7c6c3c24 refactor(claude-design-skill): template-first rewrite with bug fixes
Replace the rule-heavy Claude Design skill with a template-first
approach. Instead of teaching all rules from scratch (863 lines),
provide pre-valid skeletons where structural rules are embedded.
Claude Design fills in palette, content, and animations.

Key changes:
- Pre-valid HTML skeletons for social reel (vertical), launch teaser,
  product explainer, and cinematic title
- Mixed transitions: 2-3 shader transitions at key moments, rest
  hard cuts (matches professional video practice)
- autoAlpha toggles for non-anchor scenes (fixes invisible middle
  scenes caused by HyperShader's blanket opacity reset)
- Explicit first-anchor opacity fix (HyperShader browser mode never
  auto-shows the first anchor scene)
- No shaders on vertical (1080x1920) — WebGL canvas is hardcoded
  to 1920x1080 in webgl.ts
- Inline animation patterns (counter, stroke draw, stagger, float,
  bar chart, orbit, highlight sweep, safe CSS grain)
- Claude Design → Claude Code handoff workflow documented in
  README template and delivery step
- Troubleshooting table for black preview, invisible scenes, seeking
- Self-review checklist split: structural validity, brand accuracy,
  animation baseline
- Skill description updated per review feedback on PR #353 to
  disambiguate from the hyperframes skill on cross-surface routing

Bugs fixed by this rewrite (confirmed across demov4-1 through
demov4-6 and demov5-1 through demov5-5):
- First shader anchor invisible in every composition
- Non-anchor scenes killed by blanket querySelectorAll(".scene")
  opacity reset
- visibility toggles insufficient (opacity:0 persists after reset)
- Shaders on vertical compositions produce distorted transitions
2026-04-23 20:12:20 -04:00
Miguel Ángel 25d7a54330 docs: add Claude Design HyperFrames entry point (#353)
## Summary
- add a GitHub-hosted `claude-design-hyperframes` skill entry point that tells Claude Design to fetch the upstream HyperFrames skills tree
- add a dedicated Claude Design docs guide and link it from quickstart, prompting, and the README
- fix `@hyperframes/player` CDN docs to show a working ESM include and the explicit global-build fallback

## Verification
- `bunx oxfmt --check README.md docs/docs.json docs/guides/prompting.mdx docs/packages/player.mdx docs/quickstart.mdx packages/player/README.md docs/guides/claude-design.mdx skills/claude-design-hyperframes/SKILL.md`
- `bun run lint:skills`
- `bunx mintlify broken-links`
- browser-engine screenshots captured with Playwright CLI for the changed docs/source surfaces:
  - `/tmp/hyperframes-pr-artifacts/claude-design-guide-source.png`
  - `/tmp/hyperframes-pr-artifacts/player-docs-source.png`

## Notes
- `mintlify dev`, `mintlify validate`, and `mintlify export` stalled in this environment during preview/bootstrap, so I used the broken-links check plus screenshot-based browser fallback instead of claiming a full rendered-site pass.
- The GitHub entry-point setup reflects current Claude Design behavior discussed in the task: point Claude Design at the repo-hosted skill URL rather than a ZIP upload flow.
2026-04-23 22:55:00 +02:00
Alex Coulombe 731baebbaa docs(website-to-hyperframes): add load-bearing GSAP authoring rules
Add five animation-authoring rules to step-6-build.md that the linter
cannot catch but that silently ship broken output. Surfaced from two
independent builds (2026-04-20) where compositions passed lint and
still rendered elements invisible / unscrubbing.

Rules added:
- No iframes for captured content (don't scrub)
- Never stack transform tweens on one element (entrance + Ken Burns
  on same img silently kills it)
- Prefer tl.fromTo() over tl.from() inside .clip scenes
  (immediateRender interacts badly with scene boundaries)
- Ambient pulses must attach to seekable tl, not standalone gsap.to()
- Generalize the caption hard-kill rule to every scene-boundary exit
2026-04-21 13:09:54 -04:00
James Russo 4a55bc8673 feat(cli): add --lang and auto-infer phonemizer locale from voice prefix (#351)
* feat(cli): add --lang and auto-infer phonemizer locale from voice prefix

`hyperframes tts` was calling Kokoro's `model.create(text, voice=, speed=)`
with no language argument, so Kokoro's default phonemizer (en-us) was
applied regardless of the voice selected. Picking `ef_dora` or `jf_alpha`
and feeding it Spanish or Japanese text produced English-phonemized
output.

Closes #349.

- `manager.ts`: add `SUPPORTED_LANGS`, `inferLangFromVoiceId`, and
  `isSupportedLang`. Attach a `defaultLang` field to every bundled voice
  and expand the bundled list with `ef_dora`, `ff_siwis`, `jf_alpha`,
  `zf_xiaobei` so `--list` surfaces multilingual options.
- `synthesize.ts`: accept optional `lang: SupportedLang` in
  `SynthesizeOptions`, forward it to the Python worker as `argv[7]`.
  The worker introspects `Kokoro.create`'s signature and only passes
  `lang=` when the installed kokoro-onnx version supports it. Returned
  metadata now includes `lang` and `langApplied` so callers can detect
  silent no-ops. Bump the cached script filename to `synth-v2.py` so
  existing installs pick up the new script automatically.
- `commands/tts.ts`: add `--lang, -l` with validation against
  `SUPPORTED_LANGS`. Resolution order is explicit `--lang` > inferred
  from voice prefix > `en-us`. When explicit lang disagrees with the
  voice-implied lang (legitimate for stylized accents), emit a
  dim-level hint; suppress under `--json`. When kokoro-onnx silently
  ignores the kwarg, log that too. Update `--list` with a new
  "Lang code" column and add multilingual examples.
- Tests: new `manager.test.ts` covering every supported prefix, the
  unknown-prefix fallback, case-insensitivity, `isSupportedLang`
  validation, and a regression guard that every bundled voice has a
  valid `defaultLang` matching its ID.
- Docs: `docs/packages/cli.mdx` and `skills/hyperframes/references/tts.md`
  updated with the flag, examples, the espeak-ng dependency note for
  non-English phonemization, and the voice-prefix → lang table.

Backward compatibility:
- English voices (a*/b* prefixes) continue to phonemize as en-us / en-gb
  — no change.
- Non-English voices now phonemize correctly by default (bug fix, not a
  regression).
- Older kokoro-onnx versions that don't know the `lang` kwarg keep
  working via signature introspection; the CLI logs a dim note if
  `--lang` was requested but ignored.

Verification:
- `bun --cwd packages/cli test` — 128 tests pass (incl. 17 new).
- `bunx oxlint` and `bunx oxfmt --check` clean on changed files.
- `bun run build` succeeds.
- `npx tsx packages/cli/src/cli.ts tts --help` / `--list` render cleanly;
  invalid `--lang` produces a clean error with the valid-codes list.

* refactor(cli): simplify tts --lang implementation

Post-review cleanup on #351. Net -21 lines.

- Drop `defaultLang` field + `makeVoice()` helper from VoiceInfo —
  compute via `inferLangFromVoiceId(v.id)` at read time in listVoices.
  The only reader was the --list table; caching the derived value on
  every voice added a self-consistency invariant we had to test.
- Drop redundant `lang` field from SynthesizeResult — caller already
  knows the requested lang since it passed it in; only `langApplied`
  carries information the caller can't derive.
- Use `errorBox` for --lang validation to match the house style in
  render.ts (other validation errors already use errorBox).
- Reuse existing `langList` module constant in the validation error
  instead of re-joining SUPPORTED_LANGS.
- Inline `DEFAULT_LANG` — used once in inferLangFromVoiceId.
- Trim WHAT-restating comments and the duplicate prefix-enumeration
  JSDoc on inferLangFromVoiceId (VOICE_PREFIX_LANG already carries
  per-row comments).
- Clean up orphaned `synth*.py` files in ~/.cache/hyperframes/tts
  when writing the current versioned script, so repeated upgrades
  don't leak files.
- Drop the `EN-US` case-sensitive-rejection test assertion — the CLI
  lowercases input before validation, so accepting mixed case is a
  feature, not a bug.

Tests: 16/16 in `manager.test.ts`, 127/127 full CLI suite pass.
Lint + format + typecheck clean.
2026-04-20 10:51:00 -07:00
Ular KimsanovandClaude Opus 4.7 a78ec5ec76 fix(skill): all file paths use capture/ subfolder prefix (#345)
* fix(skill): all file paths use capture/ subfolder prefix

Step-1 was updated to capture into <project-dir>/capture/ but all
file-read instructions across steps 1-6 still used bare paths
(extracted/tokens.json, assets/hero.png). Agents following the skill
looked for files in wrong locations, producing broken compositions
with 404'd images and fonts.

- step-1: all 12+ file-read paths prefixed with capture/
- step-2: tokens.json and asset-descriptions.md paths fixed
- step-3: visible-text.txt path fixed
- step-4: asset-descriptions.md, asset examples, directory tree expanded
  to show capture/ children (screenshots/, assets/, extracted/)
- step-5: minor cleanup
- step-6: asset-descriptions.md path fixed, composition examples already
  correct (../capture/assets/)
- techniques.md: Lottie, video, font paths all prefixed

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

* fix(skill): address Copilot review — font comment path, add videos/ to tree

- techniques.md: comment says ../capture/assets/fonts/ (matches composition context)
- step-4 file tree: add videos/ under capture/assets/

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 05:01:25 +02:00
ukimsanovandClaude Opus 4.6 4e87f28cd9 fix: address PR #339 review — 7 issues
1. Catalog failure safety: warn when catalog is empty or throws, so
   capture doesn't silently produce zero images
2. Dead path: extract-audio-data.py → skills/gsap/scripts/ (was
   skills/hyperframes/scripts/)
3. --json fonts compat: emit both `fonts` (string[]) and
   `fontsDetailed` (FontToken[]) to avoid breaking external consumers
4. Restore .cursorrules writing alongside AGENTS.md + CLAUDE.md
5. .gitignore: remove over-broad `projects/` and `videos/` entries,
   keep scoped `cursor-tests/` and `launch-video*/`
6. agentPromptGenerator: mark unused params as reserved with comments,
   remove _animations from buildPrompt
7. Cookie filter: threshold 20 → 8 chars to preserve footer copy like
   "© 2026 Stripe" (16 chars) and "Privacy & Terms" (15 chars)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-19 15:34:15 -04:00
ukimsanov 517e327294 docs(skill): render step is on-demand, not automatic
Preview is the delivery — scrub through it, iterate on tweaks, only render
once the user explicitly asks ("render it", "make the final", "I'm happy").
Rendering takes minutes per pass and is wasted work if the user wants any
changes after seeing it.

- step-7-validate: rename Render section to "Render (on-demand only)" and
  make the trigger criteria explicit
- SKILL.md: step-7 summary updated to "Deliver the preview to the user
  first — only render to MP4 on explicit request"

Made-with: Cursor
2026-04-19 08:43:59 -04:00
ukimsanov 1a69cde4be docs(skill): shader/audio/render/snapshot guidance from regression evidence
Adds decision guidance and conventions the 8-site regression test exposed as
blind spots — agents had the capability but never reached for it.

step-1-capture:
- Clarify capture goes into <project-dir>/capture/ so capture artifacts stay
  isolated from later build files (SCRIPT/STORYBOARD/DESIGN/compositions/)
- 7/8 regression tests already did this; codify as the convention

step-4-storyboard:
- Add "When to pick which" decision table for shader vs CSS vs hard cut
  transitions. Shader transitions were available but used in 0/8 tests —
  every test defaulted to CSS. The table frames shaders as "reveals, reaction
  shots, brand moments" vs CSS as "connective tissue"
- Update technique count (10 → 11)

step-6-build:
- Mid-scene activity table gets a new row for audio-reactive logo/CTA
  animation (bass pulse, treble glow). Audio-reactive was used in 0/8 tests
  despite narration being present in all of them

step-7-validate:
- Snapshot section: explicit "use hyperframes snapshot, don't roll custom"
  with the default naming pattern spelled out. Stripe's run used custom
  ffmpeg naming (beat-6-cta-at-20.5s.png) instead of frame-XX-at-Ys.png
- New render section: require --output renders/<project>.mp4 so final MP4s
  have predictable names. Without this, 7/8 tests produced wildly different
  filenames (preview.mp4, cal_2026-04-19_20-29-21.mp4, basecamp.mp4, etc.)

techniques.md:
- New technique #11: Audio-Reactive Animation. Covers the sampling pattern
  (per-frame tl.call, not single tween), when to use (music/dramatic VO
  videos), intensity ranges (3-5% for text/logos, 10-30% for backgrounds),
  and anti-patterns (equalizer bars, waveforms, strobing). Cross-references
  skills/hyperframes/references/audio-reactive.md for the full API

Made-with: Cursor
2026-04-19 08:41:53 -04:00
ukimsanov d8f1af1ef1 feat(capture): write AGENTS.md alongside CLAUDE.md + skill refinements from regression tests
Capture pipeline:
- agentPromptGenerator now writes AGENTS.md + CLAUDE.md (drop legacy
  .cursorrules), matching the dual-file convention already used by the
  _shared templates in hyperframes init. AGENTS.md is picked up natively by
  Cursor, Codex, Gemini CLI, Windsurf, Aider, and Jules; CLAUDE.md covers
  Claude Code. Both files share the same content — a capture data inventory
  that points agents to the website-to-hyperframes skill.

website-to-hyperframes skill refinements (derived from 8-site regression test):
- Drop slash-command phrasing throughout SKILL.md and step-6-build.md so the
  skill works identically across Claude Code (slash), Cursor (auto-discover
  by description), and other agents.
- Remove stale HANDOFF.md references from SKILL.md step-7 summary and
  reference table — matches the intent of the prior step-7 cleanup.
- step-5-vo: specify narration.txt filename convention (pronunciation-
  substituted spoken text; distinct from SCRIPT.md the creative doc).
- step-6 self-review adds three rules derived from actual lint warnings
  observed across the 8 regression runs:
    - Every <template> root needs data-start + data-duration (catches
      root_composition_missing_data_start/duration, seen in 4/8 runs).
    - Caption exits need a hard tl.set kill after tl.to(opacity:0), or
      per-word karaoke tweens can leave captions stuck on screen
      (caption_exit_missing_hard_kill).
    - No duplicate media nodes with identical src + start + duration, or
      the compiler discovers them twice (duplicate_media_discovery_risk).

Housekeeping:
- .gitignore: add cursor-tests/, basecamp-video/, projects/, videos/ —
  local regression-test scratch dirs that should never be committed.
- Remove two broken symlinks from .claude/skills/ that pointed to paths
  which never existed in the repo (.claude/skills/ is already gitignored).

Made-with: Cursor
2026-04-18 23:17:29 -04:00
ukimsanov 92a5ef419b feat(capture): improve capture quality + clean up CLAUDE.md
Capture improvements:
- Font weights via document.fonts API + DOM sampling (variable font detection)
- Section background-image extraction (no more false #FFFFFF on hero photos)
- Detected libraries surfaced in CLAUDE.md brand summary
- Structured visible-text.txt with [tag] prefixes, cookie/nav noise filtered
- tokens.json cleaned: removed images/paragraphs/icons (duplicated elsewhere),
  filtered sections to heading-only, trimmed cssVariables to design-relevant
- Removed redundant scroll pass in htmlExtractor (2-5s faster per capture)
- Font cap at 20 families, Placeholder/Fallback fonts filtered

CLAUDE.md rewrite:
- Removed prescriptive tone ("use exact strings" → "rephrase freely")
- Removed fluff sections (How to Create, DESIGN.md warning, Example Prompts,
  Source Patterns)
- asset-descriptions.md promoted to first data row
- Removed assets-catalog.json from inventory

Skill fixes:
- Dead shader refs → point to packages/shader-transitions/README.md
- Google Fonts import in techniques.md → local @font-face placeholder
- Added Stripe DESIGN.md as light-brand example
- Removed HANDOFF.md generation from step-7
- Updated step-1 for new font weight + visible-text formats
2026-04-18 18:48:37 -04:00
ularkim de5b53c08b feat(capture): switch Gemini 2.5 Flash → 3.1 Flash Lite
Gemini 3.1 Flash Lite Preview: 2.5x faster TTFT, 45% faster output,
slightly cheaper ($0.25/M vs $0.30/M input), near-2.5-Flash quality.
Descriptions are actually more detailed in testing.
2026-04-16 22:58:50 -04:00