* docs(skills): add cloud render + variables to CLI skill, media-use generative use cases
The hyperframes-cli skill only documented self-managed AWS Lambda rendering; the
zero-infra HeyGen-hosted `cloud render` path (a real, shipped command with its
own docs page) was absent from every skill, so agents never surfaced it.
- hyperframes-cli: add `cloud` to the frontmatter verb list + entry point; new
Cloud and Variables sections; new references/cloud.md distilled from
docs/deploy/cloud.mdx; routing + workflow rows.
- media-use: add image-to-video recipe (heygen video create type:image) plus a
table of other HeyGen generative use cases (photo avatar, digital twin, video
translation, lipsync, voice design) in references/operations.md; surface them
in the SKILL coverage/provider rows.
- Sync README + docs/guides/skills.mdx catalog entries to mention cloud render.
* docs(media-use): point HeyGen generative use cases at --request-schema
Verified against the installed heygen CLI (v0.3.0): no capability gap that would
need the raw API. Replace hardcoded body-field lists with a pointer to
`heygen video create --request-schema` (self-documenting, can't rot), correct
the image-to-video motion_prompt/expressiveness support, and add the
cinematic_avatar, ai-clipping, and photo-avatar creation paths.
* fix(skills): correct media-use manifest hash (clean-tree regen)
The prior regen was polluted by the gitignored skills/media-use/eval-report.html
(a suppressed mv error left it present), so the committed media-use hash didn't
match a clean checkout. Regenerate with no untracked artifacts present.
Scaffolded projects' npm run check now invokes the single check command
instead of chaining lint, validate, and inspect (three Chrome boots
become one). The CLI skill, its correctness reference, the entry skill's
capability map, README/docs catalog rows, the Mintlify CLI page (new
check section, deprecation banner on inspect), template CLAUDE/AGENTS
(byte-identical), root CLAUDE/AGENTS, and every creation-workflow skill
that taught the old sequence all point at check. snapshot keeps its
standalone sections; validate/inspect stay documented as deprecated
aliases with their check equivalents.
* feat(media-use): color grading — grade/lut resolve, smart-grade, grade-compare CLI
Add color grading to media-use as first-class resolve types plus a faithful
comparison command. All local, offline, deterministic — no model, no GPU.
- resolve -t grade / -t lut: produce a data-color-grading block (or a frozen
.cube). Look cascade: core preset (no file) -> bundled .cube library ->
parametric buildCube. Emitted .cube is Rec.709 and validated against core's
colorLuts constraints (LUT_3D_SIZE <= 64) before it is frozen.
- smart grade (grade --for <media>): ffmpeg signalstats -> adjust suggestion
(exposure / contrast / white balance), surfaced with the measured evidence on
stderr as a starting point; never auto-applied.
- hyperframes grade-compare: renders N candidate grades onto a reference frame
through the real runtime shader into one labeled comparison PNG, so an agent
picks a look without opening Studio. Prepends an "original" baseline cell by
default (--no-baseline to omit). Shares the headless-capture pipeline with
snapshot via capture/captureCompositionFrame.
- media-use SKILL: proactive "media opportunity pass" guidance (grounded
signal -> offer, ask once, surface don't mutate).
Verified: media-use 116/116, grade-compare 7/7, snapshot 9/9, lint + format
clean, full build green, comparison renders end to end.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
* test(cli): narrow grade-compare baseline assertion off unknown-typed grading
Assert the whole cell via toEqual instead of reaching into .grading.preset /
.grading.lut on the unknown-typed field, keeping the test typecheck-clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
* feat(media-use): agent-authored LUTs via --params + validate --from cube; never-read-.cube guardrail
- resolve -t lut / -t grade --params '<json>': build a parametric .cube from
explicit params (bypassing the intent cascade), validate, and freeze in one
step. --intent becomes the optional description. Lets an agent commit a look
it computed itself.
- --from <file.cube> now validates the ingested LUT for lut/grade types and
rejects an invalid/oversized cube (no partial write) — the escape hatch for a
LUT the agent generated with its own code.
- SKILL.md: hard rule to never read a .cube body into context (~size^3 lines,
zero legible signal) — inspect via grade-compare (see it) or cube-validate
(ok/size), read the manifest description for meaning; plus both authoring
paths and the parametric-vs-film-stock ceiling note.
Verified: media-use 116/116, lint + format clean; smokes — --params builds a
valid frozen cube, grade --params returns a lut block, bad JSON and an oversized
--from cube are both rejected with no stray file.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
* fix(cli): grade-compare validates referenced LUTs, warns on no-op cells, caps candidates
Bug-bash follow-ups — grade-compare silently accepted bad input:
- Validate LUT *content*, not just existence: each referenced .cube is parsed
with core's parseCubeLut (now exported from @hyperframes/core) and rejected
with a per-cell error ("LUT for \"<label>\" is not a valid .cube: ..."). A
file that exists but isn't a valid cube no longer renders a silent no-op cell.
- Warn on inactive cells: a grading that normalizes to inactive (e.g. a
malformed {lut:12345}) emits a stderr warning naming the cell; the
auto-prepended "original" baseline is intentionally inactive and stays silent.
stdout remains valid JSON.
- Cap candidates at 16 (excluding baseline): over-cap input renders the first N
and reports {truncated:true, total:M} on stdout + a stderr note — no silent
drop, no unbounded giant sheet.
Verified: grade-compare 10/10; non-cube LUT → clear error; {lut:12345} → warning
+ ok; 20 cells → cells=17 truncated total=20; valid runs unchanged. Lint/format
clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
* feat(cli): general `hyperframes compare` visual-variant primitive
Generalize grade-compare's "render N variants → one labeled sheet → the agent
looks and picks" loop into a standalone command that works on ANY variation
(font, layout, motion, grade, whole compositions) — the tool never needs to
know what differs.
- `hyperframes compare <path...> [--at <sec>] [--labels a,b,c] [--out] [--cols]
[--json]`: renders each agent-authored composition variant through the real
runtime (captureCompositionFrame) and stitches one labeled comparison sheet +
JSON ({ok, sheet, rendered, variants, truncated?/total?}). 2+ paths required;
caps at 16 with loud truncation. It presents, it does not judge — choosing is
the caller's job.
- Factored the shared "render a labeled set → contact sheet" path so compare,
grade-compare, and snapshot all sit on it (no duplication). grade-compare is
now the first color-specific specialization of this primitive.
- New pathArgs util + contactSheet test; hyperframes-cli SKILL documents compare
as the agent's "see your own renders and choose" primitive.
Verified: 26/26 across compare + grade-compare + snapshot + contactSheet (no
regressions); compare renders 3 variants into one visibly-distinct labeled
sheet; 2+-path error path clean; lint/format clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
* fix(ci): green the skills CI — skip ffmpeg tests when absent, oxfmt markdown
The "Test: skills" CI job runs bare `node --test` with no ffmpeg on PATH (by
design — skills tests are meant to be node-builtin-only). The grade-analyzer +
smart-grade tests shell to ffmpeg and were failing there with ENOENT. Guard
them to skip when ffmpeg isn't on PATH; they still run locally / where it is.
Also oxfmt README.md + hyperframes/media-use SKILL.md (the whole-repo
`oxfmt --check .` Format job caught markdown left unformatted by the rebase
conflict resolution).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
* fix(ci): skip core-conformance test when tsx is unavailable
The "Test: skills" CI job installs no deps, so the normalizeHfColorGrading
conformance test (which imports core's TS via `node --import tsx`) failed there.
Guard it to skip when tsx can't resolve; runs locally / in the deps-installed
Test job. Completes the skills-CI greening (the ffmpeg guards handled the rest).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
* fix(cli): escape grade-compare src double-quotes (CodeQL XSS) + Windows-safe compare test
- grade-compare built `<img src="...">` (double-quoted) with the single-quote
escaper, leaving `"` unescaped — a `"` in the frame path could break out
(CodeQL: incomplete HTML attribute sanitization). Use escapeXml for src.
- compare label test hard-coded POSIX paths that can't match on Windows; assert
the derived labels (the subject); path resolution is covered elsewhere.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
* refactor(media-use): generate LUT library from params (drop committed .cube files)
The 3 bundled .cube files were 733 lines each (2,199 total) and were themselves
buildCube output — pure repo bloat. Replace with compact per-look params in
luts/index.json, generated on resolve; add an optional `url` for future scanned
LUTs to be CDN-hosted + downloaded on demand (freezeUrl) instead of committed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
* feat(media-use): serve library LUTs from CDN on-demand (static.heygen.ai/luts), params fallback
Looks now carry a CDN `url` (hosted at s3://heygen-public/luts → static.heygen.ai/luts/<id>.cube);
resolve downloads + validates + freezes on demand, like bgm/image. `params` stays
as the deterministic offline fallback (--local-only, or if the download fails), so
resolution is never blocked on the network. Provider prefers url, falls back to params.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
* fix(media-use): address #2041 review — atomic LUT writes, compare telemetry, follow-ups
- Atomic .cube writes: library provider (url + params) and the parametric
generator now write to a .tmp path, validate, then rename, so a crash can
never orphan an invalid .cube at the final path (was validate-after-write).
- track("media_use_resolve") now emits provenance.via (url/params-fallback/params).
- grade-compare + compare: --timeout flag (was hardcoded 5000) and a
media_use_compare event (cells, truncated, total, render_ready_timed_out);
openSettledCompositionPage now surfaces the render-ready timeout.
- compare staging skips node_modules/.git; --for gets an upfront existence check.
- Rec.709 luma comment; HYPERFRAMES_ANALYZE_TIMEOUT_MS override; measured note
uses basename; LUT s3 hosting moved from index.json into luts/README.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H5k87mPZ4d6yiFwcWSb8Vv
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(cli,skills): install workflow skills on demand instead of re-pulling the full set
Users report every init re-pulls all 21 skills into ~/.agents/skills
whenever anything is stale or missing - heavy, noisy, and it re-expands
deliberate partial installs.
Split the set into two tiers:
- core: the /hyperframes router + hyperframes-* domain skills +
media-use, which every workflow references structurally. init and
bare 'skills update' keep these (plus anything already installed)
fresh, and never expand the install.
- on demand: the end-user workflow skills (and figma). They install at
trigger time via 'skills update <name...>' - positional names are
the only way update expands an install: one targeted
'skills add --skill <name>' covering only stale/missing targets, a
fast no-op when current, presence-verified after install, exit 1 on
unknown names, and a presence-only degrade when GitHub is
unreachable.
The /hyperframes router now runs 'skills update <workflow>' after
routing and before reading the workflow skill, so a routed workflow is
guaranteed present even on a machine that only has the core set. Each
on-demand skill also opens with the same self-maintenance step (run
'npx hyperframes skills update <name>' silently), so a workflow
triggered directly - without the router - still refreshes itself and
restores any missing core skill before relying on it.
When the manifest is unreachable (offline / rate-limited) the engine
degrades honestly instead of claiming success: named runs presence-check
the request plus a pinned fallback core list (unit-pinned to skills/)
and blind-install whatever is absent; a bare strict update fails loudly
so the 'check || update' chain can't pass while everything stays stale;
init reports the skipped freshness check. --json emits structured
errors on failure paths.
skills check still lists every skill, but exits non-zero only for
stale installed skills, an incomplete core set, or removed leftovers -
workflow skills not yet installed are reported as available on demand.
Bare 'hyperframes skills' (and 'skills add --all') remain the explicit
full-set installs.
Verified end-to-end with a sandboxed $HOME: fresh init installs the 9
core skills only; 'skills update slideshow' adds exactly that skill
(no-op on re-run, exit 1 on unknown names); bare update refreshes
without expanding; a live Claude Code run routed PR-to-video, executed
the router's update step, and the workflow skill appeared before use;
and a second live run triggered an installed workflow directly, whose
opening maintenance step restored a deliberately removed core skill.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(skills): clarify update-engine contracts + document lazy-install model
- skills.ts: note the UpdateSkillsResult.unknown strict-mode contract,
verifyInstalled's non-strict (warn-not-throw) intent, and that a
partial install stays "refreshed but never expanded" (review nits).
- docs/guides/skills.mdx: add a "Keeping skills current" section covering
the core-eager / workflow-on-demand model and the skills check|update
commands, per the repo's catalog-maintenance rule.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: kiritowoo <295860553+kiritowoo@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Miao Yang <miao.yang@heygen.com>
* feat(media-use): resolve official brand logos via a four-tier cascade
Third-party brand logos (the meeting's 'credibility signals lost' gap)
had no acquisition path: capture only grabs the product's own site
assets, and HeyGen asset search returns generic look-alike icons for
brand queries (0/3 in testing — an X-in-a-circle for LinkedIn). Workers
could only fake a mark or drop it.
New resolve type 'logo', four tiers verified by a 54-brand stress test
(100% cascade hit across dev tools / big tech / non-tech / CN brands):
- svgl — official full-color vector SVGs + wordmark variants (40/54
first-hits); search is substring-based, so entities pass through
alias normalization (nextjs → 'next.js', aws → 'amazon web services')
- simple-icons (pinned CDN build) — official monochrome glyphs; catches
the long tail (nike, visa, toyota, wechat, bytedance)
- github org avatar — known-org map only; a brand name is not a GitHub
login, guessing risks same-named personal accounts
- domain favicon (DuckDuckGo ip3) — small-raster last resort; sub-500B
responses are DDG's placeholder and rejected; frozen with a low_res
provenance flag (chip-size use only)
logo joins the icon/image equivalence group (typesMatch) and the
images/ subdir, so entity cache hits interop with figma-imported marks.
A total miss falls through resolve's normal failure path — no special
casing. HeyGen search stays the icon provider; it is deliberately
absent from the logo cascade.
Docs: media-use gap/types/providers tables + example; the five
workflow banners now cover logos (catalog claim kept for media, 'from
their official sources' added for logos); product-launch story-design
and motion-graphics logo-reveal point at the new type; catalog
surfaces (CLAUDE.md / README / docs) updated in lockstep.
Verified: 19 unit tests + coverage row green; live smoke across all
four tiers (linkedin→svgl, nike→simple-icons, heygen→github.avatar,
amazon→favicon) plus a fabricated brand exiting 1 on the default miss
path. oxlint + oxfmt clean.
* test(media-use): sanction the four logo providers in the registry allowlist
svgl / simple-icons / github.avatar / favicon.ddg join the sanctioned
list — the logo cascade added in the previous commit. Full lib suite
95/95 green.
* test(media-use): gate the logo cascade behavior in CI + single-fetch favicon tier
Review follow-ups (miga-heygen, jrusso1020 on #2061):
- Eight mocked-network tests pin what the manual 54-brand stress test
only asserted: descriptor shape, alias retry (svgl non-array payload
→ next query, simple-icons 404 → next slug), network-error → null
fallthrough, the sub-500B placeholder rejection, github's
no-guessing (zero fetches for unmapped entities), and the real
cascade order landing tier by tier under a mocked network.
- faviconSearch now hands its verified bytes over as a local file, so
the freeze step copies instead of re-downloading — one round-trip,
and the size check is authoritative over what gets frozen.
- The header's hit counts are labeled as a stress-test snapshot, not a
live invariant.
Full lib suite 103/103; live smoke re-verified (amazon → favicon.ddg,
frozen .ico).
* fix(media-use): codex gate misfires as 'not logged in' when piped
codexUnavailableReason() gated generation on parsing `codex login status`
stdout, but that command prints 'Logged in using ChatGPT' to stderr and
exits 0 — so the piped stdout media-use captures (execFileSync returns
stdout only on success) was empty, and the gate falsely reported 'not
logged in'. Every headless / CI / agent run was blocked from codex image
gen even when fully authed.
Gate on the durable credentials file ($CODEX_HOME/auth.json) instead of
the TTY/stderr-only human text. Token validity is still proven by the
exec, which fails cleanly on a stale login. The stdout `features list`
capability check is unchanged.
Verified: reproduced the false 'not logged in' block, then after the fix
generated end-to-end via `resolve -t image --provider codex` (valid
1254x1254 PNG, source=generated, provider=codex.image_gen).
* fix(media-use): bug-bash fixes — id race, provider/reuse/adopt guards
From the bug-bash against main:
- MU-23 (HIGH): concurrent resolves raced on nextId (read-max-then-append,
non-atomic), so parallel agents got duplicate ids and clobbered each
other's files. Add allocateId(): a coarse per-project lock (.media/.lock,
15s stale-steal) around id allocation that scans the manifest AND the
type dir for reserved ids, then O_EXCL-creates a placeholder file so the
slow download between allocate and append can't collide. 5 parallel
resolves now yield 5 distinct ids + files.
- X4: --reuse imported across a type mismatch (bgm asset under images/).
Apply typesMatch on the --reuse path; reject mismatches (icon<->image
still interchangeable).
- X5: --provider silently overrode --local-only and made a network call.
--local-only is now a hard guard: network providers are skipped even
under a forced provider; the miss message explains the conflict.
- BUG-2: --provider ignored the exact-cache floor and could hand back an
asset from a different provider. A forced --provider now bypasses all
reuse rungs (regenerate with THIS provider); the unforced floor is intact.
- MU-26/X6: 0-byte assets accepted. --adopt skips 0-byte files (loud); ingest
refuses a 0-byte local file (freezeUrl already rejects empty responses).
- BUG-4: unknown/unavailable --provider now errors with the available list
instead of a generic 'no provider could resolve' (typo != catalog miss).
- BUG-5: --reuse "" gave the wrong 'type and intent required' error; it now
routes to a clear empty-sha message.
- BUG-3: voice duration leaked an unrounded float into index.md; round all
durations to 0.1s centrally at record build (matches probe).
- Nits: whitespace-only --intent is rejected; nudge grammar (exists/exist).
Tests: allocateId reservation + registry local-only-wins added; full
media-use suite green. All fixes verified e2e.
* fix(cli): reject unknown flags instead of silently ignoring them
citty is permissive: an unrecognized flag was dropped, not rejected — so
`render . --out x` (the flag is --output/-o) silently ignored --out and
rendered to the default renders/<name>.mp4 path. A mistyped flag read as a
render/catalog miss.
Add assertKnownFlags(): validate every dash-prefixed token against the
command's declared args + aliases + the global set (help/version/json)
before the command runs, in the shared trackCommandFailures run-wrapper so
every leaf command is covered. Handles --flag=value, --no-<bool> negation,
camelCase<->kebab arg names, and combined shorts; stops at --; positionals
and flag values pass through.
Verified: `render . --out x` -> 'Error: Unknown flag: --out'; --output/-o/
--json/--help still accepted. Unit tests added.
* docs(skills): install with --full-depth so agents get current main
The documented `npx skills add heygen-com/hyperframes` fetched the
skills.sh registry blob, which lags GitHub main by hours — so users
following the docs got a stale skill (e.g. media-use v1: no --candidates,
voice stubbed). The CLI's own `hyperframes skills` command already forces
a full clone via --full-depth to bypass this; the docs didn't pass it.
Add --full-depth to every documented install command (README, CLAUDE.md,
docs/guides/skills.mdx) with a one-line note on the lag. Addresses the
user-facing half of the publish/registry lag (#2034).
* chore(media-use): collapse resolve.mjs import to satisfy oxfmt --check
* fix(cli): extract longFlagName to keep flag validator under complexity gate
Also regenerate skills-manifest.json (resolve.mjs formatting change re-hashed
the media-use skill). Fixes the Fallow audit + skills-manifest-in-sync CI gates.
* fix(skills): audit descriptions — trim routing prose, fix stale facts, add missing triggers
Descriptions are the always-loaded routing tier; this audit rebuilds them on
one principle: discriminate by input shape, not pipeline internals.
- Trim creation-workflow descriptions to positive trigger + nearest-neighbor
disambiguation + /hyperframes escape hatch; full routing prose already
lives in each skill body's route-confirm block and the router
- Codify the workflow-vs-domain split as ownership (owns the end-to-end
deliverable vs capability layer pulled in mid-flight) in /hyperframes,
and widen "make me a video" framing to deck / composition port
- Fix stale facts: embedded-captions identity count (desc 32, body 17 →
actual 36 = 10 classic + 26 themed), six→ten visual languages, retired
RVM/Standard wording in router details, figma shader transport
(MCP → MCP source / native export), keyframes "cursor demos" (no backing
content), hyperframes-media scripts/audio.mjs leak
- Register missing capabilities: motion-graphics maps category (was in
categories/ but absent from its own table, description, and router),
asset-fusion + news triggers, slideshow page-to-deck + presenter mode,
general-video editing, talking-head-recut 16:9/9:16/4:5 canvas,
cli feedback + lambda sites, product demos, mood-brief BGM generation
- website-to-video: relabel promo-shaped video types to keep the promo
boundary with /product-launch-video; drop headless-Chrome wording
- music-to-video: lyric timing via /hyperframes-media transcription or
user-supplied lyrics, placed on the beat grid
- Sync catalogs in lockstep (CLAUDE.md, AGENTS.md, README,
docs/guides/skills.mdx, CLI project templates): add music-to-video +
slideshow entries, complete the domain-skill lists, and extend the
catalog-maintenance rule to cover AGENTS.md and the templates
Validated with a 35-case description-only routing eval: 35/35 both before
and after the rewrite (including new maps / asset-fusion / news probes).
* fix(skills): post-media-v2 consistency — stale media ref, router figma wording, catalog rows
- music-to-video: lyric transcription now routes to /media-use (the
retired /hyperframes-media was still referenced)
- router capability map: figma row gains the shaders fact (MCP source /
native export), matching the SKILL.md source of truth
- media-use catalog rows (CLAUDE.md, README, docs/guides/skills.mdx):
add image models + captioning, aligning with the v2 description
- catalog rule #1: root AGENTS.md carries the workflow list only (it
has no domain-skill section) — rule wording now says so
The media-use v2 row is the widest cell in the domain-skills table; oxfmt
re-pads every other row's trailing pipe to match. The merge added the row
without re-aligning, so oxfmt --check flagged README on CI (linux). Content
is unchanged; only trailing whitespace in 10 table rows.
Field feedback from a raw-API agent build (join-the-world-flow): the
catalog blurb's word 'animatics' encodes the PNG-slideshow architecture
the skill body explicitly forbids — an agent routing by the blurb
concludes the shipped behavior is frames-as-pictures. Reworded to
'reconstructed motion (frames read as states, not slides)' across all
catalog surfaces (skill frontmatter, CLAUDE.md, README, skills.mdx,
hyperframes router, figma guide).
Also codifies the stronger doctrine that build demonstrated as
storyboard rule 10: when every frame is the same product UI in
successive states, rebuild the app as live DOM (Phase-3 for stateful
parts, real pixels for static chrome — code what changes state, freeze
what doesn't) and perform frame deltas as interactions instead of
tweens. Spec §5.1 records the escalation + field origin.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(skills): reroute /figma by capability - REST/CLI for phases 1-3, MCP for 4-5 (M4)
Rewrites the skill from MCP-first to the spec 2 split: asset/tokens/
component route through the hyperframes figma CLI (FIGMA_TOKEN), motion/
shaders stay agent-driven over MCP (no REST equivalent). Adds two-
credential guidance, Starter rate-limit tactics (recursive:true, raw-
response cache, opt-in screenshots), the 7.1 binding flow (tokens before
components, one ask per unknown library, never value matching), and the
shader manual-export default. Catalog blurbs updated in lockstep.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): register figma component subcommand
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(skills): add storyboard-to-animatic guidance to /figma
Field-tested against a real 26-scene storyboard section: the parsing
grammar (frame-sized nodes incl. loose rectangles = scenes, x-order =
time order, TEXT below the strip = director notes paired by x-overlap),
batched still export (chunk ~4 ids per render call - big frames timeout
past ~12), a note-verb -> transition vocabulary (EXPLOSION/SLIDE/MORPH/
CYCLE), and the stills-vs-component routing rule for within-scene motion
notes. Catalog blurbs updated in lockstep.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(skills): storyboard frames are keyframes, not slides
Field-tested against a second real storyboard section: frames sharing an
element (matched by name, else geometry similarity) define that element's
states through time - tween the element between states, crossfade only
when pixels genuinely differ, enter/exit unmatched children, tween frame
backgrounds as a color track. Stills demoted to fallback for frames that
don't decompose. Validated live: a 4-frame logo-rise reconstructed as one
element with four keyframes.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(figma): self-explanatory first-run experience + mintlify guide
- NO_TOKEN/BAD_TOKEN errors now carry the full one-time setup (mint URL,
read-only scope checklist, persist hint) instead of a bare pointer
- figma subcommands print clean guidance on typed client errors, not a
stack trace (shared withFigmaErrors boundary)
- CLI help gains component subcommand, FIRST-TIME SETUP and WHAT TO
EXPECT blocks
- /figma skill: preflight the token before the first CLI call and walk
the user through setup up front; narrate landed-artifact + next action
at every step
- new docs/guides/figma.mdx (setup, per-phase walkthroughs, provenance,
troubleshooting table) wired into docs.json nav
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(figma): review fixes — missing withFigmaErrors imports, 401/403 semantics, docs accuracy
- tokens.ts/component.ts called withFigmaErrors without importing it
(tsup doesn't typecheck, so every invocation shipped as an immediate
ReferenceError); imports added, tsc --noEmit now clean
- error boundary widened to all Errors so bad-ref/bad-format input
errors print their message instead of a stack trace
- 401 no longer claims 'missing scopes' (figma signals that as 403);
new FORBIDDEN code maps non-variables 403 to scope/access guidance
- docs: asset/component refs require a node id (bare fileKey is
tokens-only), example snippet matches real output, FORBIDDEN row
- skill: preflight counts a project-.env token as configured (CLI
auto-loads it); BAD_TOKEN/FORBIDDEN guidance split
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): present figma errors via standard errorBox
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(core): add figma motion easing mapping
* feat(core): translate figma motion doc to gsap timeline spec
* feat(core): emit paused GSAP timeline script from figma motion spec
* fix(core): restore type exports dropped from figma barrel in Task 8
* feat(skills): add /figma import skill + catalog wiring
Add the agent-facing /figma skill (asset + Figma Motion import via the
Figma MCP connector, built on @hyperframes/core/figma) and wire it into
the skill catalog across CLAUDE.md, README.md, docs/guides/skills.mdx,
and the hyperframes router's capability map. Bumps the skill count from
19 to 20 in CLAUDE.md and README.md.
* fix(core): use replaceAll for figma node-id dash-to-colon conversion
* style: format skills catalog tables
oxfmt-align the README and router SKILL.md tables after the /figma +
/hyperframes-keyframes merge left uneven column padding.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(cli): add missing cache fields to telemetry test fixture
ExtractionPhaseBreakdown gained cachePublishFailures/cacheGcEvictions/
cacheGcBytesFreed/cacheAgedPartialsCleared; the studioRenderTelemetry
test fixture was never updated, breaking Typecheck on main and every PR
based on it.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Renames the motion-surfacing tool from `hyperframes keyframes` to `hyperframes motion`,
renames the implementation from keyframes*.ts to motion*.ts (keeping the keyframe data
model name where still accurate), and renames the shipped skill from
hyperframes-keyframes to hyperframes-motion. Expands the skill from a command
reference into a full motion-design workflow: reading motion, 3D angle verification,
layered GSAP motion, one-shot reference reproduction, diagnostic checks, and
eval-derived craft guidance.
* docs: list all 19 skills in README + add CLAUDE.md maintenance reminder
Agents discover skills via the README, so silently-out-of-date entries
kill discovery. This change:
- Adds a `## Skills` section to the README listing all 19 skills,
grouped Router / Creation workflows / Domain skills, with a one-line
"use when" blurb for each (sourced from each skill's SKILL.md
frontmatter `description:`).
- Updates the existing CLAUDE.md `## Skills` section to cover all 19
skills (was missing the domain skills, `/media-use`, `/slideshow`,
and `/music-to-video`), mirroring the README's Router / Creation /
Domain grouping.
- Adds a "Skill catalog maintenance" section to CLAUDE.md so future
skill additions / renames update both surfaces and the
`/hyperframes` router skill in lockstep.
Docs-only — no source or test changes.
— Jerrai (https://claude.com/claude-code)
* docs(mintlify): add skills catalog page + extend maintenance reminder
Per follow-up on HF#1722: the Mintlify docs at
hyperframes.heygen.com also need the skills catalog so agent
discoverability is consistent across README and docs site.
- New: docs/guides/skills.mdx (3-group catalog — router / creation
workflows / domain skills — mirrors README structure, sourced from
the same SKILL.md frontmatter)
- Update: docs/quickstart.mdx — completes the workflow-skills list
(was missing /music-to-video, /slideshow, /general-video) and
cross-links the new page
- Update: docs/introduction.mdx — adds a skills-catalog card to the
hero CardGroup and the Next Steps section
- Update: docs/docs.json — adds /guides/skills to the Guides nav
- Update: CLAUDE.md "Skill catalog maintenance" — adds
docs/guides/skills.mdx as the third sync target alongside README
and skills/hyperframes/SKILL.md, and notes the count drift surface
(README + CLAUDE.md mention "19 AI agent skills" in their intros;
the new docs page deliberately omits a count to avoid drift)
Docs-only — no source, packages, or test changes.
— Jerrai (https://claude.com/claude-code)
* docs(readme): oxfmt table column-alignment fix
Pure whitespace — oxfmt's table-column alignment caught README.md
after the previous commit. No content change.
— Jerrai (https://claude.com/claude-code)
* docs(skills): reconcile install-command contract across README/CLAUDE/Mintlify
Per Magi's review on HF#1722: the new README/CLAUDE/skills.mdx pages
described bare `npx skills add heygen-com/hyperframes` as installing all
19 skills, while existing quickstart/prompting docs said the bare command
opens a picker and `--all` installs everything.
Verified actual CLI behavior with `npx skills add --help` and a clean-dir
run: bare command opens an interactive picker for human users (the CLI
help documents `--all` as "Shorthand for --skill '*' --agent '*' -y" —
the picker-skipping form). Inside an agent the bare command auto-installs
all non-interactively, but that's an agent-detection UX shortcut, not the
public contract — documenting the picker is correct for human readers.
All touched docs now use the consistent contract:
- `npx skills add heygen-com/hyperframes` -> interactive picker
- `npx skills add heygen-com/hyperframes --all` -> install all 19 (skips picker)
- `npx skills add heygen-com/hyperframes --skill <name>` -> install just one
Files updated: README.md, CLAUDE.md, docs/guides/skills.mdx. Existing
docs/quickstart.mdx and docs/guides/prompting.mdx already used this
contract and are unchanged.
— Jerrai (https://claude.com/claude-code)
* docs(readme): swap hero media to hyperframes-logo-motion
Replaces the prior hfgif-1280.webp hero with a new logo-motion clip
Bin trimmed for the launch. Converted the source MP4 to animated webp
(the existing hero's format) so it auto-plays in the GitHub README the
same way the old one did - MP4 sources don't render inline or autoplay
in <img> tags.
- New asset: static.heygen.ai/hyperframes-oss/docs/images/
hyperframes-logo-motion-1280.webp (1280x720, 85 frames, 199KB)
- ffmpeg conversion: scale=1280, libwebp_anim, q=80, loop=0
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* fix(studio): format 5 hooks files (oxfmt)
* style: remove unused imports in studio hooks (pre-existing lint failures)
CI Lint on main was already failing with 5 unused-import errors in
packages/studio/src/hooks/. Removed the unused symbols to unblock the
README hero PR's CI:
- gsapRuntimeBridge.ts: resolveTweenStart, resolveTweenDuration
- useGsapScriptCommits.ts: usePlayerStore
- useTimelineEditing.ts: PatchTarget (type-only)
- gsapDragCommit.ts: readGsapProperty
Bundled into the README PR per James's request to fix CI in-place.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test(studio): add childRects: [] to DomEditOverlay test mock
useDomEditOverlayRects' return type added a childRects: OverlayRect[]
field; the DomEditOverlay test's mock didn't get updated and was
returning an object without it, so DomEditOverlay.tsx's
'childRects.length > 0' check threw TypeError on undefined.
One-line mock-vs-hook contract realignment.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test(studio): drive player-store currentTime in selection-hydration test (#1311 follow-up)
The 'hydrates seek first, preserves the initial url state, then restores
selection' test was failing because PR #1311 (keyframes feat) changed
useStudioUrlState to read currentTime from the player store via
usePlayerStore((s) => s.currentTime), removing it from the hook's prop
shape. The test was still trying to drive currentTime via the harness
prop, which is now a no-op — so the selection-hydration useEffect's
time-stability guard
Math.abs(currentTime - stableTimeRef.current!) > 0.05
never passed (store currentTime stayed at 0 while stableTimeRef caught
the 4.2 seek target). buildDomSelectionFromTarget was never reached,
applyDomSelection was never called, and the assertion got 0 calls.
Fix: setState the store's currentTime to 4.2 ahead of the rerender so
the hook's selector picks it up and the time-stability guard passes.
Harness prop kept as-is — it's a no-op but doesn't hurt.
Pre-existing failure on main HEAD 81416ab3; surfaced as CI gate on the
unrelated docs/readme-hero-motion-update PR.
* test(studio): stub getBoundingClientRect + flush RAF in DomEditOverlay test
The 'renders selected bounds right after clicking a movable selection'
test asserts the selection box appears after pointerdown, but happy-dom
returns 0 for newly-created elements' getBoundingClientRect. The
overlay's compRect updates via a RAF loop that early-returns when iframe
width is 0; the keyframes PR a468550f added a compRect.width > 0 guard
to the selection-box render path, so compRect=0 silently gates the box
off and the assertion fails.
Stub Element.prototype.getBoundingClientRect to return 800x450 for the
test, and flush two RAFs after render so the compRect state update lands
before the pointerdown assertion. Restore the prototype at test end.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Miguel Sierra <miguel.sierra@heygen.com>
## What
Adds a **Frame.md** section to the main README — `frame.md` is the design-system-for-video translation layer (a `DESIGN.md` superset rewritten for the frame).
Includes a 10-template gallery. Each thumbnail links to its design page on `hyperframes.dev/design/<slug>`.
## Templates
Biennale Yellow · BlockFrame · Blue Professional · Bold Poster · Broadside · Capsule · Cartesian · Cobalt Grid · Coral · Creative Mode
## Image hosting
Preview PNGs uploaded to `static.heygen.ai/hyperframes-oss/docs/images/design-templates/<slug>.png` (heygen-public bucket), matching the existing demo-gif convention. All verified `200 image/png`. Design pages all verified `200`.
<img width="652" height="996" alt="image" src="https://github.com/user-attachments/assets/832fd87d-0421-4906-9f46-c5c9bf5b48e9" />
🤖 Generated with [Claude Code](https://claude.com/claude-code)
GitHub strips autoplay/loop from <video> tags in markdown, so the MP4
required a click to play. WebP autoplays via <img> while preserving full
HD source quality (1280x720 vs the previous GIF's 400x225).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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.
Add a parallel handoff path for users of [Open Design](https://github.com/nexu-io/open-design),
the Apache-2.0, local-first, BYOK alternative to Claude Design that drives whichever
coding-agent CLI the user already has on their PATH (Claude Code, Codex, Cursor, Gemini,
OpenCode, Qwen, Copilot, Hermes, Kimi, Pi).
Mirrors the existing Claude Design integration:
- README: a paragraph next to the Claude Design one, pointing at the new guide and
explaining the drop-into-skills/SKILL.md install path
- docs/guides/open-design.mdx: Mintlify page parallel to claude-design.mdx, with
Steps, comparison table, prompts, limitations, handoff
- docs/guides/open-design-hyperframes.md: SKILL.md-shaped instruction file users
drop into skills/hyperframes-handoff/SKILL.md (Open Design auto-discovers it
on next request) or attach to chat as a one-shot
- docs/docs.json: nav entry for the new page
The instruction file deliberately defers to claude-design-hyperframes.md as the
canonical reference for skeleton catalogs, shader patterns, HDR, and audio-reactive
animation — it stays focused on what Open Design's prompt stack needs at emission
time (active-DESIGN.md binding, 5-dim self-critique gate, structural rules) so the
two guides don't drift.
Open Design already ships a motion-frames skill that says "hand-off ready for
HyperFrames" — this PR closes the loop on the HyperFrames side so the route is
discoverable from the HyperFrames docs.
Co-authored-by: pftom <huan1043269996@gmail.com>
## 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.
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.
Raw GitHub URLs serve as text/plain — clicking opens a text tab
instead of downloading. Updated all 5 references across 4 files:
- claude-design.mdx (2 refs): "right-click → Save Link As"
- prompting.mdx (1 ref): "right-click → Save Link As"
- README.md (1 ref): "click download button on GitHub"
- quickstart.mdx (1 ref): "click download button on GitHub"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update docs, quickstart, prompting guide, and README to reflect:
- Template-first approach (attach file, not paste URL)
- Claude Design produces drafts, refine in any AI coding agent
- Known limitations (vertical shaders, seeking, no linting)
- Practical example prompts (feature announcement, founder pitch)
- Removed outdated references (invisible bridges, fetch-the-skills-tree)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(claude-code-plugin): add Claude Code plugin manifest
Adds .claude-plugin/plugin.json so the repo can be loaded as a Claude
Code plugin. Reuses the existing skills/ directory — all 5 skills
(hyperframes, gsap, hyperframes-cli, hyperframes-registry,
website-to-hyperframes) are auto-discovered under the hyperframes:
namespace.
* docs(readme): document Claude Code plugin usage
* chore(claude-code-plugin): add submission branding assets
* docs(claude-code-plugin): address review notes
## 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.
Adds .cursor-plugin/plugin.json at the repo root alongside the existing
.codex-plugin/, so this repo is the single source of truth for the Codex
plugin AND the new Cursor Marketplace submission. Refreshes the shared
assets/logo.png + assets/icon.png to a 1024x1024 / 512x512 symbol-only
mark rasterized from docs/favicon.svg (white background), and renames the
marketplace display title from "HyperFrames" to "HyperFrames by HeyGen"
in both Codex and Cursor manifests.
No skill content changes; purely marketplace-visible branding and the new
Cursor manifest file.
* docs(readme): note git-lfs requirement for full clones
Repo uses Git LFS for regression-test baselines (~240 MB of .mp4 files
under packages/producer/tests/**/output.mp4). Users cloning without
git-lfs installed hit a cryptic 'git-lfs: command not found' error, as
reported in #407.
Document the requirement with install instructions and the
GIT_LFS_SKIP_SMUDGE=1 escape hatch.
* docs(readme): add Windows install instructions for git-lfs
Per review from @miguel-heygen.
* chore(ci): fix oxfmt formatting on renovate.json
Drive-by to unblock CI. Landed unformatted in #422 because
Renovate's config-migration PR bypasses the lefthook pre-commit hook,
so every subsequent PR's `bun run format:check` (which scans the whole
repo) was failing on this file.
Adds honest Hyperframes vs Remotion comparison: README section with
paragraph + table + open-source-vs-source-available callout, plus a
full guide at docs/guides/hyperframes-vs-remotion.mdx walking through
the core React-vs-HTML decision, practical differences (including a
GSAP side-by-side), and licensing.
Closes#318
* refactor(engine): restructure frame reorder buffer with Map-keyed storage
Rewrites createFrameReorderBuffer to use a Map<number, Array<() => void>>
keyed by frame index instead of a flat Array<{frame, resolve}> scanned on
every advance. O(1) lookups in enqueue/flush, fast-paths for the matching-
cursor and overshoot cases, and a small fix: waitForAllDone now coexists
with the writer still waiting on the final frame instead of colliding on
the same waiter slot.
Also adds 5 unit tests (there were none before) covering the fast-path,
out-of-order gating, multi-waiter-per-frame semantics, waitForAllDone
normal path, and the overshoot case.
Comment tweaks on buildChromeArgs — the flag profile is the standard
headless-for-capture set (Puppeteer / Playwright / Chrome headless-shell
all converge on similar flags); rephrased for clarity.
* refactor(cli): simplify port availability probe with async/await
Rewrites isPortAvailableOnHost from a single new-Promise callback into an
async/await form with an intermediate `bindError: ErrnoException | null`
variable. Makes the bind-then-release flow explicit as two sequential
awaits, and broadens the non-EADDRINUSE errno commentary (EADDRNOTAVAIL
for disabled IPv6, EACCES for privileged ports, EAFNOSUPPORT for missing
address families — all treated as "this host doesn't apply", not "port
occupied").
No behavior change to existing callers; all four portUtils tests still
pass.
* docs: add CREDITS.md and surface website-to-hyperframes skill
- New CREDITS.md acknowledging prior art in the browser-based video
rendering space (Remotion) and the ecosystem HyperFrames builds on
(Puppeteer, FFmpeg, GSAP, Hono). Standard OSS practice.
- Adds the `website-to-hyperframes` skill to the skills tables in
README.md, docs/guides/prompting.mdx, and the project template at
packages/cli/src/templates/_shared/CLAUDE.md. The skill ships in
skills/ but was missing from every table.
- Adds `/hyperframes-registry` to the prose mention in the repo
CLAUDE.md.
Move all preview mp4/png/gif assets under docs/images/ out of the repo
and serve them from https://static.heygen.ai/hyperframes-oss/docs/images/
(backed by s3://heygen-public/hyperframes-oss/docs/images/, CloudFront).
Drops ~49MB from the working tree and, more importantly, ~49MB from every
future Mintlify build checkout. Combined with the (already-LFS-tracked)
producer snapshots, the remaining bloat in 'npx skills add heygen-com/
hyperframes' (see #300) is LFS smudge during clone — separate fix needed
in the skills CLI to pass GIT_LFS_SKIP_SMUDGE=1.
Changes:
- Delete docs/images/** (103 files, ~49MB). Files are uploaded to S3 already.
- Rewrite /images/* references in 44 MDX files, TemplateCard.jsx, and
catalog-index.json to absolute CDN URLs.
- Update README.md img src to CDN URL (renders correctly on GitHub).
- Add docs/images/ to .gitignore so regenerated previews aren't committed.
- Add scripts/upload-docs-images.sh to sync docs/images/ → S3 after running
the preview generators.
- Wire up bun run upload:docs-images and bun run generate:catalog-previews
scripts in package.json.
- Update generator script docstrings to point at the upload step.
External contributors can still regenerate previews locally (mintlify dev
reads the CDN URLs, so broken previews appear only for newly added items
pending a maintainer upload). Maintainers run:
bun run generate:catalog-previews --only <name>
bun run upload:docs-images
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: add prompt cookbook + prompting guide for AI agents
Addresses user feedback that there's no guidance on how to actually
prompt Claude Code (or other agents) once the hyperframes skills are
installed. Adds copy-pasteable example prompts in the README and
quickstart, a new prompting guide page, and a starter-prompt nudge in
the `hyperframes init` output.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs(prompting): add vocabulary tables, rules, and TTS voice guide
Merges the best content from the internal prompt guide into
prompting.mdx: easing vocabulary, caption tone table, transition
energy matrix, audio-reactive frequency mapping, marker highlight
modes, TTS voice recommendations, rendering quality presets, and
framework rules (technical requirements vs best practices).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs(prompting): rename page title to "Prompt Guide"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: remove greensock/gsap-skills dependency, fix Math.random nuance
The bundled skills/gsap/ already covers the GSAP surface needed for
HyperFrames compositions. Installing greensock/gsap-skills on top adds
a competing full-ecosystem skill that's mostly irrelevant (ScrollTrigger,
Draggable, SplitText, etc.) and can confuse agents about which GSAP
context to load.
Also adds seeded-PRNG nuance to the Math.random() rule in the prompt
guide (matching the skill's actual guidance).
Removed from: skills.ts, README, AGENTS.md, shared AGENTS.md/CLAUDE.md,
and prompting.mdx.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: require minimal reproduction link in bug report template
Adds a required "Link to reproduction" input field asking users to push
a minimal repro to a public GitHub repo (scaffolded via
`hyperframes init repro --non-interactive --example blank`).
Also consolidates the OS/Node/FFmpeg/version fields into a single
"Environment" field using `npx hyperframes info` output — fewer fields
to fill, more consistent data.
Follows the same pattern as Next.js and Gatsby issue templates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(issue-template): use hyperframes doctor for environment info
`hyperframes info` only prints project metadata (resolution, duration,
elements). `hyperframes doctor` prints the full environment: version,
Node.js, FFmpeg, Chrome, memory, disk, Docker — everything needed to
diagnose bugs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs(prompting): mention validate alongside lint in anti-patterns
Per Vance's review comment — validate catches runtime errors (JS
exceptions, missing assets, contrast) that lint doesn't.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: replace libretto example URL with hyperframes repo
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## What
Fixes the README skills table to match actual skill names, and moves two orphaned script directories into the `hyperframes` skill where they belong.
## Why
**README**: Listed `hyperframes-compose` and `hyperframes-captions` as separate skills — these don't exist. Captions/compose are part of the `hyperframes` skill. Also listed `gsap-core, gsap-timeline, gsap-plugins, ...` but the actual skill is just `gsap`. Missing `hyperframes-cli` entirely.
**Orphaned scripts**: `skills/hyperframes-animation-map/` and `skills/hyperframes-contrast/` had scripts but no `SKILL.md` — they looked like broken skills and wouldn't be installed by `npx skills add`. They're helper scripts invoked by the main `hyperframes` skill (SKILL.md already references them in the "Quality Checks" section). Moving them under `skills/hyperframes/scripts/` makes them part of the skill they belong to.
## How
**README skills table** — corrected to match the 4 actual skills:
- `hyperframes` (was `hyperframes-compose` + `hyperframes-captions`)
- `hyperframes-cli` (was missing)
- `hyperframes-registry` (unchanged)
- `gsap` (was `gsap-core, gsap-timeline, gsap-plugins, ...`)
**Script moves:**
- `skills/hyperframes-animation-map/scripts/animation-map.mjs` → `skills/hyperframes/scripts/`
- `skills/hyperframes-contrast/scripts/contrast-report.mjs` → `skills/hyperframes/scripts/`
- Removed empty `skills/hyperframes-animation-map/` and `skills/hyperframes-contrast/`
- Updated path references in SKILL.md, both script headers, and `contrast-audit.browser.js`
## Test plan
- [ ] `grep -r "hyperframes-animation-map\|hyperframes-contrast" --include="*.md" --include="*.mjs" --include="*.js" --include="*.ts" .` returns no results
- [ ] `ls skills/` shows only `gsap`, `hyperframes`, `hyperframes-cli`, `hyperframes-registry`
- [ ] README skills table matches `skills/*/SKILL.md` names
- [x] Documentation updated (if applicable)
## What
Restructures the README to lead with skills-first onboarding, adds a demo GIF, surfaces the catalog, fixes incorrect pnpm references in contributing docs, and corrects the HTML example to use actual attribute names.
## Why
The README told a CLI-first story while the homepage (hyperframes.heygen.com) tells an AI-agent-first story. For a project that brands itself "built for agents," the GitHub landing page should match. Additionally, 50+ catalog blocks were invisible from GitHub, the player and shader-transitions packages were missing from the packages table, and the contributing docs referenced pnpm while the repo uses bun.
## How
**README changes:**
- Quick Start restructured: skills install as Option 1 (recommended), manual CLI as Option 2
- Added demo GIF rendered with HyperFrames itself (HTML + GSAP composition → MP4 → GIF)
- Added Catalog section with install examples and link
- Added `@hyperframes/player` and `@hyperframes/shader-transitions` to packages table
- Added npm downloads badge
- Fixed HTML example: `data-track` → `data-track-index`, added missing `class="clip"` on img
- Condensed Skills section into a concise table
- Documentation link now points to `/introduction` (Mintlify docs) instead of the landing page
**testing-local-changes.mdx:**
- All `pnpm` references replaced with `bun` (14 occurrences)
- Path references updated from `hyperframes-oss` to `hyperframes`
## Test plan
- [ ] Verify README renders correctly on GitHub (logo, badges, GIF, tables, code blocks)
- [ ] Verify GIF loops and is readable at GitHub's default README width
- [ ] Verify all links resolve (docs site, catalog, packages, contributing)
- [ ] Read through testing-local-changes.mdx for any remaining pnpm references
- [x] Documentation updated (if applicable)
Replace old text-only wordmarks and complex favicon with new HyperFrames
brand assets featuring the gradient icon. Add dark/light logo switching
to README via GitHub's <picture> element.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## What
New skill `hyperframes-registry` that teaches AI coding agents how to install and wire registry blocks and components into HyperFrames compositions.
### Skill structure
```
skills/hyperframes-registry/
SKILL.md — triggers, overview, quick reference
references/
install-locations.md — default paths, hyperframes.json config
wiring-blocks.md — iframe inclusion, data attributes, positioning
wiring-components.md — snippet merging (HTML, CSS, JS, timeline)
discovery.md — manifest reading, item fields, available items table
demo-html-pattern.md — why components ship demo.html, structure conventions
examples/
add-block.md — worked example: data-chart block install + wiring
add-component.md — worked example: shimmer-sweep component install + wiring
```
## Why
Phase B of the catalog plan (PR 10). Without this skill, agents using `hyperframes add` have to guess how to wire installed items into compositions. The skill encodes the iframe/snippet patterns so agents get it right on the first attempt.
## How
- SKILL.md frontmatter triggers on: `hyperframes add`, "block", "component", `hyperframes.json`
- References cover every step: discovery, install, wiring blocks (iframe), wiring components (snippet merge), and the demo.html convention
- Two worked examples walk through complete install-to-preview workflows
- Updated CLAUDE.md skills table + trigger rules, README.md skills table, docs/packages/cli.mdx
## Test plan
- [x] `scripts/lint-skills.ts` passes (checked 4 skill files, no issues)
- [x] `oxfmt --check` passes on all markdown files
- [x] SKILL.md frontmatter has valid `name` and `description`
- [x] All reference links in SKILL.md resolve to existing files
- [x] CLAUDE.md, README.md, and docs CLI page updated with new skill
* feat(skills): add hyperframes-cli skill for CLI workflow guidance
Adds a new skill that teaches AI agents how to use the HyperFrames CLI
(init, lint, dev, render, doctor). Previously, agents had no way to
discover the CLI — the compose-video skill only covered HTML authoring.
This led to agents searching for binaries, finding the monorepo, and
running bun run studio manually instead of using npx hyperframes dev.
Also registers the skill in init.ts so new projects get it bundled
alongside hyperframes-compose and hyperframes-captions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(cli): rename dev command to preview
The command starts a preview server — "preview" describes what users
are doing more accurately than "dev". Updates the command name, file
name, all CLI references, docs, skills, and template CLAUDE.md.
22 files updated across CLI source, docs, skills, and templates.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(skills): replace stale dev reference with preview in CLI skill
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(docs): catch remaining dev references missed in rename
- testing-local-changes.mdx: two inline command examples
- troubleshooting.mdx: anchor link #dev → #preview, "dev server" → "preview server"
- cli.mdx: "dev server" → "preview server"
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add npm version and MIT license badges (matching React/Remotion/Next.js conventions)
- Remove non-standard Docs badge
- Move Documentation section from bottom of README to right after Quick Start
for better discoverability (follows patterns from React, Remotion, Vite)
- Link to quickstart at hyperframes.heygen.com/quickstart
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Namespace skill names with `hyperframes-` prefix for clearer identity in
OSS contexts where users may have other skills installed.
Updates skill directories, SKILL.md frontmatter, CLAUDE.md, README.md,
CLI build script, init command, and project template.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>