diff --git a/CLAUDE.md b/CLAUDE.md index 4c2e34ed91..c2934f5eff 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -41,7 +41,7 @@ Atomic capabilities the creation workflows compose against — pull one when you - `/media-use` — the media OS: resolve any media need (BGM, SFX, image, icon, logo, voice, color grade, LUT) into a frozen local file or paste-ready block + ledger record; generate via TTS / music / image models when the catalog misses; transcribe, caption, remove backgrounds, and reuse assets across projects. One shared `scripts/audio.mjs` engine + manifest tracking; keeps search noise on disk. - `/hyperframes-audio` — mix the audio already placed in a composition: voiceover carve (dip a music bed only in the bands the voice occupies, static or dynamic, level match included), the effect chain (EQ, compressor, limiter, gate, saturation, delay, reverb, chorus, phaser, bitcrush), automation envelopes on volume or any effect parameter, and submix buses (``) that carry one chain, fader and automation clock for several tracks at once. Sourcing the audio is `/media-use`; this is what happens to it afterwards. - `/hyperframes-cli` — CLI dev loop: `init`, `add`, `lint`, `check`, `snapshot`, `preview`, `render`, `publish`, `doctor`, `lambda` (AWS Lambda cloud rendering). -- `/hyperframes-registry` — install and wire registry blocks and components into compositions via `hyperframes add`. Covers authoring a new block or component to contribute upstream. +- `/hyperframes-registry` — search, install and wire registry blocks and components into compositions via `hyperframes catalog` / `hyperframes add`. Load it before hand-building any named look, effect, treatment or transition: the search ranks the whole hosted registry with nothing installed. Covers authoring a new block or component to contribute upstream. - `/figma` — import Figma assets, tokens, components, and storyboard sections → reconstructed motion (frames read as states, not slides) (REST/CLI) plus Motion animations (MCP) and shaders (MCP source / native export) into a composition. ## Skill catalog maintenance diff --git a/README.md b/README.md index 7bd074786d..14da79e9f7 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,7 @@ Atomic capabilities the creation workflows compose against — pull one when you | `/media-use` | The media OS — resolve any media need (BGM, SFX, image, icon, logo, voice, color grade, LUT) into a frozen local file or paste-ready block + ledger record, generate via TTS/music/image models when the catalog misses, transcribe, caption, remove backgrounds, and reuse assets across projects. One shared audio engine + manifest tracking. | | `/hyperframes-cli` | CLI dev loop — `init`, `lint`, `check`, `snapshot`, `preview`, `render`, `publish`, `doctor`, plus HeyGen-hosted cloud rendering (`cloud render`) and AWS Lambda rendering (`lambda deploy / render / progress`). | | `/hyperframes-audio` | Mix the audio already placed in a composition — voiceover carve (dip a music bed only in the bands the voice occupies, static or dynamic, level match included), the effect chain (EQ, compressor, limiter, gate, saturation, delay, reverb, chorus, phaser, bitcrush), automation envelopes on volume or any effect parameter, and submix buses (``) carrying one chain, fader and automation clock for several tracks at once. Sourcing the audio is `/media-use`. | -| `/hyperframes-registry` | Install and wire registry blocks and components into compositions via `hyperframes add`. Authoring a new block or component to contribute upstream. | +| `/hyperframes-registry` | Search, install and wire registry blocks and components into compositions via `hyperframes catalog` / `hyperframes add`. Load before hand-building any named look, effect, treatment or transition. Authoring a new block or component to contribute upstream. | | `/figma` | Import Figma assets, tokens, components, and storyboard sections → reconstructed motion (frames read as states, not slides) (REST/CLI) plus Motion animations (MCP) and shaders (MCP source / native export) into a composition. | For visual design handoff workflows, see the [Claude Design guide](https://hyperframes.heygen.com/guides/claude-design) and [Open Design guide](https://hyperframes.heygen.com/guides/open-design). diff --git a/docs/prompting/overview.mdx b/docs/prompting/overview.mdx index 2385353b26..bdf1f67d6b 100644 --- a/docs/prompting/overview.mdx +++ b/docs/prompting/overview.mdx @@ -52,7 +52,7 @@ The installer shows a picker. Select the **core skills** below — every project | `/hyperframes-creative` | Creative direction — design spec, palettes, typography, narration, beats | | `/hyperframes-cli` | Dev-loop CLI — `init`, `lint`, `check`, `preview`, `render`, `doctor` | | `/media-use` | Media OS — TTS voiceover (`tts`), `transcribe`, `remove-background`, plus BGM / SFX / image resolution | -| `/hyperframes-registry` | Block and component installation via `hyperframes add` | +| `/hyperframes-registry` | Search the catalog before hand-building a look; install via `hyperframes add` | | `/hyperframes-keyframes`| Seek-safe keyframe authoring across runtimes, plus `hyperframes keyframes` diagnostics | | `/general-video` | The general authoring workflow — multi-scene pieces, reels, montages, remixes, and the home of **companion mode**; the fallback when no workflow below fits | diff --git a/packages/cli/src/commands/coreSkillContent.test.ts b/packages/cli/src/commands/coreSkillContent.test.ts index f796f627f6..64324a3fd3 100644 --- a/packages/cli/src/commands/coreSkillContent.test.ts +++ b/packages/cli/src/commands/coreSkillContent.test.ts @@ -132,6 +132,73 @@ describe("media treatment routing documentation", () => { } }); + it("makes the motion-graphics build path run a live catalog search, not read a snapshot", () => { + // The failure this pins: a user inside /motion-graphics asked for "CRT scanlines + // and glitch effects" and the agent hand-authored both, while `caption-glitch-rgb` + // ("RGB chromatic aberration with CRT scanline overlay") ranks first for that exact + // query on either tier. Every reuse instruction in the workflow pointed at + // catalog-map.md, a hand-maintained snapshot, and none named the search. The search + // needs nothing installed, so "I forgot to install the components" was never the cause. + for (const file of [ + ["skills", "motion-graphics", "catalog-map.md"], + ["skills", "motion-graphics", "agents", "director.md"], + ["skills", "motion-graphics", "agents", "builder.md"], + ]) { + expect(read(...file)).toContain("npx hyperframes catalog --query"); + } + // And it must say the search stands alone, or the next reader re-derives the + // creator's wrong diagnosis: that a catalog you have not installed cannot be searched. + expect(read("skills", "motion-graphics", "catalog-map.md")).toContain( + "needs nothing installed", + ); + }); + + it("routes every authoring workflow through the live catalog search, or documents why not", () => { + // The same failure one layer up. The search instruction lived only in + // hyperframes-cli and hyperframes-registry, both loaded on demand, and the + // registry skill's own trigger named the command ("use when running + // hyperframes catalog") — circular, because the agent that never thought to + // search could not reach the doc telling it to search. All ten workflow + // skills carried zero mentions of the command. + for (const file of [ + ["skills", "motion-graphics", "agents", "director.md"], + ["skills", "product-launch-video", "SKILL.md"], + ["skills", "faceless-explainer", "SKILL.md"], + ["skills", "pr-to-video", "SKILL.md"], + ["skills", "music-to-video", "SKILL.md"], + ["skills", "general-video", "SKILL.md"], + ["skills", "slideshow", "SKILL.md"], + ["skills", "remotion-to-hyperframes", "SKILL.md"], + ]) { + const doc = read(...file); + expect(doc, file.join("/")).toContain("npx hyperframes catalog --query"); + // "I forgot to install the components" was the wrong self-diagnosis that + // hid this bug. Every copy of the instruction has to kill it on the spot. + expect(doc, file.join("/")).toContain("nothing installed"); + } + + // The two workflows that deliberately do NOT search. Both compile their + // output through a closed authoring vocabulary (embedded-captions' locked + // caption engines, talking-head-recut's `data-anim` card kinds), and a + // registry item is a standalone composition with no place to mount. The + // exemption is written into each skill so the next reader does not close + // the gap with an instruction that would be false there. + for (const file of [ + ["skills", "embedded-captions", "SKILL.md"], + ["skills", "talking-head-recut", "SKILL.md"], + ]) { + expect(read(...file), file.join("/")).toContain( + "does not search the HyperFrames component registry", + ); + } + + // The symptom-triggered description is the other half of the fix: the skill + // has to be reachable from the user naming an effect, not from the command. + const registrySkill = read("skills", "hyperframes-registry", "SKILL.md"); + expect(registrySkill).toContain("Use BEFORE hand-building any named visual"); + expect(registrySkill).toContain("CRT scanlines"); + }); + it("gives agents a process-owned preview lifecycle in new project instructions", () => { for (const file of ["AGENTS.md", "CLAUDE.md"]) { const template = read("packages", "cli", "src", "templates", "_shared", file); diff --git a/scripts/lint-skills.test.mjs b/scripts/lint-skills.test.mjs index ed77e84756..e41b4e4e27 100644 --- a/scripts/lint-skills.test.mjs +++ b/scripts/lint-skills.test.mjs @@ -8,7 +8,7 @@ import test from "node:test"; import assert from "node:assert/strict"; -import { lintFrontmatter } from "./lint-skills.ts"; +import { lintFrontmatter, lintRegistryItemRefs } from "./lint-skills.ts"; const wrap = (frontmatter) => `---\n${frontmatter}\n---\n\n# body\n`; @@ -125,3 +125,58 @@ test("invalid: top-level scalar (frontmatter is not a mapping)", () => { // be non-empty. assert.ok(violations.length > 0); }); + +// --------------------------------------------------------------------------- +// Registry-snapshot drift guard +// --------------------------------------------------------------------------- + +const KNOWN = new Set(["caption-glitch-rgb", "code-diff", "data-chart"]); +const MARKER = ""; + +test("registry refs: unmarked file is never checked", () => { + // Opt-in is the whole design. Most kebab-case backticks in skill docs are CSS + // properties, data-* attributes or skill directory names, and a check that + // flags those gets switched off. null (not []) distinguishes "not a snapshot" + // from "a snapshot with nothing wrong", which is what the counter reports. + assert.equal(lintRegistryItemRefs("Use `not-a-real-item` here.\n", KNOWN), null); +}); + +test("registry refs: a marker inside a fenced block does not arm the check", () => { + // Otherwise a doc that documents this marker's own syntax arms the check on + // itself, and every identifier in it starts failing for no stated reason. + const doc = ["# Doc", "", "```md", MARKER, "```", "", "Use `not-a-real-item`."].join("\n"); + assert.equal(lintRegistryItemRefs(doc, KNOWN), null); +}); + +test("registry refs: marked file passes when every id is real", () => { + const doc = `${MARKER}\n\nUse \`caption-glitch-rgb\` or \`code-diff\`.\n`; + assert.deepEqual(lintRegistryItemRefs(doc, KNOWN), []); +}); + +test("registry refs: marked file flags an id the registry does not have", () => { + const doc = `${MARKER}\n\nInstall \`text-wave-distort\` for the wobble.\n`; + const violations = lintRegistryItemRefs(doc, KNOWN); + assert.equal(violations.length, 1); + assert.equal(violations[0].line, 3); + assert.ok(violations[0].message.includes("text-wave-distort")); +}); + +test("registry refs: allow= exempts a legitimately non-item identifier", () => { + const doc = `\n\n\`dark-plus\` and \`pin-rollout\`.\n`; + assert.deepEqual(lintRegistryItemRefs(doc, KNOWN), []); +}); + +test("registry refs: non-id backticks are ignored", () => { + const doc = `${MARKER}\n\n\`--json\`, \`Foo-Bar\`, \`a b-c\`, \`UPPER-CASE\`.\n`; + assert.deepEqual(lintRegistryItemRefs(doc, KNOWN), []); +}); + +test("registry refs: single-word ids are a KNOWN blind spot, not an accident", () => { + // The pattern requires a hyphen, so real single-word registry items (glitch, + // flowchart, typewriter, confetti, separator, vignette, vignelli) are never + // checked. Pinned here so the tradeoff is visible in code, not just in a + // comment: dropping the hyphen would cost 46 allow= entries of prose nouns + // across the marked files to monitor 3 more items. See lint-skills.ts header. + const doc = `${MARKER}\n\n\`glitch\` was renamed and this doc was not updated.\n`; + assert.deepEqual(lintRegistryItemRefs(doc, KNOWN), []); +}); diff --git a/scripts/lint-skills.ts b/scripts/lint-skills.ts index d03b26b97b..10c8847f47 100644 --- a/scripts/lint-skills.ts +++ b/scripts/lint-skills.ts @@ -12,6 +12,7 @@ import { readFileSync, readdirSync, statSync } from "node:fs"; import { join, relative } from "node:path"; import { parse as parseYaml, YAMLParseError } from "yaml"; +import type { RegistryManifest } from "../packages/core/src/index.js"; const REPO_ROOT = join(import.meta.dirname, ".."); // Every location that ships SKILL.md files gets linted. `skills/` is the @@ -256,6 +257,79 @@ function lintInlinePatterns(file: string, stripped: string): Violation[] { .flatMap((line, i) => (line ? matchDangerousPatterns(file, line, i + 1) : [])); } +// --------------------------------------------------------------------------- +// Registry-item references in hand-maintained snapshots +// --------------------------------------------------------------------------- +// +// A skill doc that snapshots part of the component registry rots in silence: +// nothing fails when an item is renamed or dropped, and the agent that follows +// the doc runs `hyperframes add ` and dies. A doc opts into this check +// with a marker line, after which every registry-item-shaped identifier in a +// backtick span must name a real item in registry/registry.json: +// +// +// +// Opt-in rather than repo-wide on purpose. Kebab-case backticks are also CSS +// properties, `data-*` attributes, skill directory names, script names, and +// motion-graphics category names, and a check that flags those is a check +// people turn off. `allow=` carries the few non-item identifiers a snapshot +// legitimately names (bare suffixes under a spelled-out prefix, ids the doc +// itself marks as hand-authored). +// +// TWO KNOWN BLIND SPOTS, both deliberate, both false NEGATIVES (this check +// never invents a violation, it only misses some): +// +// 1. Identifiers outside a backtick span are not seen. A bare `bar-chart-race` +// in prose slipped past this check while it was a live defect elsewhere. +// 2. Single-word item names are not seen, because the pattern below requires a +// hyphen. Measured on the six currently-marked files: dropping the hyphen +// requirement would monitor 3 more real items (`glitch`, `flowchart`, +// `typewriter`) and force 46 new allow= entries for ordinary prose words +// ("add", "line", "name", "height", "text"). A 15:1 noise ratio is how a +// check gets switched off, so the hyphen requirement stays. +const REGISTRY_MARKER = //; +const REGISTRY_ITEM_ID = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)+$/; + +function registryItemNames(): Set { + const raw = readFileSync(join(REPO_ROOT, "registry", "registry.json"), "utf-8"); + // The cast describes the file; it does not validate it. The runtime filter and + // the throw below are what actually stop us linting against an empty set. + const parsed = JSON.parse(raw) as RegistryManifest; + const names = (parsed.items ?? []).map((item) => item.name).filter((name) => Boolean(name)); + if (names.length === 0) { + throw new Error("registry/registry.json parsed to zero item names — refusing to lint blind."); + } + return new Set(names); +} + +/** `null` when the file is not marked as a registry snapshot; otherwise its violations. */ +export function lintRegistryItemRefs(content: string, known: Set): LineViolation[] | null { + // Marker detection ignores fenced blocks so a doc that *documents* the marker + // syntax in an example does not arm the check on itself. The scan below still + // reads full content, so ids inside fenced examples stay covered. + const marker = stripFencedBlocks(content).match(REGISTRY_MARKER); + if (!marker) return null; + const allowed = new Set((marker[1] ?? "").split(",").filter(Boolean)); + return content.split("\n").flatMap((line, index) => { + const dead = [...new Set([...line.matchAll(/`([^`\n]+)`/g)].map((m) => (m[1] ?? "").trim()))] + .filter((token) => REGISTRY_ITEM_ID.test(token)) + .filter((token) => !known.has(token) && !allowed.has(token)); + return dead.map((token) => + violation( + index + 1, + `"${token}" is not an item in registry/registry.json, but this file is marked as a registry snapshot. Correct the name, remove it, or add it to the marker's allow= list if it is legitimately not an item.`, + line.trim(), + ), + ); + }); +} + +function collectMarkdownFiles(dir: string): string[] { + return readdirSync(dir, { withFileTypes: true, recursive: true }) + .filter((entry) => entry.isFile() && entry.name.endsWith(".md")) + .map((entry) => join(entry.parentPath, entry.name)); +} + function lintFile(filePath: string): Violation[] { const raw = readFileSync(filePath, "utf-8"); const file = relative(process.cwd(), filePath); @@ -281,18 +355,35 @@ if (files.length === 0) { let totalViolations = 0; -for (const file of files) { - const violations = lintFile(file); +function report(file: string, violations: LineViolation[]): void { for (const v of violations) { - console.error(`${v.file}:${v.line}: ${v.message}`); + console.error(`${file}:${v.line}: ${v.message}`); console.error(` ${v.text}\n`); totalViolations++; } } +for (const file of files) { + report(relative(process.cwd(), file), lintFile(file)); +} + +const knownItems = registryItemNames(); +let snapshotsChecked = 0; +for (const dir of SKILLS_DIRS) { + if (!statSync(dir, { throwIfNoEntry: false })?.isDirectory()) continue; + for (const path of collectMarkdownFiles(dir)) { + const found = lintRegistryItemRefs(readFileSync(path, "utf-8"), knownItems); + if (found === null) continue; + snapshotsChecked++; + report(relative(process.cwd(), path), found); + } +} + if (totalViolations > 0) { console.error(`\n${totalViolations} skill lint error(s) found.`); process.exit(1); } else { - console.log(`Checked ${files.length} skill file(s) — no issues found.`); + console.log( + `Checked ${files.length} skill file(s) and ${snapshotsChecked} registry snapshot(s) against ${knownItems.size} registry items — no issues found.`, + ); } diff --git a/skills-manifest.json b/skills-manifest.json index e34115da7d..50188d976b 100644 --- a/skills-manifest.json +++ b/skills-manifest.json @@ -2,11 +2,11 @@ "source": "heygen-com/hyperframes", "skills": { "embedded-captions": { - "hash": "1677ab00946eb80c", + "hash": "57a5caaa35ff79c8", "files": 142 }, "faceless-explainer": { - "hash": "a7080101c30ceeb7", + "hash": "986ee23676272292", "files": 24 }, "figma": { @@ -14,11 +14,11 @@ "files": 2 }, "general-video": { - "hash": "16898c02677d09bc", + "hash": "ced729740550f414", "files": 4 }, "hyperframes": { - "hash": "f09636f3307817ab", + "hash": "e77a36c488b4f80c", "files": 17 }, "hyperframes-animation": { @@ -30,7 +30,7 @@ "files": 7 }, "hyperframes-cli": { - "hash": "1a691d7069bc158e", + "hash": "03b1b65f35a1be63", "files": 11 }, "hyperframes-core": { @@ -46,39 +46,39 @@ "files": 3 }, "hyperframes-registry": { - "hash": "0142a8e09bbe7e2c", + "hash": "51e6dba95a8dfb45", "files": 12 }, "media-use": { - "hash": "591daf2adb78e1cd", + "hash": "332f69eaeabc945f", "files": 156 }, "motion-graphics": { - "hash": "853ac75cbab69036", + "hash": "de8ec5464028ec67", "files": 23 }, "music-to-video": { - "hash": "39282be90a90f89f", + "hash": "be70b499dd72169b", "files": 132 }, "pr-to-video": { - "hash": "e3c6d1527c04a804", + "hash": "4905e50c64aab195", "files": 30 }, "product-launch-video": { - "hash": "71226b200d8adae3", + "hash": "960e964f32dcb4fa", "files": 30 }, "remotion-to-hyperframes": { - "hash": "79fcf8e9641d126e", + "hash": "13ade041e6416e5b", "files": 70 }, "slideshow": { - "hash": "c68fb51d48b80802", + "hash": "3d03ada897faebd2", "files": 2 }, "talking-head-recut": { - "hash": "2eaa83d6889537a5", + "hash": "50d1f9c928514826", "files": 28 } } diff --git a/skills/embedded-captions/SKILL.md b/skills/embedded-captions/SKILL.md index dbb201776d..f2a813b6a9 100644 --- a/skills/embedded-captions/SKILL.md +++ b/skills/embedded-captions/SKILL.md @@ -65,6 +65,8 @@ Procedure: probe the clip → shortlist 2–3 identities from the catalog → re (The full identity table lives in [CATALOG.md](CATALOG.md) — single source of truth for routing. The engine docs below describe each backend's authoring contract.) +**CATALOG.md is the whole answer space here: this workflow does not search the HyperFrames component registry.** The composition workflows run `npx hyperframes catalog` before authoring a named look; this one must not. Its engines are locked compilers that consume `cinematic.json` / `theme.json` and emit the composition themselves, so a registry item — the `caption-*` blocks included — has nothing to mount into. A registry block styles text on a designed canvas; this skill burns captions into somebody's footage through a matte. When no identity fits the ask, say so and pick the nearest, rather than reaching outside the catalog. + **Recommendation heuristic**: use the "Shortlisting heuristics" in [CATALOG.md](CATALOG.md) — they are identity-level (e.g. "炸" shortlists ordnance/stomp/terminal/loud and picks by WHAT should explode), never category-level. Unsure → `anchor`. - **Cinematic** → write `plan.json` for a locked template, compiled by `make-composition.cjs`. diff --git a/skills/faceless-explainer/SKILL.md b/skills/faceless-explainer/SKILL.md index 62568b587e..e040c7502c 100644 --- a/skills/faceless-explainer/SKILL.md +++ b/skills/faceless-explainer/SKILL.md @@ -123,6 +123,8 @@ Edit `STORYBOARD.md` in place. Do not create another storyboard. Use `frame.md` Read `references/visual-design.md`, `../hyperframes-animation/blueprints-index.md`, `references/motion-language.md`, and `../hyperframes-animation/rules-index.md`. Use `visual-design.md` for the method (the time-coded shot sequence, the inline Layout vocabulary, and the invented-visual treatment), plus the required `## Video direction` block. Use `../hyperframes-animation/blueprints-index.md` to pick each frame's shot shape. Use `motion-language.md` (the motion vocabulary + the motion doctrine) and `../hyperframes-animation/rules-index.md` (valid rule names) for motion — do not invent motion names. +**Search the live catalog before you invent any named look.** A faceless explainer invents every visual, which is exactly when a hand-authored rebuild of an existing block is most likely. For every look, effect, treatment or transition the brief names — "CRT scanlines", "glitch", "film grain", "shimmer sweep", "confetti burst" — run `npx hyperframes catalog --query "" --json` and read the top results BEFORE you write that look into `STORYBOARD.md`. The search needs **nothing installed**: no project, no prior `add`, no account. It ranks the whole hosted registry (~400 blocks and components) from any directory. A block that already does the job becomes the frame's `focal` — name it here so Step 5's workers install and customize it. Invent a visual only after a search for it came back with nothing that fits. + For every frame, write a **time-coded shot sequence** into `STORYBOARD.md` per `visual-design.md`'s method: pick the frame's blueprint (or compose), instantiate it with THIS frame's **invented** content, and pace each Scene's reveal to the voiceover so the frame develops across its full duration instead of front-loading then freezing. Because the explainer is faceless, `focal`/`roles` name the **invented visual elements** (a hero word, a diagram node, a data-viz series) — you are designing them, not selecting captured assets. State layout and motion **inline** per Scene (vocabularies in `visual-design.md` and `motion-language.md`). Add one video-wide `## Video direction` block. Do not change story, script, `transition_in`, or the source text. Do not write HTML in this step. There is **no asset-staging step** — faceless visuals are built by the workers in Step 5. If the user supplied a real `public/` image, reference it by path in the relevant frame's `focal`/`roles`; otherwise nothing to stage. diff --git a/skills/general-video/SKILL.md b/skills/general-video/SKILL.md index 8830870bb8..8628198019 100644 --- a/skills/general-video/SKILL.md +++ b/skills/general-video/SKILL.md @@ -101,7 +101,7 @@ Do not replace these reads with recollection. Progressive disclosure saves conte Use this dependency order. Skip a stage only when its input is absent. -1. **Plan.** State the viewer arc, structure, rhythm, and duration driver. Use one file for a short single scene; use sub-compositions for three or more hard scene cuts or any reused scene. Read `/hyperframes-creative` → `references/story-spine.md` for narrated arcs, `references/beat-direction.md` for rhythm, and `/hyperframes-core` → `references/composition-patterns.md` for structure. For an open-ended multi-scene brief, expand the prompt through `/hyperframes-creative` → `references/prompt-expansion.md`. A multi-scene plan cites each scene's shape: a blueprint id from `/hyperframes-animation` → `blueprints-index.md` when one fits, or the named rules it composes from `rules-index.md` when none does — motion names come from those indexes, never invented. Story truth decides which scenes exist; the citation dresses them. A multi-scene plan is also recorded as the dispatch artifact: one `## Frame N` block per scene in `STORYBOARD.md` — `status: outline`, a declared `src:`, the blueprint/rules citation, and the beat text — **even when `storyboard: no`**. The block is the dispatch unit; the board is only the review surface. +1. **Plan.** State the viewer arc, structure, rhythm, and duration driver. Use one file for a short single scene; use sub-compositions for three or more hard scene cuts or any reused scene. Read `/hyperframes-creative` → `references/story-spine.md` for narrated arcs, `references/beat-direction.md` for rhythm, and `/hyperframes-core` → `references/composition-patterns.md` for structure. For an open-ended multi-scene brief, expand the prompt through `/hyperframes-creative` → `references/prompt-expansion.md`. A multi-scene plan cites each scene's shape: a blueprint id from `/hyperframes-animation` → `blueprints-index.md` when one fits, or the named rules it composes from `rules-index.md` when none does — motion names come from those indexes, never invented. Story truth decides which scenes exist; the citation dresses them. **Search the live catalog before you plan to build any named look yourself**: for every look, effect, treatment or transition the brief names — "CRT scanlines", "glitch", "film grain", "shimmer sweep", "confetti burst" — run `npx hyperframes catalog --query "" --json` and read the top results before the plan names how that look gets built. The search needs **nothing installed**: no project, no prior `add`, no account. It ranks the whole hosted registry (~400 blocks and components) from any directory, so it also applies to a look the user asks for mid-build. Blocks the plan names are installed at stage 3; hand-author a look only after a search for it came back with nothing that fits. A multi-scene plan is also recorded as the dispatch artifact: one `## Frame N` block per scene in `STORYBOARD.md` — `status: outline`, a declared `src:`, the blueprint/rules citation, and the beat text — **even when `storyboard: no`**. The block is the dispatch unit; the board is only the review surface. 2. **Review the plan when requested.** For `storyboard: yes`, run the shared review loop over those blocks. For `storyboard: no`, continue without opening the board. When a plan pause happens anyway, fold the sub-agent delegation grant (needed by codex for step 4's dispatch) into that pause rather than stopping again later. 3. **Resolve dependencies.** Install registry blocks before parallel work. Stage user assets, adopt existing media, and resolve only what the brief requires. Start audio early when its timings drive duration. 4. **Build scenes.** For a short single-scene piece, implement the scene at its most visible moment before adding motion (the confirmed wireframe, when present, is that end state and must not be redrawn), then animate from its cited blueprint or rules — read the full recipe body (`/hyperframes-animation` → `blueprints/.md`, `rules/.md`) before writing motion. diff --git a/skills/hyperframes-cli/references/init-and-scaffold.md b/skills/hyperframes-cli/references/init-and-scaffold.md index f51f11eeca..5e04614094 100644 --- a/skills/hyperframes-cli/references/init-and-scaffold.md +++ b/skills/hyperframes-cli/references/init-and-scaffold.md @@ -16,7 +16,7 @@ npx hyperframes init my-video --non-interactive --example blank # CI/agents — **Default depends on TTY**: in a terminal, the CLI prompts for example/options. Outside a TTY (CI, agents, piped output) it auto-switches to non-interactive and **requires `--example`** (the CLI errors with a usage example if missing). Pass `--non-interactive` to force flag-only mode even on a TTY. -Templates: `blank`, `warm-grain`, `play-mode`, `swiss-grid`, `vignelli`, `decision-tree`, `kinetic-type`, `product-promo`, `nyt-graph`. +Templates: `blank`, `warm-grain`, `play-mode`, `swiss-grid`, `vignelli`, `decision-tree`, `kinetic-type`, `product-promo`, `nyt-graph`, `vscode-theme-visualizer`. (The closed set of `hyperframes:example` items in `registry/registry.json`. `hyperframes catalog` does not list examples — its `--type` takes only `block` or `component` — so this list has no live equivalent and is checked by `bun run lint:skills`.) Other useful flags: diff --git a/skills/hyperframes-registry/SKILL.md b/skills/hyperframes-registry/SKILL.md index 42a54d918a..5a5096f3da 100644 --- a/skills/hyperframes-registry/SKILL.md +++ b/skills/hyperframes-registry/SKILL.md @@ -1,6 +1,6 @@ --- name: hyperframes-registry -description: Install, discover, and wire registry blocks and components into HyperFrames compositions. Use when running hyperframes add or hyperframes catalog, installing one item or every block matching a tag, wiring an installed item into index.html, or working with hyperframes.json. Covers discovery, install locations, block sub-composition wiring, component snippet merging, and authoring a new block or component to contribute upstream (idea → scaffold → validate → PR). +description: Search, install, and wire registry blocks and components into HyperFrames compositions. Use BEFORE hand-building any named visual — whenever a brief, a user, or a storyboard names a look, effect, treatment, or transition such as CRT scanlines, glitch, chromatic aberration, film grain, a shimmer sweep, a chart, a code or terminal window, a map, or a confetti burst — because roughly 400 hosted items already cover many of them and the search ranks all of them with nothing installed, no project, and no account. Also use when running hyperframes add or hyperframes catalog, installing one item or every block matching a tag, wiring an installed item into index.html, or working with hyperframes.json. Covers discovery, install locations, block sub-composition wiring, component snippet merging, and authoring a new block or component to contribute upstream (idea → scaffold → validate → PR). --- # HyperFrames Registry diff --git a/skills/hyperframes-registry/references/discovery.md b/skills/hyperframes-registry/references/discovery.md index 550a9a7cf8..e0780bb570 100644 --- a/skills/hyperframes-registry/references/discovery.md +++ b/skills/hyperframes-registry/references/discovery.md @@ -1,5 +1,7 @@ # Registry discovery + + ## Use the catalog command first ```bash @@ -54,7 +56,7 @@ Where `` is `examples`, `blocks`, or `components`. ### Blocks -For an always-current list run `npx hyperframes catalog --type block`. The tables below group the 97 blocks by category. **Block name ≠ shader name**: shader-transition blocks (e.g. `domain-warp-dissolve`) wrap a HyperShader runtime whose internal name omits the `-dissolve`/`-warp` suffix — see the showcase HTML installed alongside the block for the canonical name. +For an always-current list run `npx hyperframes catalog --type block`. **The search is the source of truth; the tables below are a hand-maintained sample and under-cover by design** — they group 97 of the registry's 180 blocks by category, so a block missing from them is not evidence the registry lacks it. Only an empty `npx hyperframes catalog --query "" --json` is that evidence. Do not grow these tables toward the full set; search instead. **Block name ≠ shader name**: shader-transition blocks (e.g. `domain-warp-dissolve`) wrap a HyperShader runtime whose internal name omits the `-dissolve`/`-warp` suffix — see the showcase HTML installed alongside the block for the canonical name. #### Shader transitions (14) diff --git a/skills/hyperframes/SKILL.md b/skills/hyperframes/SKILL.md index d67beb8ead..f653653f28 100644 --- a/skills/hyperframes/SKILL.md +++ b/skills/hyperframes/SKILL.md @@ -85,17 +85,18 @@ Use the bare name without `/`. If the command fails, surface the error; do not r ## 5. Load domain skills on demand -| Need | Skill | -| ------------------------------------------------------------------------------------------------------------------- | ------------------------ | -| Composition structure, timing attributes, tracks, variables, determinism | `/hyperframes-core` | -| Motion rules, scene blueprints, transitions, runtime adapters | `/hyperframes-animation` | -| Seek-safe GSAP, CSS, Anime.js, WAAPI, FLIP, paths, masks, SVG, 3D keyframes, or `hyperframes keyframes` diagnostics | `/hyperframes-keyframes` | -| Design specs, concept, palette, typography, narration, beat planning | `/hyperframes-creative` | -| Images, icons, logos, audio, captions, grades, LUTs, reusable media | `/media-use` | -| Voiceover carve, audio effect chains, automation envelopes, or one chain/fader across several tracks (submix bus) | `/hyperframes-audio` | -| Init, lint, check, snapshots, compare, batch render, Studio, render, publish, or diagnostics | `/hyperframes-cli` | -| Registry blocks and components | `/hyperframes-registry` | -| Figma assets, tokens, components, or storyboard frames as reconstructed motion | `/figma` | +| Need | Skill | +| ------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | +| Composition structure, timing attributes, tracks, variables, determinism | `/hyperframes-core` | +| Motion rules, scene blueprints, transitions, runtime adapters | `/hyperframes-animation` | +| Seek-safe GSAP, CSS, Anime.js, WAAPI, FLIP, paths, masks, SVG, 3D keyframes, or `hyperframes keyframes` diagnostics | `/hyperframes-keyframes` | +| Design specs, concept, palette, typography, narration, beat planning | `/hyperframes-creative` | +| Images, icons, logos, audio, captions, grades, LUTs, reusable media | `/media-use` | +| Voiceover carve, audio effect chains, automation envelopes, or one chain/fader across several tracks (submix bus) | `/hyperframes-audio` | +| Init, lint, check, snapshots, compare, batch render, Studio, render, publish, or diagnostics | `/hyperframes-cli` | +| Registry blocks and components | `/hyperframes-registry` | +| A named look, effect, treatment, or transition — CRT scanlines, glitch, film grain, shimmer sweep, confetti burst — BEFORE hand-building it | `/hyperframes-registry` | +| Figma assets, tokens, components, or storyboard frames as reconstructed motion | `/figma` | Creator edit phrases are cross-domain requests. Load every skill named in the matching row: diff --git a/skills/media-use/audio/references/captions/authoring.md b/skills/media-use/audio/references/captions/authoring.md index 65687f6803..8992f1eff7 100644 --- a/skills/media-use/audio/references/captions/authoring.md +++ b/skills/media-use/audio/references/captions/authoring.md @@ -1,5 +1,9 @@ # Captions + + +**The live search is the source of truth for what the registry has.** The table(s) below are a hand-maintained sample and under-cover by design: run `npx hyperframes catalog --query "" --json` — it needs nothing installed — before concluding the registry lacks something. Item names here are checked against `registry/registry.json` by `bun run lint:skills`. + Before authoring: confirm the transcript came from the right Whisper model. CLI default `small.en` silently translates non-English audio — see [`../transcribe.md`](../transcribe.md) → "Language Rule" and [`transcript-handling.md`](transcript-handling.md) for the mandatory quality check. Analyze spoken content to determine caption style. If user specifies a style, use that. Otherwise, detect tone from the transcript. diff --git a/skills/motion-graphics/agents/builder.md b/skills/motion-graphics/agents/builder.md index 8fef685107..2e8a026fa1 100644 --- a/skills/motion-graphics/agents/builder.md +++ b/skills/motion-graphics/agents/builder.md @@ -6,6 +6,7 @@ Turn `shot-plan.json` into one renderable HyperFrames composition (`compositions Default = **compose existing catalog capabilities, not hand-author**: +- **Search first, for every named effect** — `npx hyperframes catalog --query "" --json`, including an effect the user names after the plan is written. It needs nothing installed and no project. Author by hand only after a search came back with nothing that does the job, and report that miss with `npx hyperframes feedback --search-miss`. - `npx hyperframes add ` (registry) → customize in place. Most blocks bake content/data into their own script (only a few expose CSS-var params), so reuse = **add + edit**. - `hyperframes-animation` rules / blueprints / transitions for motion; runtime adapters (GSAP default). diff --git a/skills/motion-graphics/agents/director.md b/skills/motion-graphics/agents/director.md index 37b17a237b..b2206181ca 100644 --- a/skills/motion-graphics/agents/director.md +++ b/skills/motion-graphics/agents/director.md @@ -40,7 +40,8 @@ Emit a DRAFT `shot-plan.json`. Given the draft + resolved `assets/index.md` (if Step 2 ran) + `catalog-map.md`, design the shot **around the assets**: -- Pick the **catalog block(s)** + the `hyperframes-animation` rules / blueprints (catalog-aware — see `catalog-map.md`). +- **Run `npx hyperframes catalog --query "" --json` for every look or effect the brief names**, before naming any block. It ranks the whole hosted registry and needs nothing installed. `catalog-map.md` is a partial snapshot; the search is the source of truth. +- Pick the **catalog block(s)** from those results + the `hyperframes-animation` rules / blueprints (see `catalog-map.md` for how each category customizes). - Layout (hero-frame), motion (per `references/motion-vocabulary.md`), beats, pacing, exits. - `asset-fusion`: read the asset's **geometric affordance** → `element_positions` (center / extent / safe-zones / avoid-zones) + **eyedropper palette** from the asset. - Finalize `shot-plan.json`: `content.block` + `content.customize` + the per-category `content`. diff --git a/skills/motion-graphics/catalog-map.md b/skills/motion-graphics/catalog-map.md index b69bcd7adc..801cc1a100 100644 --- a/skills/motion-graphics/catalog-map.md +++ b/skills/motion-graphics/catalog-map.md @@ -1,5 +1,18 @@ # Director → catalog block map (reuse-first) + + + +**Search the live catalog before you use this table, and again before any hand-authored effect.** Run +`npx hyperframes catalog --query "" --json` — once per named look or effect the +user asks for ("CRT scanlines", "glitch", "film grain", "shimmer sweep"), including effects asked for +mid-build. **The search needs nothing installed**: it ranks the whole hosted registry (~400 items) from any +directory, with no project, no prior `add`, and no account. The table below is a hand-maintained snapshot of +part of that registry and it under-covers by design — treat a miss here as unproven, and only the search's +own empty result as evidence the catalog lacks the move. When it does, say so with +`npx hyperframes feedback --search-miss "" --wanted "" --tier ` +before hand-authoring. Full flags and tiers: `/hyperframes-registry` → § Discovery. + The Builder's **default is to compose existing HF catalog blocks, not hand-author.** `npx hyperframes add ` drops a block's source into `compositions/`; the Builder then **customizes in place** — most blocks bake their content/data into their own script (only a few expose CSS-var `params`), so reuse = **add + edit**, not pure variable injection. Hand-author only (a) gaps no block covers and (b) the asset-fusion affordance binding. After classifying intent → category, the **Director names the block(s) + what to customize** in the shot-plan IR: @@ -12,9 +25,9 @@ After classifying intent → category, the **Director names the block(s) + what | Category | Borrow from catalog | Customize | Gaps → hand-author | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- | -| **kinetic-typo** | one of **18 `caption-*`** (kinetic-slam, editorial-emphasis, clip-wipe, gradient-fill, neon-glow, glitch-rgb, matrix-decode, particle-burst, weight-shift, pill-karaoke, highlight, blend-difference…) | words; `emphasis_words` → `word--emphasis`; palette; font; timing | a motif none of the 18 cover | -| **charts** | `data-chart` (bar+line, staggered, value labels) | edit the data array + headline/subtitle; `--bg`/`--text` | pie/donut, bar-chart-race, ring/% | -| **stat** | `apple-money-count` (finance: $ counter + burst + SFX) **or** our generic `stat-motion` (any %/number + ring) | target, prefix/suffix, label, palette | — | +| **kinetic-typo** | one of **17 `caption-*`** (kinetic-slam, editorial-emphasis, clip-wipe, gradient-fill, neon-glow, glitch-rgb, matrix-decode, particle-burst, weight-shift, pill-karaoke, highlight, blend-difference…) | words; `emphasis_words` → `word--emphasis`; palette; font; timing | a motif none of the 17 cover | +| **charts** | `data-chart` (bar+line, staggered, value labels), `bar-chart-race` (a race) | edit the data array + headline/subtitle; `--bg`/`--text` | pie/donut, ring/% | +| **stat** | `apple-money-count` (finance: $ counter + burst + SFX) **or** hand-author a generic %/number + ring per `categories/stat/module.md` (there is no `stat-motion` block) | target, prefix/suffix, label, palette | — | | maps/geo | **vector lane**: `us-map` (+bubble/hex/flow), `world-map`, `spain-map` + **hand-author** `geo-highlight`/`geo-flow`/`flag-borders`/`pin-rollout` (NOT in registry — build per `categories/maps/module.md`). **basemap lane** (real satellite/dark / zoom-to-place): bake via `categories/maps/bake-basemap.mjs` → `