{"id":"7a90a404-83dc-4c9c-a359-3f71445c3640","entityType":"agent","slug":"clawhub-heygen-com-motion-graphics","name":"motion-graphics","canonicalUrl":"https://www.xpersona.co/agent/clawhub-heygen-com-motion-graphics","canonicalPath":"/agent/clawhub-heygen-com-motion-graphics","generatedAt":"2026-10-09T23:09:08.369Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-09T13:21:17.706Z","emptyReason":null},"description":"A short, design-led motion graphic where motion is the message — kinetic typography, stat count-up, chart/data-viz hit, logo sting / brand lockup, lower-third / callout / social overlay, animated map (highlight regions, connect places, zoom to a location), animated tweet / news-article / headline, webpage / UI animation (scroll, cursor, callouts), or fusing a real image's geometry into a chart. Usually under 10s (up to ~30s), no narration or live-action subject; renders to MP4 or transparent overlay. Longer / narrated / multi-scene → /general-video. Unclear → /hyperframes. Skill: motion-graphics Owner: heygen-com Summary: A short, design-led motion graphic where motion is the message — kinetic typography, stat count-up, chart/data-viz hit, logo sting / brand lockup, lower-third / callout / social overlay, animated map (highlight regions, connect places, zoom to a location), animated tweet / news-article / headline, webpage / UI animation (scroll, cursor, callouts), or fusing a real ima","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 2.6K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s17fpgb0p797dzkbtbrxw5x1hh89qs64:motion-graphics","sourceUrl":"https://clawhub.ai/heygen-com/motion-graphics","homepage":"https://clawhub.ai/heygen-com/skills/motion-graphics","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/heygen-com/motion-graphics","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/heygen-com/skills/motion-graphics","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":68,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"A short, design-led motion graphic where motion is the message — kinetic typography, stat count-up, chart/data-viz hit, logo sting / brand lockup, lower-third /"},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T13:21:17.706Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T13:21:17.706Z","emptyReason":null},"stars":null,"forks":null,"downloads":2573,"packageName":null,"latestVersion":"1.0.24","tractionLabel":"2.6K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T13:21:17.259Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T13:21:17.706Z","lastCrawledAt":"2026-10-09T13:21:17.259Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T13:21:17.259Z","lastVerifiedAt":null,"highlights":[{"version":"1.0.24","createdAt":"2026-10-04T19:31:39.200Z","changelog":"Synced from 0c3e244 (main)","fileCount":25,"zipByteSize":55743},{"version":"1.0.23","createdAt":"2026-10-04T19:18:59.891Z","changelog":"Synced from 173103d (main)","fileCount":25,"zipByteSize":55872},{"version":"1.0.22","createdAt":"2026-10-04T13:08:34.905Z","changelog":"Synced from 69a2169 (main)","fileCount":25,"zipByteSize":55861},{"version":"1.0.21","createdAt":"2026-10-03T22:39:34.988Z","changelog":"Synced from 9031a02 (main)","fileCount":25,"zipByteSize":55863},{"version":"1.0.20","createdAt":"2026-09-27T21:21:44.065Z","changelog":"Synced from ff6e210 (main)","fileCount":25,"zipByteSize":55443},{"version":"1.0.19","createdAt":"2026-09-23T20:57:52.003Z","changelog":"Synced from d49e7b9 (main)","fileCount":25,"zipByteSize":55693},{"version":"1.0.18","createdAt":"2026-09-22T11:06:43.109Z","changelog":"Synced from 05d09a7 (main)","fileCount":25,"zipByteSize":55655},{"version":"1.0.17","createdAt":"2026-09-14T01:25:53.734Z","changelog":"Synced from 95bea16 (main)","fileCount":25,"zipByteSize":56068}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s17fpgb0p797dzkbtbrxw5x1hh89qs64:motion-graphics","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-motion-graphics/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-motion-graphics/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-motion-graphics/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-motion-graphics/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-motion-graphics/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-motion-graphics/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T23:09:08.365Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-motion-graphics/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-motion-graphics/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-motion-graphics/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-heygen-com-motion-graphics/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-09T13:21:17.706Z","emptyReason":null},"readme":"Skill: motion-graphics\n\nOwner: heygen-com\n\nSummary: A short, design-led motion graphic where motion is the message — kinetic typography, stat count-up, chart/data-viz hit, logo sting / brand lockup, lower-third / callout / social overlay, animated map (highlight regions, connect places, zoom to a location), animated tweet / news-article / headline, webpage / UI animation (scroll, cursor, callouts), or fusing a real image's geometry into a chart. Usually under 10s (up to ~30s), no narration or live-action subject; renders to MP4 or transparent overlay. Longer / narrated / multi-scene → /general-video. Unclear → /hyperframes.\n\nTags: latest:1.0.24\n\nVersion history:\n\nv1.0.24 | 2026-10-04T19:31:39.200Z | user\n\nSynced from 0c3e244 (main)\n\nv1.0.23 | 2026-10-04T19:18:59.891Z | user\n\nSynced from 173103d (main)\n\nv1.0.22 | 2026-10-04T13:08:34.905Z | user\n\nSynced from 69a2169 (main)\n\nv1.0.21 | 2026-10-03T22:39:34.988Z | user\n\nSynced from 9031a02 (main)\n\nv1.0.20 | 2026-09-27T21:21:44.065Z | user\n\nSynced from ff6e210 (main)\n\nv1.0.19 | 2026-09-23T20:57:52.003Z | user\n\nSynced from d49e7b9 (main)\n\nv1.0.18 | 2026-09-22T11:06:43.109Z | user\n\nSynced from 05d09a7 (main)\n\nv1.0.17 | 2026-09-14T01:25:53.734Z | user\n\nSynced from 95bea16 (main)\n\nv1.0.16 | 2026-09-10T03:25:01.656Z | user\n\nSynced from 0f8eb89 (main)\n\nv1.0.15 | 2026-08-21T03:09:36.582Z | user\n\nSynced from efc2e19 (main)\n\nv1.0.14 | 2026-08-19T21:04:07.025Z | user\n\nSynced from 9da422f (main)\n\nv1.0.13 | 2026-08-04T17:45:39.671Z | user\n\nSynced from f9ec934 (main)\n\nv1.0.12 | 2026-07-31T20:33:40.212Z | user\n\nSynced from ebea530 (main)\n\nv1.0.11 | 2026-07-28T11:29:11.579Z | user\n\nSynced from d287e52 (main)\n\nv1.0.10 | 2026-07-20T15:21:49.243Z | user\n\nSynced from 6ad738b (main)\n\nv1.0.9 | 2026-07-15T16:28:03.724Z | user\n\nSynced from c8d13af (main)\n\nv1.0.8 | 2026-07-15T13:23:56.040Z | user\n\nSynced from b9be0b2 (main)\n\nv1.0.7 | 2026-07-10T22:49:48.888Z | user\n\nSynced from 00d059b (main)\n\nv1.0.6 | 2026-07-10T02:57:37.672Z | user\n\nSynced from a8f242e (main)\n\nv1.0.5 | 2026-07-08T18:01:04.800Z | user\n\nSynced from 17b8527 (main)\n\nv1.0.4 | 2026-07-08T17:32:28.747Z | user\n\nSynced from 81884a7 (main)\n\nv1.0.3 | 2026-07-08T16:00:02.517Z | user\n\nSynced from 4d3cdc3 (main)\n\nv1.0.2 | 2026-07-07T20:28:26.060Z | user\n\nSynced from 7286b00 (main)\n\nv1.0.1 | 2026-07-07T18:58:05.563Z | user\n\nSynced from 5fe9573 (main)\n\nv1.0.0 | 2026-07-01T11:06:12.889Z | user\n\nOfficial HyperFrames skills from heygen-com/hyperframes\n\nArchive index:\n\nArchive v1.0.24: 25 files, 55743 bytes\n\nFiles: agents/builder.md (4071b), agents/director.md (6078b), agents/finalize.md (1071b), catalog-map.md (10641b), categories/asset-fusion/module.md (3968b), categories/charts/module.md (1982b), categories/kinetic-type/module.md (1607b), categories/logo-reveal/module.md (1131b), categories/lower-thirds/module.md (1493b), categories/maps/bake-basemap.mjs (14726b), categories/maps/module.md (9587b), categories/news/module.md (5425b), categories/stat/module.md (1330b), categories/tweet/module.md (1015b), categories/webpage/module.md (2538b), grounding/locate.mjs (8236b), grounding/PROTOCOL.md (3108b), phases/source/guide.md (1962b), references/builder-contract.md (2818b), references/motion-vocabulary.md (3978b), references/shot-plan-ir.md (2616b), samples/asset-fusion/_ref-circle-highlight.html (10674b), skill-card.md (1879b), SKILL.md (16013b), _meta.json (135b)\n\nFile v1.0.24:SKILL.md\n\n---\nname: motion-graphics\ndescription: >\n  A short, design-led motion graphic where motion is the message — kinetic\n  typography, stat count-up, chart/data-viz hit, logo sting / brand lockup,\n  lower-third / callout / social overlay, animated map (highlight regions,\n  connect places, zoom to a location), animated tweet / news-article /\n  headline, webpage / UI animation (scroll, cursor, callouts), or fusing a\n  real image's geometry into a chart. Usually under 10s (up to ~30s), no\n  narration or live-action subject; renders to MP4 or transparent overlay.\n  Longer / narrated / multi-scene → /general-video. Unclear → /hyperframes.\n---\n\n**Plugin installs:** Before setup or freshness commands, follow [plugin execution rules](../hyperframes/references/plugin-installation.md) when this skill is inside a HyperFrames plugin. Standalone installs keep the update instructions below.\n\n> **First, keep this skill fresh — confirm with the user before running:** `npx hyperframes skills update motion-graphics`. A fast no-op when everything is current; otherwise it refreshes this skill plus the core domain skills it depends on before you rely on them.\n\n> **figma source**: If the logo/asset/animation to build from comes from a figma.com URL, run `/figma` first — asset export, brand tokens, and Motion→GSAP translation if the graphic is a Figma Motion import — then build from its output. Don't drive Figma via raw MCP tools directly: that skips SVG sanitization, `.media/manifest.jsonl` provenance, and brand-token `var()` binding, so a later brand change can't propagate without a full re-import.\n\n# motion-graphics — dispatch entry\n\n> **The front door is `/hyperframes`.** This skill makes a **short, design-led, unnarrated motion graphic** (motion is the message; ~under 10s, no voice-over). Anything longer, narrated, or multi-scene — or any uncertainty → read `/hyperframes` first: the intent layer owns every route decision.\n\nThis workflow is **autonomous by design** — at most one clarifying question (`agents/director.md`), then build through verification without intermediate review. The intent layer (`/hyperframes` → `references/intent-interview.md`) routes here directly without run-shape questions; a storyboard and companion session add little to a piece this short. Rendering is still user-gated: after checks and proof snapshots pass, open the Studio preview and ask the canonical “render now, or what changes?” question from `../hyperframes/references/brief-contract.md`. When a `BRIEF.md` exists, read it before the director's question.\n\nA short design-led motion graphic. **Asset-first**: decide the asset strategy and source real material _before_ designing the shot, then design the shot around what you have, then compose by reusing catalog capabilities. All artifacts go to `PROJECT_DIR = videos/<project-name>/` (created in Step 0); all paths below are relative to it.\n\n| Phase    | Execution                                                             | Primary artifact                                                 | Detailed flow                 |\n| -------- | --------------------------------------------------------------------- | ---------------------------------------------------------------- | ----------------------------- |\n| init     | Bash                                                                  | `hyperframes.json`                                               | Step 0                        |\n| plan     | subagent — **decide search?** + classify + asset strategy             | `shot-plan.json` (draft: category, `asset_needs` queries, brief) | `agents/director.md` (Part 1) |\n| source ◇ | Bash — media-use resolve (**skip if `asset_needs` is empty**)         | `assets/` + `assets/index.md`                                    | `phases/source/guide.md`      |\n| design   | subagent — shot design around resolved assets                         | `shot-plan.json` (final: block(s) + layout + motion + positions) | `agents/director.md` (Part 2) |\n| build    | subagent — reuse-first composition                                    | `compositions/index.html`                                        | `agents/builder.md`           |\n| verify   | Bash — `lint`, `check`, proof snapshots; repair on failure            | `snapshots/contact-sheet.jpg`                                    | Step 5                        |\n| approve  | Open the preview; ask render or changes; wait for the answer          | explicit render approval                                         | Step 6                        |\n| render   | Bash — `hyperframes render` (MP4, or `--format webm/mov` for overlay) | `renders/video.mp4` or transparent overlay                       | Step 6                        |\n\n`◇ source` runs only when the chosen category declares assets. Pure code/text categories (e.g. `kinetic-type`, most `charts`/`stat`) have `asset_needs: []` and skip straight from plan to design.\n\n## Categories — split by the search decision\n\n`plan`'s **first decision is: does this need a search?** That fork splits the categories into two groups; then the specific category is picked — for search-driven, **by the type of content the search returns**. Each category is one `categories/<id>/module.md` (its planning + build rules); the shared motion vocabulary lives in `references/motion-vocabulary.md` (→ `hyperframes-animation` rules/blueprints + registry blocks).\n\n**Form categories — no search; the user supplies the content:**\n\n| Category       | Intent                                                                                                         | Leans on                                                                    |\n| -------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |\n| `kinetic-type` | punchy line / quote / title, motion-first text                                                                 | `caption-*` blocks + animation rules                                        |\n| `stat`         | single hero number / count-up + ring                                                                           | `apple-money-count` / `rules/{counting-dynamic-scale, stat-bars-and-fills}` |\n| `charts`       | bar / line / pie / race / % from data                                                                          | `data-chart` block                                                          |\n| `logo-reveal`  | logo sting / brand lockup (user logo)                                                                          | `logo-outro` / `rules/svg-path-draw`                                        |\n| `lower-thirds` | name / title bars, callouts, social overlays                                                                   | `caption-*` + registry overlay blocks                                       |\n| `maps`         | geographic motion — highlight regions, connect places, zoom to a location (vector lane, or baked basemap lane) | `us-map` / `world-map` family + `bake-basemap.mjs`                          |\n\n**Search-driven categories — search first, then animate by content type** (the RWA path):\n\n| Returned content | Category       | Animation                                                      |\n| ---------------- | -------------- | -------------------------------------------------------------- |\n| webpage / link   | `webpage`      | webpage / UI animation (scroll, reveal, cursor, callouts)      |\n| news article     | `news`         | headline reveal + source card + key-fact callouts              |\n| tweet            | `tweet`        | animated tweet card                                            |\n| image / entity   | `asset-fusion` | the asset's geometry _becomes_ the chart (RWA diegetic fusion) |\n\nBuild order: one at a time, coverage-first (rough is fine). `kinetic-type` ported from the prototype; the rest follow.\n\n## Prerequisites\n\nmacOS Apple Silicon or Linux x64. System tools: `brew install node ffmpeg`. `npx hyperframes doctor` once. macOS GPU render: `export PRODUCER_BROWSER_GPU_MODE=hardware`.\n\nOptional keys (local fallbacks if unset) — only needed by categories that source/generate assets via media-use:\n\n| Key                                 | Used for                                                    | Fallback                        |\n| ----------------------------------- | ----------------------------------------------------------- | ------------------------------- |\n| `GEMINI_API_KEY` / `GOOGLE_API_KEY` | image generation (media-use resolve)                        | skip generate / search-only     |\n| (asset_scout / search providers)    | `webpage`/`news`/`tweet` + `asset-fusion` real-asset search | category degrades to asset-free |\n\n## Flow\n\n### Step 0 — Initialize\n\ncwd is the agent workspace root; write all artifacts under `PROJECT_DIR = videos/<project-name>/`. `<project-name>`: use the dir the user gave, else a short kebab-case name from the intent (`<subject>-motion`). Not the workspace basename or a timestamp.\n\nOnly when `$PROJECT_DIR/hyperframes.json` is absent:\n\n```bash\nPROJECT_DIR=\"${MOTION_GRAPHICS_DIR:-videos/<project-name>}\"\nmkdir -p \"$(dirname \"$PROJECT_DIR\")\"\nnpx hyperframes init \"$PROJECT_DIR\" --non-interactive --example=blank --skill=motion-graphics\n```\n\n`init` checks the installed skills against the latest on GitHub and updates the global set if any are out of date.\n\n**Constraints:** never `hyperframes init` in the workspace root; never nest another `hyperframes/` inside `PROJECT_DIR`; every Bash command (master + subagents) is a `(cd \"$PROJECT_DIR\" && ...)` subshell — never bare `cd`.\n\n### Step 1 — Plan (subagent: Director Part 1)\n\nDispatch one subagent. prompt = full `agents/director.md` + `## Dispatch context` (`SKILL_DIR` / `PROJECT_DIR` / the user's request / `Schema: <SKILL_DIR>/references/shot-plan-ir.md`). It must:\n\n1. **Decide: does this need a search?** (the first fork)\n   - **No** → pick a **form category** (kinetic-type / stat / charts / logo-reveal / lower-thirds / maps); content is user-supplied; `asset_needs: []`.\n   - **Yes** → emit a **search plan** into `asset_needs[]` (news / web / tweet / image; two-pole queries). The specific **search-driven category** (webpage / news / tweet / asset-fusion) is confirmed by the content type returned in Step 2, and finalized in Step 3.\n2. Write a draft `shot-plan.json` (envelope + chosen form category _or_ search intent + `asset_needs` + a one-paragraph shot brief). Schema: `references/shot-plan-ir.md`.\n\nValidation: `[ -s \"$PROJECT_DIR/shot-plan.json\" ] && echo ok || echo missing`.\n\n### Step 2 — Source ◇ (Bash: media-use, conditional)\n\nIf `shot-plan.json.asset_needs` is non-empty, resolve assets (search / generate / fetch → frozen project-local paths + ledger). See `phases/source/guide.md` (wraps `media-use resolve`; the search-driven categories use the news/web/tweet/image search). If `asset_needs` is empty, **skip to Step 3**.\n\nDegrade gracefully: if a search/provider is unavailable, the category falls back to asset-free (note it in `context.log`).\n\n### Step 3 — Design (subagent: Director Part 2)\n\nDispatch a subagent (prompt = `agents/director.md` Part 2 + dispatch context including the resolved `assets/index.md` if Step 2 ran + `catalog-map.md`). It designs the shot **around the available assets**: pick the catalog block(s) + the `hyperframes-animation` rules/blueprints, the layout, the motion, beats, and (for `asset-fusion`) the `element_positions` + eyedropper palette. Finalizes `shot-plan.json` (`content.block` + `content.customize` + per-category content).\n\n### Step 4 — Build (subagent: Builder, reuse-first)\n\nInclude the shared [motion principles](../hyperframes-creative/references/motion-principles.md) in the Builder's dispatch context. For `charts` and `stat`, also include [data in motion](../hyperframes-creative/references/data-in-motion.md). The Builder reads these guides before writing the timeline.\n\nDispatch a subagent. prompt = full `agents/builder.md` + dispatch context (`shot-plan.json`, `catalog-map.md`, the category's `module.md`, `references/motion-vocabulary.md`, `references/builder-contract.md`). **Reuse-first**: `npx hyperframes add <block>` + customize in place; hand-author only gaps + the asset-fusion affordance. Output `compositions/index.html` honoring the HF contract (paused GSAP timeline on `window.__timelines`, `class=\"clip\"` + stable ids, `tl.seek(0)`, deterministic).\n\n### Step 5 — Verify (Bash → repair subagent on failure)\n\n```bash\n(cd \"$PROJECT_DIR\" && npx hyperframes check .)\n(cd \"$PROJECT_DIR\" && npx hyperframes snapshot --at <proof-times>)\n```\n\nChoose proof times that show the opening state, signature move, and final hold. Inspect the generated contact or snapshot sheet before continuing. On `lint`, `check`, or snapshot failure, dispatch the repair subagent (`agents/finalize.md`) for one in-place fix pass, then rerun the failed gate. Never change a fixed duration merely to hide a defect.\n\n### Step 6 — Approve and render (Bash)\n\nOpen Studio, then ask one question: “render now, or what changes?” After revisions, return to the same gate:\n\n```bash\n(cd \"$PROJECT_DIR\" && npx hyperframes preview --background)\n```\n\nRender only after an explicit render answer:\n\n```bash\n(cd \"$PROJECT_DIR\" && npx hyperframes render . --skill=motion-graphics -q high -o ./renders/video.mp4)\n# transparent overlay variant: --format webm  (or mov)\n```\n\nVerify the output exists, is non-empty, and has the intended duration. The final handoff names the artifact, actual duration, composition or frame id, proof times, and the inspected contact or snapshot sheet. Flags live in `/hyperframes-cli` → `references/preview-render.md`.\n\n## Resume table\n\n| State                                                    | Continue from              |\n| -------------------------------------------------------- | -------------------------- |\n| no `shot-plan.json`                                      | Step 1 (plan)              |\n| `shot-plan.json` has `asset_needs`, no `assets/`         | Step 2 (source)            |\n| `shot-plan.json` final, no `compositions/index.html`     | Step 3/4 (design+build)    |\n| `compositions/index.html` exists, proof snapshots absent | Step 5 (verify)            |\n| checks and proof snapshots pass, no approved render      | Step 6 (approval)          |\n| approved render exists                                   | verify output, then report |\n\n## Design notes (maintainers — execution does not read this)\n\n- **Asset-first rationale:** sourcing is front-loaded and informs shot design (the RWA flow: analyze → search → review → compose). the search-driven categories (`webpage`/`news`/`tweet`) and `asset-fusion` both lean on media-use search (news/web/tweet/image), which is media-use's documented RWA lineage.\n- **Reuse-first:** the in-ecosystem analog of LLM-generated templates is \"compose catalog blocks + `hyperframes-animation` rules\". HF's paused GSAP timeline ≙ Remotion's `useCurrentFrame`.\n- **Category module contract:** one `categories/<id>/module.md` (planning + build), sharing `references/motion-vocabulary.md` (+ optional eval). Adding a category = drop the folder + register its classifier line in `agents/director.md` + its row in `catalog-map.md`; the phase pipeline is untouched.\n- **Directory shape:**\n  ```\n  videos/<project-name>/\n    hyperframes.json  context.log\n    shot-plan.json            # the IR (Director output)\n    assets/  assets/index.md  # media-use output (if sourced)\n    compositions/index.html   # Builder output\n    renders/video.mp4\n  ```\n- **Registration:** in `hyperframes` router — add the \"design-led short motion graphic\" intent + Workflow description; carve the motion-graphics triggers out of `/general-video`; add reverse Do-NOT-use edges. See `motion-graphics-genre.md` §5-7.\n\nFile v1.0.24:_meta.json\n\n{\n  \"ownerId\": \"kn77d06grj6xqp3dqwkk4bavhn89pegt\",\n  \"slug\": \"motion-graphics\",\n  \"version\": \"1.0.24\",\n  \"publishedAt\": 1791142299200\n}\n\nFile v1.0.24:references/builder-contract.md\n\n# Builder contract — composition rules (detail behind agents/builder.md)\n\n## Root must be sized\n\nRoot `#stage` (`data-composition-id`) needs `position: relative; width: <W>px; height: <H>px`. Without a resolved height, flex children collapse to ~0 and content piles into the top-left. Automated gates may miss it, so inspect proof snapshots.\n\n## Layout before animation\n\n1. Identify the **hero frame** (the moment most elements are visible) → build THAT in static CSS first, no GSAP.\n2. `.scene-content` fills the scene with padding, not offsets:\n   ```css\n   display: flex;\n   flex-direction: column;\n   justify-content: center;\n   width: 100%;\n   height: 100%;\n   padding: 120px 160px;\n   gap: 24px;\n   box-sizing: border-box;\n   ```\n   Never `position:absolute; top:Npx` on a content container (it overflows). Reserve absolute for decoratives. Keep ≥80px padding (title-safe margin).\n3. **Entrances**: use `gsap.from()` only for a non-clip element active from `t=0`. Inside `.clip`, in sub-compositions, and for later entrances, use explicit `fromTo()`. The CSS position is ground truth; the tween is the journey to it.\n4. **Exits**: only the final scene animates elements out; between scenes the transition IS the exit.\n\n## Timeline / clip contract\n\n- ONE `gsap.timeline({paused:true})` on `window.__timelines[\"<id>\"]`; `tl.seek(0)`; never `tl.play()`.\n- Timed elements: `class=\"clip\"` + `data-start`/`data-duration`/`data-track-index` + a stable `id`. Timeline-driven groups inside one full-duration clip don't each need timing attrs.\n- Deterministic only — no `Date.now()` / `Math.random()` / network. Count-ups tween a proxy object via `onUpdate` (seek-safe), never a wall-clock counter.\n\n## Correctness\n\n- **Seek-safe reveal of delayed elements**: on a non-clip element or wrapper inside a clip, use one registered timeline `fromTo()` with an explicit `{ autoAlpha: 0 }` start and `{ autoAlpha: 1, ... }` end. Do not page-load `gsap.set()` a later `.clip`, and never target `.clip` visibility; the framework owns its lifecycle. _(Eval finding.)_\n- **Count-ups** tween a proxy via `onUpdate`; they only render when the host advances the timeline **with events enabled** (`tl.time()` / non-suppressed seek). A bare `seek(t, true)` freezes them at 0 — the HF render host must seek with events on. _(Eval finding.)_\n- Clamp at tween bounds; don't let a spring overshoot past a held value.\n- Allowed eases: `power1–4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine` (`.in/.out/.inOut`).\n- One motif per scene. Run `hyperframes check`; mark intentional overflow `data-layout-allow-overflow=\"true\"`.\n- **Palette discipline**: define all colors in one `palette` object / CSS custom properties — no inline hex scattered through the markup (for `asset-fusion`, eyedropper the palette from the asset).\n\nFile v1.0.24:references/motion-vocabulary.md\n\n# text module · motion vocabulary (primitive → GSAP)\n\n<!-- registry-items: allow= -->\n\n**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 \"<what you want>\" --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`.\n\nNamed primitives the Director references in `motion` strings and the Builder implements. `code_hint`s are framework-neutral physics; the GSAP recipe is the HF implementation. Prefer an HF **registry component** (bottom) when one fits — don't reinvent.\n\n## Entry\n\n| primitive                     | GSAP recipe (into CSS end-state)                               | suits                     |\n| ----------------------------- | -------------------------------------------------------------- | ------------------------- |\n| `slide_bottom/top/left/right` | `from({ y:±150 / x:±200, opacity:0, ease:\"power4.out\" })`      | calm, build, professional |\n| `scale_grow`                  | `from({ scale:0, opacity:0, duration:.6, ease:\"power2.out\" })` | calm, gentle              |\n| `scale_punch`                 | `from({ scale:.6, opacity:0, ease:\"back.out(2.2)\" })`          | impact, energetic         |\n| `fade_in`                     | `from({ opacity:0, duration:.4 })`                             | subtle                    |\n| `fade_blur`                   | `from({ opacity:0, filter:\"blur(14px)\" })`                     | cinematic, dreamy         |\n| `typewriter`                  | reveal via clip/`SplitText` width step                         | technical, narrative      |\n| `word_reveal`                 | per-word `from({opacity:0,y:..}, stagger:.1)`                  | storytelling              |\n| `wave`                        | per-letter `from({y:..}, stagger:{each:.04})`                  | flowing, musical          |\n| `bounce_in`                   | `from({y:-120}, ease:\"bounce.out\")`                            | playful                   |\n| `slam`                        | `from({ y:-300, ease:\"power4.out\" })` + shake on land          | impact, heavy             |\n\n## Emphasis (in place, often on a beat)\n\n| primitive     | GSAP recipe                                                          | suits              |\n| ------------- | -------------------------------------------------------------------- | ------------------ |\n| `scale_pulse` | `to({ scale:1.12, yoyo:true, repeat:1, ease:\"sine.inOut\" })` at beat | rhythmic, peak     |\n| `shake`       | `to({ keyframes:[{x:-9},{x:9},{x:0}], ease:\"none\" })`                | urgent, intense    |\n| `glow`        | `to({ textShadow:\"0 0 46px <ink/accent>\", yoyo:true, repeat:1 })`    | important, magical |\n| `color_shift` | `to({ color:\"<accent>\" })` (or accent on the word in CSS)            | dynamic            |\n\n## Exit\n\n| primitive   | GSAP recipe                                        | suits      |\n| ----------- | -------------------------------------------------- | ---------- |\n| `fade_out`  | `to({ opacity:0, duration:.4, ease:\"power2.in\" })` | ending     |\n| `slide_out` | `to({ y/x: off, opacity:0, ease:\"power2.in\" })`    | transition |\n| `scale_out` | `to({ scale:1.06, opacity:0, ease:\"power2.in\" })`  | transition |\n\n## Accent graphics (not text)\n\n`underline_sweep` `fromTo({scaleX:0},{scaleX:1}, transformOrigin:\"left center\")` · `bar_wipe` · `hold_breath` `to({scale:1.015, ease:\"sine.inOut\"})`.\n\n## Prefer HF registry components when they fit\n\n`caption-kinetic-slam` · `caption-editorial-emphasis` · `caption-neon-glow` · `caption-glitch-rgb` · `caption-particle-burst` · `caption-weight-shift` · `caption-matrix-decode` · `caption-pill-karaoke` · `shimmer-sweep`. These are pre-built, in-ecosystem, and already render-tested — the Builder should reach for them before hand-rolling an equivalent.\n\nFile v1.0.24:references/shot-plan-ir.md\n\n# shot-plan IR\n\nThe single contract between Director and Builder. One file: `PROJECT_DIR/shot-plan.json`.\n\n```jsonc\n{\n  // ── envelope (every category) ──\n  \"category\": \"kinetic-type | stat | charts | logo-reveal | lower-thirds | webpage | news | tweet | asset-fusion\",\n  \"duration_s\": 6,\n  \"fps\": 30,\n  \"canvas\": { \"w\": 1080, \"h\": 1920, \"aspect\": \"9:16\" },\n  \"style\": \"free-form visual direction (mood / energy / reference)\",\n  \"palette\": [\"#…\"], // or \"derive-from-asset\"\n  \"font\": \"<HF embed-list font>\",\n  \"beats\": [12, 37], // optional accent frames/seconds\n  \"export\": \"mp4\", // or \"alpha-overlay\" (transparent webm/mov)\n\n  // ── sourcing seam (Director Part 1) — [] means skip the source phase ──\n  \"asset_needs\": [\n    {\n      \"role\": \"hero\",\n      \"kind\": \"image|icon|logo|svg|news|web|tweet\",\n      \"query\": \"…\",\n      \"source\": \"…\",\n      \"treatment\": \"cutout|recolor|vectorize|none\",\n    },\n  ],\n\n  // ── build directive (Director Part 2, reuse-first) ──\n  \"block\": \"<catalog block id, e.g. data-chart | caption-kinetic-slam>\", // optional\n  \"customize\": {\n    /* what to change on the block: data, text, palette, positions */\n  },\n\n  // ── category-specific content ──\n  \"content\": {\n    /* shape varies by category, below */\n  },\n}\n```\n\n**Per-category `content` shapes:**\n\n- `kinetic-type` → `scenes[]` `{ id, start, end, text, emphasis_words[], emotion, motion, beats[] }`\n- `stat` → `{ value, prefix, suffix, label, ring: bool }`\n- `charts` → `{ type: bar|line|pie|race|pct, data[], labels[], headline, axes: bool }`\n- `logo-reveal` → `{ logo: <asset path>, tagline, url }`\n- `lower-thirds` → `{ name, role, position, brand_colors[] }`\n- `webpage` → `{ url, capture, highlights: [ { selector|region, label } ] }` (step-highlight a real captured page)\n- `news` → `{ outlet, headline, body, keyword, layout: A|B, logo?, date?, subject? }` (article-highlight: lay text out readable — **no zoom** — then sweep a marker band over the keyword in place. Layout **A** = centered-emphasis 9:16 text-only; **B** = full article 16:9 with `logo` + `date` + `subject` (a person photo → `remove-background` cutout))\n- `tweet` → `{ author, handle, avatar, text, metrics }`\n- `asset-fusion` → `{ data_type, asset: <path>, affordance, element_positions: {center, extent, safe[], avoid[]}, derived_palette[], connectors[] }`\n\n**Invariants:** `scenes` (if present) partition `[0, duration_s]` with no gaps/overlaps · empty `asset_needs` ⇒ Step 2 (source) is skipped · a named `block` ⇒ the Builder reuses + customizes it rather than hand-authoring.\n\nFile v1.0.24:agents/builder.md\n\n# Motion-Graphics Builder\n\nTurn `shot-plan.json` into one renderable HyperFrames composition (`compositions/index.html`). Everything stays in the HF ecosystem — HTML is the source of truth; a single **paused** GSAP timeline carries all motion; the engine seeks it. Category-specific build rules live in `categories/<id>/module.md`; this file is the shared contract.\n\n## Reuse-first (the default)\n\nDefault = **compose existing catalog capabilities, not hand-author**:\n\n- **Search first, for every named effect** — `npx hyperframes catalog --query \"<the move, in plain English>\" --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`.\n- `npx hyperframes add <block>` (registry) → customize in place. Most blocks bake content/data into their own script (only a few expose CSS-var params), so reuse = **add + edit**.\n- `hyperframes-animation` rules / blueprints / transitions for motion; runtime adapters (GSAP default).\n\nHand-author only (a) gaps no block/rule covers, (b) the `asset-fusion` affordance binding. The Director named the block(s) + customizations in `shot-plan.json` (`content.block` + `content.customize`); see `catalog-map.md`.\n\n## The HF contract (non-negotiable)\n\n- Root `#stage` carries `data-composition-id`, `data-start=\"0\"`, `data-duration=<s>`, `data-fps`, `data-width`, `data-height`.\n- Exactly ONE `gsap.timeline({ paused:true })`; register `window.__timelines[\"<id>\"] = tl;`; end with `tl.seek(0)`. **Never `tl.play()`** for render-critical motion. No timers / async / event-driven timeline build. Finite repeats only.\n- **Timed clips** need `class=\"clip\"` + a stable `id`. Timeline-driven groups inside one full-duration clip don't each need timing attrs.\n- **Fonts**: prefer local `@font-face` (.woff2) for deterministic / offline render; CDN Google Fonts do render (compiler caches + injects `@font-face`) but warn + need network.\n- **Deterministic only** — no `Date.now()` / `Math.random()` / network.\n\n## Layout before animation\n\nBuild the **hero-frame end-state** in CSS first (flex + padding; never absolute offsets on content containers; the root must be sized). Use `fromTo()` for elements inside `.clip` and for any delayed entrance; `from()` is safe only for non-clip elements active from `t=0`. Exits belong to transitions or the final scene. Full rules: `references/builder-contract.md`.\n\n## IR → composition\n\n- `content.block` → `hyperframes add` it (or inline) + apply `content.customize`.\n- per-category `content` (text scenes / chart data / fusion positions / news-tweet content) → realize per `categories/<id>/module.md`.\n- resolved `asset_needs` → reference **frozen project-local paths** (never a remote URL or a prompt).\n- `palette[-1]` / bg + `font` from the envelope.\n- `export: alpha-overlay` → transparent bg; render `--format webm` (or `mov`).\n\n## Critical correctness (GSAP / seek)\n\nOpacity-gate delayed elements (set hidden until their entrance). Clamp at tween bounds (no overshoot past a held value). Allowed eases: `power1–4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine` (`.in/.out/.inOut`). One motif per scene. Run `hyperframes check` for overflow / collisions.\n\n## Motion quality\n\nBefore writing the timeline, read and follow the shared [motion principles](../../hyperframes-creative/references/motion-principles.md). For `charts` and `stat`, also read [data in motion](../../hyperframes-creative/references/data-in-motion.md) before laying out or animating the data.\n\n## Hand off for verification\n\nSelf-check the authored file, then return it to the orchestrator. Step 5 runs `hyperframes lint`, `hyperframes check`, and proof snapshots on the assembled project. Do not render. When redispatched with a finding, fix the offending element and never change a fixed `data-duration` during repair. Remotion-source migrations use `/remotion-to-hyperframes` and its SSIM harness instead.\n\nFile v1.0.24:agents/director.md\n\n# Motion-Graphics Director\n\nTurn a request into a `shot-plan.json` for a short (~3–30s) **design-led motion graphic**. You run in **two parts** around the asset-sourcing step: **Part 1 (plan)** before sourcing, **Part 2 (design)** after. You do NOT write composition code — that's the Builder. Schema: `references/shot-plan-ir.md`.\n\n## Part 1 — Plan (before sourcing)\n\nEmit a DRAFT `shot-plan.json`.\n\n0. **Decide first: does this need a search?** No → a **form category** (user supplies content). Yes → emit a search plan; the specific **search-driven category** (`webpage` / `news` / `tweet` / `asset-fusion`) is confirmed by what the search returns (Step 2 → finalized in Part 2).\n\n1. **Classify** — form categories by intent below; search-driven categories are picked post-search:\n\n   | Category       | Pick when…                                                                                                                                                                         |\n   | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n   | `kinetic-type` | a punchy line / quote / title; text is the hero                                                                                                                                    |\n   | `stat`         | a single hero number / count-up                                                                                                                                                    |\n   | `charts`       | bar / line / pie / race / % from data                                                                                                                                              |\n   | `logo-reveal`  | a logo sting / brand lockup (user supplies the logo)                                                                                                                               |\n   | `lower-thirds` | name/title bars, callouts, social overlays                                                                                                                                         |\n   | `maps`         | a geographic shot — highlight regions, connect places, zoom to a location. Sub-fork: **vector** (D3, stylized) vs **basemap** (baked MapLibre — real satellite/dark/zoom-to-place) |\n   | `webpage`      | highlight / animate a real captured web page or UI _(search-driven)_                                                                                                               |\n   | `news`         | a news article → article-highlight: blur → zoom into keyword _(search-driven)_                                                                                                     |\n   | `tweet`        | a tweet → animated card _(search-driven)_                                                                                                                                          |\n   | `asset-fusion` | a real photo/asset's geometry _becomes_ the chart _(search-driven)_                                                                                                                |\n\n   If genuinely ambiguous between two, ask exactly one question. Then load `categories/<id>/module.md` for that category's specifics.\n\n2. **Asset strategy → `asset_needs[]`.** Each item: `{ role, kind: image|icon|logo|svg|news|web|tweet, query|source, treatment }`.\n   - asset-free (`kinetic-type`, most `stat`/`charts`) → `asset_needs: []`.\n   - `maps` → **vector** lane: `asset_needs: []` (D3/TopoJSON, runs live in HF). **basemap** lane (satellite/dark/zoom-to-place): `asset_needs: [{ type: \"map-bake\", … }]` (baked in Source — see `categories/maps/module.md`).\n   - `webpage` / `news` / `tweet` → search the real source (page / article / tweet) + a supporting image. **Two-pole queries only**: atomic (1–3 words, composable: portraits, logos, objects) OR specific (5–15 words: a news event, a tweet). Never the middle. A failed specific query is dropped, not broadened.\n   - `asset-fusion` → search or generate one hero asset.\n   - `logo-reveal` → user-supplied logo (`source`).\n\n3. **Envelope**: `duration_s` (3–30), `fps` (30), `canvas` (default 1080×1920; 16:9 / 1:1 per platform), `style`, `palette` (hex list, or `\"derive-from-asset\"`), `font` (from the HF embed list), `beats`, `export` (`mp4` | `alpha-overlay`).\n\n4. **Shot brief**: one paragraph — what the viewer experiences + the single dominant motion idea.\n\n## Part 2 — Design (after sourcing)\n\nGiven the draft + resolved `assets/index.md` (if Step 2 ran) + `catalog-map.md`, design the shot **around the assets**:\n\n- **Run `npx hyperframes catalog --query \"<the move, in plain English>\" --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.\n- Pick the **catalog block(s)** from those results + the `hyperframes-animation` rules / blueprints (see `catalog-map.md` for how each category customizes).\n- Layout (hero-frame), motion (per `references/motion-vocabulary.md`), beats, pacing, exits.\n- `asset-fusion`: read the asset's **geometric affordance** → `element_positions` (center / extent / safe-zones / avoid-zones) + **eyedropper palette** from the asset.\n- Finalize `shot-plan.json`: `content.block` + `content.customize` + the per-category `content`.\n\n## Heuristics (design-led short motion)\n\n- **Motion IS the message**; no narration arc. Hook lands fast (~first 0.5s). **One dominant motif.** Pattern-interrupt if the piece runs >~2.5s (change exactly one thing). Effect intensity matches the energy. Legibility: a key element stays readable ≥~0.3s. Beats may be anticipated ~0.1s for perceived sync.\n- **Reuse-first**: name a catalog block; ask for hand-authored motion only for gaps + the `asset-fusion` affordance.\n\nThen hand `shot-plan.json` to the Builder.\n\nFile v1.0.24:agents/finalize.md\n\n# Finalize / repair subagent\n\nPerform snapshot QA and one in-place repair pass. Dispatch only when Step 5 `lint`, `check`, or snapshot review reports a defect. The orchestrator owns final approval and render; this agent never renders.\n\n## Dispatch context\n\n`SKILL_DIR` / `PROJECT_DIR` / proof snapshot times / `lint` and `check` output tails, when present.\n\n## Flow\n\n1. **Snapshots** — run `npx hyperframes snapshot --at <proof-times>` and inspect overflow, off-canvas content, text collisions, empty frames, wrong content, and unreadable motion.\n2. **One in-place repair pass** — edit `compositions/index.html` for the visible issues. Never change a fixed `data-duration`; timing is set upstream.\n3. **Recheck** — rerun `npx hyperframes lint`, `npx hyperframes check`, and the affected snapshots. Return the result to the orchestrator without rendering.\n\n## STOP / escalate\n\nOnly when the shot is **fundamentally wrong** (whole content off, needs recomposition) — return to Step 3/4 (re-design + re-build), don't force it with edits. Small fixes never escalate.\n\nFile v1.0.24:catalog-map.md\n\n# Director → catalog block map (reuse-first)\n\n<!-- registry-items: allow=geo-highlight,geo-flow,flag-borders,pin-rollout,stat-motion,data-composition-src -->\n<!-- allow= entries above are deliberately NOT registry items: geo-*/flag-borders/pin-rollout and stat-motion are hand-authored gaps this file names in order to say they are gaps. -->\n\n**Search the live catalog before you use this table, and again before any hand-authored effect.** Run\n`npx hyperframes catalog --query \"<the move, in plain English>\" --json` — once per named look or effect the\nuser asks for (\"CRT scanlines\", \"glitch\", \"film grain\", \"shimmer sweep\"), including effects asked for\nmid-build. **The search needs nothing installed**: it ranks the whole hosted registry (~400 items) from any\ndirectory, with no project, no prior `add`, and no account. The table below is a hand-maintained snapshot of\npart of that registry and it under-covers by design — treat a miss here as unproven, and only the search's\nown empty result as evidence the catalog lacks the move. When it does, say so with\n`npx hyperframes feedback --search-miss \"<query>\" --wanted \"<the move>\" --tier <tier from the envelope>`\nbefore hand-authoring. Full flags and tiers: `/hyperframes-registry` → § Discovery.\n\nThe Builder's **default is to compose existing HF catalog blocks, not hand-author.** `npx hyperframes add <block>` 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.\n\nAfter classifying intent → category, the **Director names the block(s) + what to customize** in the shot-plan IR:\n\n```jsonc\n\"content\": { \"block\": \"data-chart\", \"customize\": { \"data\": [...], \"headline\": \"…\", \"palette\": [\"…\"] } }\n```\n\n## Category → block(s)\n\n| Category               | Borrow from catalog                                                                                                                                                                                                                                                                                                                                                                         | Customize                                                                                        | Gaps → hand-author                                                                                             |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |\n| **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                                                                                   |\n| **charts**             | `data-chart` (bar+line, staggered, value labels), `bar-chart-race` (a race)                                                                                                                                                                                                                                                                                                                 | edit the data array + headline/subtitle; `--bg`/`--text`                                         | pie/donut, ring/%                                                                                              |\n| **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                                                            | —                                                                                                              |\n| 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` → `<video>` + geo-aligned SVG overlay (border draw-on + colour-block fills) | regions/data, palette, callouts/connectors, basemap style                                        | (basemap lane now covers real imagery + zoom-to-address — was the gap)                                         |\n| diagram                | `flowchart` (SVG connectors + nodes)                                                                                                                                                                                                                                                                                                                                                        | nodes, edges, labels                                                                             | —                                                                                                              |\n| **brand reveal**       | `logo-outro` (piece assembly + glow + tagline + URL pill)                                                                                                                                                                                                                                                                                                                                   | logo asset, tagline, URL, palette                                                                | —                                                                                                              |\n| transitions            | 15+ shader transitions (domain-warp, whip-pan, sdf-iris, glitch…)                                                                                                                                                                                                                                                                                                                           | direction, timing                                                                                | —                                                                                                              |\n| social overlay         | ig / tiktok / yt / x / reddit / spotify / macos cards                                                                                                                                                                                                                                                                                                                                       | handle, metrics, avatar                                                                          | —                                                                                                              |\n| polish                 | grain-overlay, vignette, shimmer-sweep, texture-mask-text                                                                                                                                                                                                                                                                                                                                   | intensity                                                                                        | —                                                                                                              |\n| **asset-fusion (RWA)** | **annotation kit from `north-korea-locked-down`** — scribble-circle draw-on, pop-up pill + pointer, red-wash, scanline, corners, camera push; + `us-map-bubble` callouts/connectors                                                                                                                                                                                                         | asset, annotation position (`element_positions`), label, palette **eyedropper'd from the asset** | **NET-NEW (not in catalog): the affordance binding — asset geometry _becomes_ the chart axis (straw → gauge)** |\n\n## Reuse mechanics\n\n- `npx hyperframes add <block>` → source lands in `compositions/<block>.html`; inline it or reference via `data-composition-src`; customize content/data/palette/positions in place.\n- Blocks ship at fixed canvases (1920×1080 / 1080×1920 / 1080×1080) — match or adapt.\n- Blocks already follow the HF contract (paused timeline, seek) — keep it.\n\n## Asset-fusion: borrow + net-new (the only real net-new IP)\n\nBorrow `north-korea-locked-down`'s annotation _language_; the net-new is the RWA fusion _logic_ (see the RWA study):\n\n1. Classify the data type; read the asset's **geometric affordance** — linearity → timeline/gauge, volume/texture → pie, height → bar, container → exploded view.\n2. **`element_positions`** — measure the asset's feature (center / extent / safe-zones / avoid-zones). This is the reverse-engineer step (vision); in the prototype it's hand-estimated.\n3. **Eyedropper palette** from the asset (never generic #FFF/#000).\n4. **Two layers** — asset (z0, full-bleed) + data graphics fused to its geometry (z1+), anchored by `element_positions`; connectors/scribble physically tie the data to the asset; the asset stays visible.\n\nFile v1.0.24:categories/asset-fusion/module.md\n\n# asset-fusion — category module (search-driven · the net-new IP)\n\n**A real asset's geometry _becomes_ the chart** — RWA diegetic fusion (the straw becomes a gauge; a glass's liquid becomes a pie). Not in any catalog; the genuinely net-new capability. ~5–8s.\n\n## Source (Step 2)\n\nSearch or generate one **hero asset** with strong geometric affordance. `asset_needs`: `{ kind: image, query|generate, treatment: cutout|none }`. Freeze it project-local.\n\n## Plan (Director Part 2) — the fusion logic\n\n1. Classify the **data type** (temporal / quantitative / proportion / spatial).\n2. Read the asset's **geometric affordance** — linearity → timeline/gauge · volume/texture → pie · height → bar · container → exploded view.\n3. `element_positions`: **GROUND with the locate protocol — never eyeball pixel coords.** Read **`grounding/PROTOCOL.md`** and run the loop with `node grounding/locate.mjs` (`overlay` → read strips → `region` → read crop → `final` → **`mark` + verify**). Zero keys/deps assumed (node + ffmpeg only); the optional `auto` fast path exists only when `GEMINI_API_KEY` happens to be set. Why: eyeballing put rings off-subject (~16–24% center error on weak vision models); the grid loop pulls it to ~2–4% (measured E2E: eyeball 6.5% → protocol 2.3% avg center error, no case worse).\n4. **Eyedropper palette** from the asset (never generic #FFF/#000).\n\n## Highlight + circle recipe (the common case)\n\n\"Ring / spotlight object X in a real image\" → use the drop-in template **`samples/asset-fusion/_ref-circle-highlight.html`**: set `CFG.box` (from the locate protocol), `CFG.label`, `CFG.asset`, EVEN `CFG.W/H`, `CFG.mode` (`full` = ring+connector+label+brackets+scanlines, `circle` = ring only). It computes the radial wash, the amber double over-stroke ring, connector, callout, and corner-bracket reticle from the box. The whole pipeline is: locate (PROTOCOL.md) → fill template → render.\n\n## Render gotchas (codified — skipping these breaks the render)\n\n- **EVEN width & height** — odd width _or height_ (e.g. 1400×933) → `ffmpeg` encode fails / distorts. Resize the asset/stage to even dims (1400×932).\n- **`data-width`/`data-height` must be STATIC HTML attrs on the stage** — the renderer's StaticGuard reads them at compile time, before JS runs. Setting them via `setAttribute` is too late → render falls back to portrait 1080×1920 and distorts. (The circle-highlight template now hard-codes them; keep them equal to `CFG.W/H`.)\n- **Draw-on (`stroke-dashoffset`) must be `autoAlpha:0`-gated** — `getTotalLength()` can read 0 before layout → dash disabled → a solid line shows at t=0. Gate every draw-on element with `autoAlpha:0` until it draws, and fall back `getTotalLength() || <const>`.\n- **CSS var tween scope** — `gsap.to(\":root\", {\"--x\":..})` won't reach an element that has its own inline `--x`; tween the var on the element itself.\n- **No camera push under a fixed overlay** — scaling the image while the ring/wash stay fixed drifts the target out of the ring. Either skip the push or scale the whole scene together.\n- Lossless delivery: `--format mov` (ProRes); `mp4` is lossy.\n\n## Vocabulary / leans on\n\n- Borrow the annotation kit from registry **`north-korea-locked-down`** (hand-drawn scribble circle draw-on, pop-up label + pointer, editorial wash, camera push).\n- Primitives: gauge fill / marker-rise along the affordance · connector (data → asset point) · diegetic chart fused to the asset's geometry.\n- Adapt the diegetic chart to each asset's affordance (read the geometry, fuse the data into it).\n\n## Build (reuse-first + hand-author the affordance)\n\n**Two layers**: asset (z0, full-bleed) + data graphics (z1+) fused to its geometry, anchored by `element_positions`; connectors/scribble physically tie the data to the asset; asset stays visible. Reference impl: the prototype `fusion-demo/index-annotated.html` (straw → gauge + borrowed annotation kit).\n\nFile v1.0.24:categories/charts/module.md\n\n# charts — category module\n\nAnimated **data-viz** from data. Asset-free (the \"input\" is the data). \"One chart, one message\" for short durations.\n\nRead [data in motion](../../../hyperframes-creative/references/data-in-motion.md) before planning or building. Apply its guidance to default chart choices; preserve a chart type explicitly requested by the user.\n\n## Plan (Director)\n\n`content`: `{ type: bar|line|pie|race|pct, data[], labels[], headline, axes: bool }`. For `race`, data must be cumulative/time-staged.\n\n## Vocabulary / leans on\n\n- Block: **`data-chart`** (animated **bar + line**, staggered reveal, value labels — proven: borrowed + customized + rendered to MP4 in the prototype `charts-demo`).\n- Also in the registry: **`bar-chart-race`** — install it rather than hand-authoring a race.\n- Gaps (hand-author): **pie / donut, ring/%** — no registry block covers these. Search first (`npx hyperframes catalog --query \"pie chart reveal\" --json`), then use SVG/CSS for data→geometry + GSAP for motion.\n- Signature animations: bar stagger-grow · line `stroke-dashoffset` draw-on · pie radial sweep · ring fill · KPI count-up · race reorder.\n\n## Build (reuse-first)\n\nReuse `data-chart`: `npx hyperframes add data-chart` → edit the data arrays + scales + headline/labels + palette in place (its data is baked in the script, not a `--variables` flag). Axes hidden by default; show muted only when magnitude is the message. Determinism: drive any animation from the seek clock, never wall-clock.\n\n## Dashboard-skeleton variant\n\nFor a **product-dashboard** case: lay out a skeleton dashboard — a top bar with a **real test logo** (e.g. the hyperframes logo in `samples/_assets/`) + a title, then a grid of 3–4 **KPI cards** (each a `stat` count-up) + one `data-chart` panel. Reveal order: header/logo in → cards stagger in → the chart animates. Composes the `stat` + `charts` primitives inside a dashboard frame; the logo is a frozen project-local asset.\n\nFile v1.0.24:categories/kinetic-type/module.md\n\n# kinetic-type — category module\n\nText is the hero; typography + motion carry the message. Usually asset-free (`asset_needs: []`).\n\n## Plan (Director)\n\n- **Style first.** If the project has a **`design.md` / `frame.md`** (precedence: `frame.md` → `design.md` → `DESIGN.md`), READ it and use its **exact palette / fonts / constraints** — do not invent. No spec → pick a named style, or ask: mood + light/dark + any brand color/font. (Style is an input the case must exercise; the same shot in two `design.md`s should look different.)\n- Segment the copy into scenes by meaning / breath (EN ~3–7 words; ZH ~4–12 chars). Tag each scene **Hook → Build → Punch → Resolve**.\n- 1–2 `emphasis_words` per scene. Per scene: `emotion` + `motion` (free-form) + `beats`.\n\n## Vocabulary\n\nMotion primitives + registry blocks: **`references/motion-vocabulary.md`** (slide / scale / fade / blur / typewriter / word_reveal / wave / bounce / slam / scale_pulse / shake / glow / color_shift, plus the 18 `caption-*` blocks).\n\n## Build (reuse-first)\n\n- Prefer a **`caption-*` block** when one fits (`caption-kinetic-slam` / `caption-editorial-emphasis` / …): `npx hyperframes add` + set words / `emphasis_words` / palette / font.\n- Else hand-author: one full-duration `.clip`; a `.group` per scene (flex-centered); words as spans; explicit `gsap.fromTo()` entrances per scene `motion`; emphasis words → `glow` / `scale_pulse` on the beat; seek-safe `autoAlpha` only on inner non-clip elements. Honor `references/builder-contract.md`.\n- Reference impl: prototype `v0-text-motion-demo` + `pipeline-demo`.\n\nArchive v1.0.23: 25 files, 55872 bytes\n\nFiles: agents/builder.md (4071b), agents/director.md (6078b), agents/finalize.md (1071b), catalog-map.md (10641b), categories/asset-fusion/module.md (3968b), categories/charts/module.md (1982b), categories/kinetic-type/module.md (1607b), categories/logo-reveal/module.md (1131b), categories/lower-thirds/module.md (1493b), categories/maps/bake-basemap.mjs (14726b), categories/maps/module.md (9587b), categories/news/module.md (5425b), categories/stat/module.md (1330b), categories/tweet/module.md (1015b), categories/webpage/module.md (2538b), grounding/locate.mjs (8236b), grounding/PROTOCOL.md (3108b), phases/source/guide.md (1962b), references/builder-contract.md (2818b), references/motion-vocabulary.md (3978b), references/shot-plan-ir.md (2616b), samples/asset-fusion/_ref-circle-highlight.html (10674b), skill-card.md (2128b), SKILL.md (16170b), _meta.json (135b)\n\nFile v1.0.23:SKILL.md\n\n---\nname: motion-graphics\ndescription: >\n  A short, design-led motion graphic where motion is the message — kinetic\n  typography, stat count-up, chart/data-viz hit, logo sting / brand lockup,\n  lower-third / callout / social overlay, animated map (highlight regions,\n  connect places, zoom to a location), animated tweet / news-article /\n  headline, webpage / UI animation (scroll, cursor, callouts), or fusing a\n  real image's geometry into a chart. Usually under 10s (up to ~30s), no\n  narration or live-action subject; renders to MP4 or transparent overlay.\n  Longer / narrated / multi-scene → /general-video. Unclear → /hyperframes.\n---\n\n**Plugin installs:** Before setup or freshness commands, follow [plugin execution rules](../hyperframes/references/plugin-installation.md) when this skill is inside a HyperFrames plugin. Standalone installs keep the update instructions below.\n\n> **First, keep this skill fresh — confirm with the user before running:** `npx hyperframes skills update motion-graphics`. A fast no-op when everything is current; otherwise it refreshes this skill plus the core domain skills it depends on before you rely on them.\n\n> **figma source**: If the logo/asset/animation to build from comes from a figma.com URL, run `/figma` first — asset export, brand tokens, and Motion→GSAP translation if the graphic is a Figma Motion import — then build from its output. Don't drive Figma via raw MCP tools directly: that skips SVG sanitization, `.media/manifest.jsonl` provenance, and brand-token `var()` binding, so a later brand change can't propagate without a full re-import.\n\n# motion-graphics — dispatch entry\n\n> **The front door is `/hyperframes`.** This skill makes a **short, design-led, unnarrated motion graphic** (motion is the message; ~under 10s, no voice-over). Anything longer, narrated, or multi-scene — or any uncertainty → read `/hyperframes` first: the intent layer owns every route decision.\n\nThis workflow is **autonomous by design** — at most one clarifying question (`agents/director.md`), then build through verification without intermediate review. The intent layer (`/hyperframes` → `references/intent-interview.md`) routes here directly without run-shape questions; a storyboard and companion session add little to a piece this short. Rendering is still user-gated: after checks and proof snapshots pass, open the Studio preview and ask the canonical “render now, or what changes?” question from `../hyperframes/references/brief-contract.md`. When a `BRIEF.md` exists, read it before the director's question.\n\nA short design-led motion graphic. **Asset-first**: decide the asset strategy and source real material _before_ designing the shot, then design the shot around what you have, then compose by reusing catalog capabilities. All artifacts go to `PROJECT_DIR = videos/<project-name>/` (created in Step 0); all paths below are relative to it.\n\n| Phase    | Execution                                                             | Primary artifact                                                 | Detailed flow                 |\n| -------- | --------------------------------------------------------------------- | ---------------------------------------------------------------- | ----------------------------- |\n| init     | Bash                                                                  | `hyperframes.json`                                               | Step 0                        |\n| plan     | subagent — **decide search?** + classify + asset strategy             | `shot-plan.json` (draft: category, `asset_needs` queries, brief) | `agents/director.md` (Part 1) |\n| source ◇ | Bash — media-use resolve (**skip if `asset_needs` is empty**)         | `assets/` + `assets/index.md`                                    | `phases/source/guide.md`      |\n| design   | subagent — shot design around resolved assets                         | `shot-plan.json` (final: block(s) + layout + motion + positions) | `agents/director.md` (Part 2) |\n| build    | subagent — reuse-first composition                                    | `compositions/index.html`                                        | `agents/builder.md`           |\n| verify   | Bash — `lint`, `check`, proof snapshots; repair on failure            | `snapshots/contact-sheet.jpg`                                    | Step 5                        |\n| approve  | Open the preview; ask render or changes; wait for the answer          | explicit render approval                                         | Step 6                        |\n| render   | Bash — `hyperframes render` (MP4, or `--format webm/mov` for overlay) | `renders/video.mp4` or transparent overlay                       | Step 6                        |\n\n`◇ source` runs only when the chosen category declares assets. Pure code/text categories (e.g. `kinetic-type`, most `charts`/`stat`) have `asset_needs: []` and skip straight from plan to design.\n\n## Categories — split by the search decision\n\n`plan`'s **first decision is: does this need a search?** That fork splits the categories into two groups; then the specific category is picked — for search-driven, **by the type of content the search returns**. Each category is one `categories/<id>/module.md` (its planning + build rules); the shared motion vocabulary lives in `references/motion-vocabulary.md` (→ `hyperframes-animation` rules/blueprints + registry blocks).\n\n**Form categories — no search; the user supplies the content:**\n\n| Category       | Intent                                                                                                         | Leans on                                                                    |\n| -------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |\n| `kinetic-type` | punchy line / quote / title, motion-first text                                                                 | `caption-*` blocks + animation rules                                        |\n| `stat`         | single hero number / count-up + ring                                                                           | `apple-money-count` / `rules/{counting-dynamic-scale, stat-bars-and-fills}` |\n| `charts`       | bar / line / pie / race / % from data                                                                          | `data-chart` block                                                          |\n| `logo-reveal`  | logo sting / brand lockup (user logo)                                                                          | `logo-outro` / `rules/svg-path-draw`                                        |\n| `lower-thirds` | name / title bars, callouts, social overlays                                                                   | `caption-*` + registry overlay blocks                                       |\n| `maps`         | geographic motion — highlight regions, connect places, zoom to a location (vector lane, or baked basemap lane) | `us-map` / `world-map` family + `bake-basemap.mjs`                          |\n\n**Search-driven categories — search first, then animate by content type** (the RWA path):\n\n| Returned content | Category       | Animation                                                      |\n| ---------------- | -------------- | -------------------------------------------------------------- |\n| webpage / link   | `webpage`      | webpage / UI animation (scroll, reveal, cursor, callouts)      |\n| news article     | `news`         | headline reveal + source card + key-fact callouts              |\n| tweet            | `tweet`        | animated tweet card                                            |\n| image / entity   | `asset-fusion` | the asset's geometry _becomes_ the chart (RWA diegetic fusion) |\n\nBuild order: one at a time, coverage-first (rough is fine). `kinetic-type` ported from the prototype; the rest follow.\n\n## Prerequisites\n\nmacOS Apple Silicon or Linux x64. System tools: `brew install node ffmpeg`. `npx hyperframes doctor` once. macOS GPU render: `export PRODUCER_BROWSER_GPU_MODE=hardware`.\n\nOptional keys (local fallbacks if unset) — only needed by categories that source/generate assets via media-use:\n\n| Key                                 | Used for                                                    | Fallback                        |\n| ----------------------------------- | ----------------------------------------------------------- | ------------------------------- |\n| `GEMINI_API_KEY` / `GOOGLE_API_KEY` | image generation (media-use resolve)                        | skip generate / search-only     |\n| (asset_scout / search providers)    | `webpage`/`news`/`tweet` + `asset-fusion` real-asset search | category degrades to asset-free |\n\n## Flow\n\n### Step 0 — Initialize\n\ncwd is the agent workspace root; write all artifacts under `PROJECT_DIR = videos/<project-name>/`. `<project-name>`: use the dir the user gave, else a short kebab-case name from the intent (`<subject>-motion`). Not the workspace basename or a timestamp.\n\nOnly when `$PROJECT_DIR/hyperframes.json` is absent:\n\n```bash\nPROJECT_DIR=\"${MOTION_GRAPHICS_DIR:-videos/<project-name>}\"\nmkdir -p \"$(dirname \"$PROJECT_DIR\")\"\nnpx hyperframes init \"$PROJECT_DIR\" --non-interactive --example=blank --skill=motion-graphics\n```\n\n`init` checks the installed skills against the latest on GitHub and updates the global set if any are out of date.\n\n**Constraints:** never `hyperframes init` in the workspace root; never nest another `hyperframes/` inside `PROJECT_DIR`; every Bash command (master + subagents) is a `(cd \"$PROJECT_DIR\" && ...)` subshell — never bare `cd`.\n\n### Step 1 — Plan (subagent: Director Part 1)\n\nDispatch one subagent. prompt = full `agents/director.md` + `## Dispatch context` (`SKILL_DIR` / `PROJECT_DIR` / the user's request / `Schema: <SKILL_DIR>/references/shot-plan-ir.md`). It must:\n\n1. **Decide: does this need a search?** (the first fork)\n   - **No** → pick a **form category** (kinetic-type / stat / charts / logo-reveal / lower-thirds); content is user-supplied; `asset_needs: []`.\n   - **Yes** → emit a **search plan** into `asset_needs[]` (news / web / tweet / image; two-pole queries). The specific **search-driven category** (webpage / news / tweet / asset-fusion) is confirmed by the content type returned in Step 2, and finalized in Step 3.\n2. Write a draft `shot-plan.json` (envelope + chosen form category _or_ search intent + `asset_needs` + a one-paragraph shot brief). Schema: `references/shot-plan-ir.md`.\n\nValidation: `[ -s \"$PROJECT_DIR/shot-plan.json\" ] && echo ok || echo missing`.\n\n### Step 2 — Source ◇ (Bash: media-use, conditional)\n\nIf `shot-plan.json.asset_needs` is non-empty, resolve assets (search / generate / fetch → frozen project-local paths + ledger). See `phases/source/guide.md` (wraps `media-use resolve`; the search-driven categories use the news/web/tweet/image search). If `asset_needs` is empty, **skip to Step 3**.\n\n```bash\n# illustrative — see phases/source/guide.md\n(cd \"$PROJECT_DIR\" && node <SKILL_DIR>/phases/source/resolve.mjs --plan ./shot-plan.json --out ./assets)\n```\n\nDegrade gracefully: if a search/provider is unavailable, the category falls back to asset-free (note it in `context.log`).\n\n### Step 3 — Design (subagent: Director Part 2)\n\nDispatch a subagent (prompt = `agents/director.md` Part 2 + dispatch context including the resolved `assets/index.md` if Step 2 ran + `catalog-map.md`). It designs the shot **around the available assets**: pick the catalog block(s) + the `hyperframes-animation` rules/blueprints, the layout, the motion, beats, and (for `asset-fusion`) the `element_positions` + eyedropper palette. Finalizes `shot-plan.json` (`content.block` + `content.customize` + per-category content).\n\n### Step 4 — Build (subagent: Builder, reuse-first)\n\nInclude the shared [motion principles](../hyperframes-creative/references/motion-principles.md) in the Builder's dispatch context. For `charts` and `stat`, also include [data in motion](../hyperframes-creative/references/data-in-motion.md). The Builder reads these guides before writing the timeline.\n\nDispatch a subagent. prompt = full `agents/builder.md` + dispatch context (`shot-plan.json`, `catalog-map.md`, the category's `module.md`, `references/motion-vocabulary.md`, `references/builder-contract.md`). **Reuse-first**: `npx hyperframes add <block>` + customize in place; hand-author only gaps + the asset-fusion affordance. Output `compositions/index.html` honoring the HF contract (paused GSAP timeline on `window.__timelines`, `class=\"clip\"` + stable ids, `tl.seek(0)`, deterministic).\n\n### Step 5 — Verify (Bash → repair subagent on failure)\n\n```bash\n(cd \"$PROJECT_DIR\" && npx hyperframes check .)\n(cd \"$PROJECT_DIR\" && npx hyperframes snapshot --at <proof-times>)\n```\n\nChoose proof times that show the opening state, signature move, and final hold. Inspect the generated contact or snapshot sheet before continuing. On `lint`, `check`, or snapshot failure, dispatch the repair subagent (`agents/finalize.md`) for one in-place fix pass, then rerun the failed gate. Never change a fixed duration merely to hide a defect.\n\n### Step 6 — Approve and render (Bash)\n\nOpen Studio, then ask one question: “render now, or what changes?” After revisions, return to the same gate:\n\n```bash\n(cd \"$PROJECT_DIR\" && npx hyperframes preview --background)\n```\n\nRender only after an explicit render answer:\n\n```bash\n(cd \"$PROJECT_DIR\" && npx hyperframes render . --skill=motion-graphics -q high -o ./renders/video.mp4)\n# transparent overlay variant: --format webm  (or mov)\n```\n\nVerify the output exists, is non-empty, and has the intended duration. The final handoff names the artifact, actual duration, composition or frame id, proof times, and the inspected contact or snapshot sheet. Flags live in `/hyperframes-cli` → `references/preview-render.md`.\n\n## Resume table\n\n| State                                                    | Continue from              |\n| -------------------------------------------------------- | -------------------------- |\n| no `shot-plan.json`                                      | Step 1 (plan)              |\n| `shot-plan.json` has `asset_needs`, no `assets/`         | Step 2 (source)            |\n| `shot-plan.json` final, no `compositions/index.html`     | Step 3/4 (design+build)    |\n| `compositions/index.html` exists, proof snapshots absent | Step 5 (verify)            |\n| checks and proof snapshots pass, no approved render      | Step 6 (approval)          |\n| approved render exists                                   | verify output, then report |\n\n## Design notes (maintainers — execution does not read this)\n\n- **Asset-first rationale:** sourcing is front-loaded and informs shot design (the RWA flow: analyze → search → review → compose). the search-driven categories (`webpage`/`news`/`tweet`) and `asset-fusion` both lean on media-use search (news/web/tweet/image), which is media-use's documented RWA lineage.\n- **Reuse-first:** the in-ecosystem analog of LLM-generated templates is \"compose catalog blocks + `hyperframes-animation` rules\". HF's paused GSAP timeline ≙ Remotion's `useCurrentFrame`.\n- **Category module contract:** one `categories/<id>/module.md` (planning + build), sharing `references/motion-vocabulary.md` (+ optional eval). Adding a category = drop the folder + register its classifier line in `agents/director.md` + its row in `catalog-map.md`; the phase pipeline is untouched.\n- **Directory shape:**\n  ```\n  videos/<project-name>/\n    hyperframes.json  context.log\n    shot-plan.json            # the IR (Director output)\n    assets/  assets/index.md  # media-use output (if sourced)\n    compositions/index.html   # Builder output\n    renders/video.mp4\n  ```\n- **Registration:** in `hyperframes` router — add the \"design-led short motion graphic\" intent + Workflow description; carve the motion-graphics triggers out of `/general-video`; add reverse Do-NOT-use edges. See `motion-graphics-genre.md` §5-7.\n\nFile v1.0.23:_meta.json\n\n{\n  \"ownerId\": \"kn77d06grj6xqp3dqwkk4bavhn89pegt\",\n  \"slug\": \"motion-graphics\",\n  \"version\": \"1.0.23\",\n  \"publishedAt\": 1791141539891\n}\n\nFile v1.0.23:references/builder-contract.md\n\n# Builder contract — composition rules (detail behind agents/builder.md)\n\n## Root must be sized\n\nRoot `#stage` (`data-composition-id`) needs `position: relative; width: <W>px; height: <H>px`. Without a resolved height, flex children collapse to ~0 and content piles into the top-left. Automated gates may miss it, so inspect proof snapshots.\n\n## Layout before animation\n\n1. Identify the **hero frame** (the moment most elements are visible) → build THAT in static CSS first, no GSAP.\n2. `.scene-content` fills the scene with padding, not offsets:\n   ```css\n   display: flex;\n   flex-direction: column;\n   justify-content: center;\n   width: 100%;\n   height: 100%;\n   padding: 120px 160px;\n   gap: 24px;\n   box-sizing: border-box;\n   ```\n   Never `position:absolute; top:Npx` on a content container (it overflows). Reserve absolute for decoratives. Keep ≥80px padding (title-safe margin).\n3. **Entrances**: use `gsap.from()` only for a non-clip element active from `t=0`. Inside `.clip`, in sub-compositions, and for later entrances, use explicit `fromTo()`. The CSS position is ground truth; the tween is the journey to it.\n4. **Exits**: only the final scene animates elements out; between scenes the transition IS the exit.\n\n## Timeline / clip contract\n\n- ONE `gsap.timeline({paused:true})` on `window.__timelines[\"<id>\"]`; `tl.seek(0)`; never `tl.play()`.\n- Timed elements: `class=\"clip\"` + `data-start`/`data-duration`/`data-track-index` + a stable `id`. Timeline-driven groups inside one full-duration clip don't each need timing attrs.\n- Deterministic only — no `Date.now()` / `Math.random()` / network. Count-ups tween a proxy object via `onUpdate` (seek-safe), never a wall-clock counter.\n\n## Correctness\n\n- **Seek-safe reveal of delayed elements**: on a non-clip element or wrapper inside a clip, use one registered timeline `fromTo()` with an explicit `{ autoAlpha: 0 }` start and `{ autoAlpha: 1, ... }` end. Do not page-load `gsap.set()` a later `.clip`, and never target `.clip` visibility; the framework owns its lifecycle. _(Eval finding.)_\n- **Count-ups** tween a proxy via `onUpdate`; they only render when the host advances the timeline **with events enabled** (`tl.time()` / non-suppressed seek). A bare `seek(t, true)` freezes them at 0 — the HF render host must seek with events on. _(Eval finding.)_\n- Clamp at tween bounds; don't let a spring overshoot past a held value.\n- Allowed eases: `power1–4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine` (`.in/.out/.inOut`).\n- One motif per scene. Run `hyperframes check`; mark intentional overflow `data-layout-allow-overflow=\"true\"`.\n- **Palette discipline**: define all colors in one `palette` object / CSS custom properties — no inline hex scattered through the markup (for `asset-fusion`, eyedropper the palette from the asset).\n\nFile v1.0.23:references/motion-vocabulary.md\n\n# text module · motion vocabulary (primitive → GSAP)\n\n<!-- registry-items: allow= -->\n\n**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 \"<what you want>\" --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`.\n\nNamed primitives the Director references in `motion` strings and the Builder implements. `code_hint`s are framework-neutral physics; the GSAP recipe is the HF implementation. Prefer an HF **registry component** (bottom) when one fits — don't reinvent.\n\n## Entry\n\n| primitive                     | GSAP recipe (into CSS end-state)                               | suits                     |\n| ----------------------------- | -------------------------------------------------------------- | ------------------------- |\n| `slide_bottom/top/left/right` | `from({ y:±150 / x:±200, opacity:0, ease:\"power4.out\" })`      | calm, build, professional |\n| `scale_grow`                  | `from({ scale:0, opacity:0, duration:.6, ease:\"power2.out\" })` | calm, gentle              |\n| `scale_punch`                 | `from({ scale:.6, opacity:0, ease:\"back.out(2.2)\" })`          | impact, energetic         |\n| `fade_in`                     | `from({ opacity:0, duration:.4 })`                             | subtle                    |\n| `fade_blur`                   | `from({ opacity:0, filter:\"blur(14px)\" })`                     | cinematic, dreamy         |\n| `typewriter`                  | reveal via clip/`SplitText` width step                         | technical, narrative      |\n| `word_reveal`                 | per-word `from({opacity:0,y:..}, stagger:.1)`                  | storytelling              |\n| `wave`                        | per-letter `from({y:..}, stagger:{each:.04})`                  | flowing, musical          |\n| `bounce_in`                   | `from({y:-120}, ease:\"bounce.out\")`                            | playful                   |\n| `slam`                        | `from({ y:-300, ease:\"power4.out\" })` + shake on land          | impact, heavy             |\n\n## Emphasis (in place, often on a beat)\n\n| primitive     | GSAP recipe                                                          | suits              |\n| ------------- | -------------------------------------------------------------------- | ------------------ |\n| `scale_pulse` | `to({ scale:1.12, yoyo:true, repeat:1, ease:\"sine.inOut\" })` at beat | rhythmic, peak     |\n| `shake`       | `to({ keyframes:[{x:-9},{x:9},{x:0}], ease:\"none\" })`                | urgent, intense    |\n| `glow`        | `to({ textShadow:\"0 0 46px <ink/accent>\", yoyo:true, repeat:1 })`    | important, magical |\n| `color_shift` | `to({ color:\"<accent>\" })` (or accent on the word in CSS)            | dynamic            |\n\n## Exit\n\n| primitive   | GSAP recipe                                        | suits      |\n| ----------- | -------------------------------------------------- | ---------- |\n| `fade_out`  | `to({ opacity:0, duration:.4, ease:\"power2.in\" })` | ending     |\n| `slide_out` | `to({ y/x: off, opacity:0, ease:\"power2.in\" })`    | transition |\n| `scale_out` | `to({ scale:1.06, opacity:0, ease:\"power2.in\" })`  | transition |\n\n## Accent graphics (not text)\n\n`underline_sweep` `fromTo({scaleX:0},{scaleX:1}, transformOrigin:\"left center\")` · `bar_wipe` · `hold_breath` `to({scale:1.015, ease:\"sine.inOut\"})`.\n\n## Prefer HF registry components when they fit\n\n`caption-kinetic-slam` · `caption-editorial-emphasis` · `caption-neon-glow` · `caption-glitch-rgb` · `caption-particle-burst` · `caption-weight-shift` · `caption-matrix-decode` · `caption-pill-karaoke` · `shimmer-sweep`. These are pre-built, in-ecosystem, and already render-tested — the Builder should reach for them before hand-rolling an equivalent.\n\nFile v1.0.23:references/shot-plan-ir.md\n\n# shot-plan IR\n\nThe single contract between Director and Builder. One file: `PROJECT_DIR/shot-plan.json`.\n\n```jsonc\n{\n  // ── envelope (every category) ──\n  \"category\": \"kinetic-type | stat | charts | logo-reveal | lower-thirds | webpage | news | tweet | asset-fusion\",\n  \"duration_s\": 6,\n  \"fps\": 30,\n  \"canvas\": { \"w\": 1080, \"h\": 1920, \"aspect\": \"9:16\" },\n  \"style\": \"free-form visual direction (mood / energy / reference)\",\n  \"palette\": [\"#…\"], // or \"derive-from-asset\"\n  \"font\": \"<HF embed-list font>\",\n  \"beats\": [12, 37], // optional accent frames/seconds\n  \"export\": \"mp4\", // or \"alpha-overlay\" (transparent webm/mov)\n\n  // ── sourcing seam (Director Part 1) — [] means skip the source phase ──\n  \"asset_needs\": [\n    {\n      \"role\": \"hero\",\n      \"kind\": \"image|icon|logo|svg|news|web|tweet\",\n      \"query\": \"…\",\n      \"source\": \"…\",\n      \"treatment\": \"cutout|recolor|vectorize|none\",\n    },\n  ],\n\n  // ── build directive (Director Part 2, reuse-first) ──\n  \"block\": \"<catalog block id, e.g. data-chart | caption-kinetic-slam>\", // optional\n  \"customize\": {\n    /* what to change on the block: data, text, palette, positions */\n  },\n\n  // ── category-specific content ──\n  \"content\": {\n    /* shape varies by category, below */\n  },\n}\n```\n\n**Per-category `content` shapes:**\n\n- `kinetic-type` → `scenes[]` `{ id, start, end, text, emphasis_words[], emotion, motion, beats[] }`\n- `stat` → `{ value, prefix, suffix, label, ring: bool }`\n- `charts` → `{ type: bar|line|pie|race|pct, data[], labels[], headline, axes: bool }`\n- `logo-reveal` → `{ logo: <asset path>, tagline, url }`\n- `lower-thirds` → `{ name, role, position, brand_colors[] }`\n- `webpage` → `{ url, capture, highlights: [ { selector|region, label } ] }` (step-highlight a real captured page)\n- `news` → `{ outlet, headline, body, keyword, layout: A|B, logo?, date?, subject? }` (article-highlight: lay text out readable — **no zoom** — then sweep a marker band over the keyword in place. Layout **A** = centered-emphasis 9:16 text-only; **B** = full article 16:9 with `logo` + `date` + `subject` (a person photo → `remove-background` cutout))\n- `tweet` → `{ author, handle, avatar, text, metrics }`\n- `asset-fusion` → `{ data_type, asset: <path>, affordance, element_positions: {center, extent, safe[], avoid[]}, derived_palette[], connectors[] }`\n\n**Invariants:** `scenes` (if present) partition `[0, duration_s]` with no gaps/overlaps · empty `asset_needs` ⇒ Step 2 (source) is skipped · a named `block` ⇒ the Builder reuses + customizes it rather than hand-authoring.\n\nFile v1.0.23:agents/builder.md\n\n# Motion-Graphics Builder\n\nTurn `shot-plan.json` into one renderable HyperFrames composition (`compositions/index.html`). Everything stays in the HF ecosystem — HTML is the source of truth; a single **paused** GSAP timeline carries all motion; the engine seeks it. Category-specific build rules live in `categories/<id>/module.md`; this file is the shared contract.\n\n## Reuse-first (the default)\n\nDefault = **compose existing catalog capabilities, not hand-author**:\n\n- **Search first, for every named effect** — `npx hyperframes catalog --query \"<the move, in plain English>\" --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`.\n- `npx hyperframes add <block>` (registry) → customize in place. Most blocks bake content/data into their own script (only a few expose CSS-var params), so reuse = **add + edit**.\n- `hyperframes-animation` rules / blueprints / transitions for motion; runtime adapters (GSAP default).\n\nHand-author only (a) gaps no block/rule covers, (b) the `asset-fusion` affordance binding. The Director named the block(s) + customizations in `shot-plan.json` (`content.block` + `content.customize`); see `catalog-map.md`.\n\n## The HF contract (non-negotiable)\n\n- Root `#stage` carries `data-composition-id`, `data-start=\"0\"`, `data-duration=<s>`, `data-fps`, `data-width`, `data-height`.\n- Exactly ONE `gsap.timeline({ paused:true })`; register `window.__timelines[\"<id>\"] = tl;`; end with `tl.seek(0)`. **Never `tl.play()`** for render-critical motion. No timers / async / event-driven timeline build. Finite repeats only.\n- **Timed clips** need `class=\"clip\"` + a stable `id`. Timeline-driven groups inside one full-duration clip don't each need timing attrs.\n- **Fonts**: prefer local `@font-face` (.woff2) for deterministic / offline render; CDN Google Fonts do render (compiler caches + injects `@font-face`) but warn + need network.\n- **Deterministic only** — no `Date.now()` / `Math.random()` / network.\n\n## Layout before animation\n\nBuild the **hero-frame end-state** in CSS first (flex + padding; never absolute offsets on content containers; the root must be sized). Use `fromTo()` for elements inside `.clip` and for any delayed entrance; `from()` is safe only for non-clip elements active from `t=0`. Exits belong to transitions or the final scene. Full rules: `references/builder-contract.md`.\n\n## IR → composition\n\n- `content.block` → `hyperframes add` it (or inline) + apply `content.customize`.\n- per-category `content` (text scenes / chart data / fusion positions / news-tweet content) → realize per `categories/<id>/module.md`.\n- resolved `asset_needs` → reference **frozen project-local paths** (never a remote URL or a prompt).\n- `palette[-1]` / bg + `font` from the envelope.\n- `export: alpha-overlay` → transparent bg; render `--format webm` (or `mov`).\n\n## Critical correctness (GSAP / seek)\n\nOpacity-gate delayed elements (set hidden until their entrance). Clamp at tween bounds (no overshoot past a held value). Allowed eases: `power1–4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine` (`.in/.out/.inOut`). One motif per scene. Run `hyperframes check` for overflow / collisions.\n\n## Motion quality\n\nBefore writing the timeline, read and follow the shared [motion principles](../../hyperframes-creative/references/motion-principles.md). For `charts` and `stat`, also read [data in motion](../../hyperframes-creative/references/data-in-motion.md) before laying out or animating the data.\n\n## Hand off for verification\n\nSelf-check the authored file, then return it to the orchestrator. Step 5 runs `hyperframes lint`, `hyperframes check`, and proof snapshots on the assembled project. Do not render. When redispatched with a finding, fix the offending element and never change a fixed `data-duration` during repair. Remotion-source migrations use `/remotion-to-hyperframes` and its SSIM harness instead.\n\nFile v1.0.23:agents/director.md\n\n# Motion-Graphics Director\n\nTurn a request into a `shot-plan.json` for a short (~3–30s) **design-led motion graphic**. You run in **two parts** around the asset-sourcing step: **Part 1 (plan)** before sourcing, **Part 2 (design)** after. You do NOT write composition code — that's the Builder. Schema: `references/shot-plan-ir.md`.\n\n## Part 1 — Plan (before sourcing)\n\nEmit a DRAFT `shot-plan.json`.\n\n0. **Decide first: does this need a search?** No → a **form category** (user supplies content). Yes → emit a search plan; the specific **search-driven category** (`webpage` / `news` / `tweet` / `asset-fusion`) is confirmed by what the search returns (Step 2 → finalized in Part 2).\n\n1. **Classify** — form categories by intent below; search-driven categories are picked post-search:\n\n   | Category       | Pick when…                                                                                                                                                                         |\n   | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n   | `kinetic-type` | a punchy line / quote / title; text is the hero                                                                                                                                    |\n   | `stat`         | a single hero number / count-up                                                                                                                                                    |\n   | `charts`       | bar / line / pie / race / % from data                                                                                                                                              |\n   | `logo-reveal`  | a logo sting / brand lockup (user supplies the logo)                                                                                                                               |\n   | `lower-thirds` | name/title bars, callouts, social overlays                                                                                                                                         |\n   | `maps`         | a geographic shot — highlight regions, connect places, zoom to a location. Sub-fork: **vector** (D3, stylized) vs **basemap** (baked MapLibre — real satellite/dark/zoom-to-place) |\n   | `webpage`      | highlight / animate a real captured web page or UI _(search-driven)_                                                                                                               |\n   | `news`         | a news article → article-highlight: blur → zoom into keyword _(search-driven)_                                                                                                     |\n   | `tweet`        | a tweet → animated card _(search-driven)_                                                                                                                                          |\n   | `asset-fusion` | a real photo/asset's geometry _becomes_ the chart _(search-driven)_                                                                                                                |\n\n   If genuinely ambiguous between two, ask exactly one question. Then load `categories/<id>/module.md` for that category's specifics.\n\n2. **Asset strategy → `asset_needs[]`.** Each item: `{ role, kind: image|icon|logo|svg|news|web|tweet, query|source, treatment }`.\n   - asset-free (`kinetic-type`, most `stat`/`charts`) → `asset_needs: []`.\n   - `maps` → **vector** lane: `asset_needs: []` (D3/TopoJSON, runs live in HF). **basemap** lane (satellite/dark/zoom-to-place): `asset_needs: [{ type: \"map-bake\", … }]` (baked in Source — see `categories/maps/module.md`).\n   - `webpage` / `news` / `tweet` → search the real source (page / article / tweet) + a supporting image. **Two-pole queries only**: atomic (1–3 words, composable: portraits, logos, objects) OR specific (5–15 words: a news event, a tweet). Never the middle. A failed specific query is dropped, not broadened.\n   - `asset-fusion` → search or generate one hero asset.\n   - `logo-reveal` → user-supplied logo (`source`).\n\n3. **Envelope**: `duration_s` (3–30), `fps` (30), `canvas` (default 1080×1920; 16:9 / 1:1 per platform), `style`, `palette` (hex list, or `\"derive-from-asset\"`), `font` (from the HF embed list), `beats`, `export` (`mp4` | `alpha-overlay`).\n\n4. **Shot brief**: one paragraph — what the viewer experiences + the single dominant motion idea.\n\n## Part 2 — Design (after sourcing)\n\nGiven the draft + resolved `assets/index.md` (if Step 2 ran) + `catalog-map.md`, design the shot **around the assets**:\n\n- **Run `npx hyperframes catalog --query \"<the move, in plain English>\" --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.\n- Pick the **catalog block(s)** from those results + the `hyperframes-animation` rules / blueprints (see `catalog-map.md` for how each category customizes).\n- Layout (hero-frame), motion (per `references/motion-vocabulary.md`), beats, pacing, exits.\n- `asset-fusion`: read the asset's **geometric affordance** → `element_positions` (center / extent / safe-zones / avoid-zones) + **eyedropper palette** from the asset.\n- Finalize `shot-plan.json`: `content.block` + `content.customize` + the per-category `content`.\n\n## Heuristics (design-led short motion)\n\n- **Motion IS the message**; no narration arc. Hook lands fast (~first 0.5s). **One dominant motif.** Pattern-interrupt if the piece runs >~2.5s (change exactly one thing). Effect intensity matches the energy. Legibility: a key element stays readable ≥~0.3s. Beats may be anticipated ~0.1s for perceived sync.\n- **Reuse-first**: name a catalog block; ask for hand-authored motion only for gaps + the `asset-fusion` affordance.\n\nThen hand `shot-plan.json` to the Builder.\n\nFile v1.0.23:agents/finalize.md\n\n# Finalize / repair subagent\n\nPerform snapshot QA and one in-place repair pass. Dispatch only when Step 5 `lint`, `check`, or snapshot review reports a defect. The orchestrator owns final approval and render; this agent never renders.\n\n## Dispatch context\n\n`SKILL_DIR` / `PROJECT_DIR` / proof snapshot times / `lint` and `check` output tails, when present.\n\n## Flow\n\n1. **Snapshots** — run `npx hyperframes snapshot --at <proof-times>` and inspect overflow, off-canvas content, text collisions, empty frames, wrong content, and unreadable motion.\n2. **One in-place repair pass** — edit `compositions/index.html` for the visible issues. Never change a fixed `data-duration`; timing is set upstream.\n3. **Recheck** — rerun `npx hyperframes lint`, `npx hyperframes check`, and the affected snapshots. Return the result to the orchestrator without rendering.\n\n## STOP / escalate\n\nOnly when the shot is **fundamentally wrong** (whole content off, needs recomposition) — return to Step 3/4 (re-design + re-build), don't force it with edits. Small fixes never escalate.\n\nFile v1.0.23:catalog-map.md\n\n# Director → catalog block map (reuse-first)\n\n<!-- registry-items: allow=geo-highlight,geo-flow,flag-borders,pin-rollout,stat-motion,data-composition-src -->\n<!-- allow= entries above are deliberately NOT registry items: geo-*/flag-borders/pin-rollout and stat-motion are hand-authored gaps this file names in order to say they are gaps. -->\n\n**Search the live catalog before you use this table, and again before any hand-authored effect.** Run\n`npx hyperframes catalog --query \"<the move, in plain English>\" --json` — once per named look or effect the\nuser asks for (\"CRT scanlines\", \"glitch\", \"film grain\", \"shimmer sweep\"), including effects asked for\nmid-build. **The search needs nothing installed**: it ranks the whole hosted registry (~400 items) from any\ndirectory, with no project, no prior `add`, and no account. The table below is a hand-maintained snapshot of\npart of that registry and it under-covers by design — treat a miss here as unproven, and only the search's\nown empty result as evidence the catalog lacks the move. When it does, say so with\n`npx hyperframes feedback --search-miss \"<query>\" --wanted \"<the move>\" --tier <tier from the envelope>`\nbefore hand-authoring. Full flags and tiers: `/hyperframes-registry` → § Discovery.\n\nThe Builder's **default is to compose existing HF catalog blocks, not hand-author.** `npx hyperframes add <block>` 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.\n\nAfter classifying intent → category, the **Director names the block(s) + what to customize** in the shot-plan IR:\n\n```jsonc\n\"content\": { \"block\": \"data-chart\", \"customize\": { \"data\": [...], \"headline\": \"…\", \"palette\": [\"…\"] } }\n```\n\n## Category → block(s)\n\n| Category               | Borrow from catalog                                                                                                                                                                                                                                                                                                                                                                         | Customize                                                                                        | Gaps → hand-author                                                                                             |\n| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |\n| **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                                                                                   |\n| **charts**             | `data-chart` (bar+line, staggered, value labels), `bar-chart-race` (a race)                                                                                                                                                                                                                                                                                                                 | edit the data array + headline/subtitle; `--bg`/`--text`                                         | pie/donut, ring/%                                                                                              |\n| **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                                                            | —                                                                                                              |\n| 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` → `<video>` + geo-aligned SVG overlay (border draw-on + colour-block fills) | regions/data, palette, callouts/connectors, basemap style                                        | (basemap lane now covers real imagery + zoom-to-address — was the gap)                                         |\n| diagram                | `flowchart` (SVG connectors + nodes)                                                                                                                                                                                                                                                                                                                                                        | nodes, edges, labels                                                                             | —                                                                                                              |\n| **brand reveal**       | `logo-outro` (piece assembly + glow + tagline + URL pill)                                                                                                                                                                                                                                                                                                                                   | logo asset, tagline, URL, palette                                                                | —                                                                                                              |\n| transitions            | 15+ shader transitions (domain-warp, whip-pan, sdf-iris, glitch…)                                                                                                                                                                                                                                                                                                                           | direction, timing                                                                                | —                                                                                                              |\n| social overlay         | ig / tiktok / yt / x / reddit / spotify / macos cards                                                                                                                                                                                                                                                                                                                                       | handle, metrics, avatar                                                                          | —                                                                                                              |\n| polish                 | grain-overlay, vignette, shimmer-sweep, texture-mask-text                                                                                                                                                                                                                                                                                                                                   | intensity                                                                                        | —                                                                                                              |\n| **asset-fusion (RWA)** | **annotation kit from `north-korea-locked-down`** — scribble-circle draw-on, pop-up pill + pointer, red-wash, scanline, corners, camera push; + `us-map-bubble` callouts/connectors                                                                                                                                                                                                         | asset, annotation position (`element_positions`), label, palette **eyedropper'd from the asset** | **NET-NEW (not in catalog): the affordance binding — asset geometry _becomes_ the chart axis (straw → gauge)** |\n\n## Reuse mechanics\n\n- `npx hyperframes add <block>` → source lands in `compositions/<block>.html`; inline it or reference via `data-composition-src`; customize content/data/palette/positions in place.\n- Blocks ship at fixed canvases (1920×1080 / 1080×1920 / 1080×1080) — match or adapt.\n- Blocks already follow the HF contract (paused timeline, seek) — keep it.\n\n## Asset-fusion: borrow + net-new (the only real net-new IP)\n\nBorrow `north-korea-locked-down`'s annotation _language_; the net-new is the RWA fusion _logic_ (see the RWA study):\n\n1. Classify the data type; read the asset's **geometric affordance** — linearity → timeline/gauge, volume/texture → pie, height → bar, container → exploded view.\n2. **`element_positions`** — measure the asset's feature (center / extent / safe-zones / avoid-zones). This is the reverse-engineer step (vision); in the prototype it's hand-estimated.\n3. **Eyedropper palette** from the asset (never generic #FFF/#000).\n4. **Two layers** — asset (z0, full-bleed) + data graphics fused to its geometry (z1+), anchored by `element_positions`; connectors/scribble physically tie the data to the asset; the asset stays visible.\n\nFile v1.0.23:categories/asset-fusion/module.md\n\n# asset-fusion — category module (search-driven · the net-new IP)\n\n**A real asset's geometry _becomes_ the chart** — RWA diegetic fusion (the straw becomes a gauge; a glass's liquid becomes a pie). Not in any catalog; the genuinely net-new capability. ~5–8s.\n\n## Source (Step 2)\n\nSearch or generate one **hero asset** with strong geometric affordance. `asset_needs`: `{ kind: image, query|generate, treatment: cutout|none }`. Freeze it project-local.\n\n## Plan (Director Part 2) — the fusion logic\n\n1. Classify the **data type** (temporal / quantitative / proportion / spatial).\n2. Read the asset's **geometric affordance** — linearity → timeline/gauge · volume/texture → pie · height → bar · container → exploded view.\n3. `element_positions`: **GROUND with the locate protocol — never eyeball pixel coords.** Read **`grounding/PROTOCOL.md`** and run the loop with `node grounding/locate.mjs` (`overlay` → read strips → `region` → read crop → `final` → **`mark` + verify**). Zero keys/deps assumed (node + ffmpeg only); the optional `auto` fast path exists only when `GEMINI_API_KEY` happens to be set. Why: eyeballing put rings off-subject (~16–24% center error on weak vision models); the grid loop pulls it to ~2–4% (measured E2E: eyeball 6.5% → protocol 2.3% avg center error, no case worse).\n4. **Eyedropper palette** from the asset (never generic #FFF/#000).\n\n## Highlight + circle recipe (the common case)\n\n\"Ring / spotlight object X in a real image\" → use the drop-in template **`samples/asset-fusion/_ref-circle-highlight.html`**: set `CFG.box` (from the locate protocol), `CFG.label`, `CFG.asset`, EVEN `CFG.W/H`, `CFG.mode` (`full` = ring+connector+label+brackets+scanlines, `circle` = ring only). It computes the radial wash, the amber double over-stroke ring, connector, callout, and corner-bracket reticle from the box. The whole pipeline is: locate (PROTOCOL.md) → fill template → render.\n\n## Render gotchas (codified — skipping these breaks the render)\n\n- **EVEN width & height** — odd width _or height_ (e.g. 1400×933) → `ffmpeg` encode fails / distorts. Resize the asset/stage to even dims (1400×932).\n- **`data-width`/`data-height` must be STATIC HTML attrs on the stage** — the renderer's StaticGuard reads them at compile time, before JS runs. Setting them via `setAttribute` is too late → render falls back to portrait 1080×1920 and distorts. (The circle-highlight template now hard-codes them; keep them equal to `CFG.W/H`.)\n- **Draw-on (`stroke-dashoffset`) must be `autoAlpha:0`-gated** — `getTotalLength()` can read 0 before layout → dash disabled → a solid line shows at t=0. Gate every draw-on element with `autoAlpha:0` until it draws, and fall back `getTotalLength() || <const>`.\n- **CSS var tween scope** — `gsap.to(\":root\", {\"--x\":..})` won't reach an element that has its own inline `--x`; tween the var on the element itself.\n- **No camera push under a fixed overlay** — scaling the image while the ring/wash stay fixed drifts the target out of the ring. Either skip the push or scale the whole scene together.\n- Lossless delivery: `--format mov` (ProRes); `mp4` is lossy.\n\n## Vocabulary / leans on\n\n- Borrow the annotation kit from registry **`north-korea-locked-down`** (hand-drawn scribble circle draw-on, pop-up label + pointer, editorial wash, camera push).\n- Primitives: gauge fill / marker-rise along the affordance · connector (data → asset point) · diegetic chart fused to the asset's geometry.\n- Adapt the diegetic chart to each asset's affordance (read the geometry, fuse the data into it).\n\n## Build (reuse-first + hand-author the affordance)\n\n**Two layers**: asset (z0, full-bleed) + data graphics (z1+) fused to its geometry, anchored by `element_positions`; connectors/scribble physically tie the data to the asset; asset stays visible. Reference impl: the prototype `fusion-demo/index-annotated.html` (straw → gauge + borrowed annotation kit).\n\nFile v1.0.23:categories/charts/module.md\n\n# charts — category module\n\nAnimated **data-viz** from data. Asset-free (the \"input\" is the data). \"One chart, one message\" for short durations.\n\nRead [data in motion](../../../hyperframes-creative/references/data-in-motion.md) before planning or building. Apply its guidance to default chart choices; preserve a chart type explicitly requested by the user.\n\n## Plan (Director)\n\n`content`: `{ type: bar|line|pie|race|pct, data[], labels[], headline, axes: bool }`. For `race`, data must be cumulative/time-staged.\n\n## Vocabulary / leans on\n\n- Block: **`data-chart`** (animated **bar + line**, staggered reveal, value labels — proven: borrowed + customized + rendered to MP4 in the prototype `charts-demo`).\n- Also in the registry: **`bar-chart-race`** — install it rather than hand-authoring a race.\n- Gaps (hand-author): **pie / donut, ring/%** — no registry block covers these. Search first (`npx hyperframes catalog --query \"pie chart reveal\" --json`), then use SVG/CSS for data→geometry + GSAP for motion.\n- Signature animations: bar stagger-grow · line `stroke-dashoffset` draw-on · pie radial sweep · ring fill · KPI count-up · race reorder.\n\n## Build (reuse-first)\n\nReuse `data-chart`: `npx hyperframes add data-chart` → edit the data arrays + scales + headline/labels + palette in place (its data is baked in the script, not a `--variables` flag). Axes hidden by default; show muted only when magnitude is the message. Determinism: drive any animation from the seek clock, never wall-clock.\n\n## Dashboard-skeleton variant\n\nFor a **product-dashboard** case: lay out a skeleton dashboard — a top bar with a **real test logo** (e.g. the hyperframes logo in `samples/_assets/`) + a title, then a grid of 3–4 **KPI cards** (each a `stat` count-up) + one `data-chart` panel. Reveal order: header/logo in → cards stagger in → the chart animates. Composes the `stat` + `charts` primitives inside a dashboard frame; the logo is a frozen project-local asset.\n\nFile v1.0.23:categories/kinetic-type/module.md\n\n# kinetic-type — category module\n\nText is the hero; typography + motion carry the message. Usually asset-free (`asset_needs: []`).\n\n## Plan (Director)\n\n- **Style first.** If the project has a **`design.md` / `frame.md`** (precedence: `frame.md` → `design.md` → `DESIGN.md`), READ it and use its **exact palette / fonts / constraints** — do not invent. No spec → pick a named style, or ask: mood + light/dark + any brand color/font. (Style is an input the case must exercise; the same shot in two `design.md`s should look different.)\n- Segment the copy into scenes by meaning / breath (EN ~3–7 words; ZH ~4–12 chars). Tag each scene **Hook → Build → Punch → Resolve**.\n- 1–2 `emphasis_words` per scene. Per scene: `emotion` + `motion` (free-form) + `beats`.\n\n## Vocabulary\n\nMotion primitives + registry blocks: **`references/motion-vocabulary.md`** (slide / scale / fade / blur / typewriter / word_reveal / wave / bounce / slam / scale_pulse / shake / glow / color_shift, plus the 18 `caption-*` blocks).\n\n## Build (reuse-first)\n\n- Prefer a **`caption-*` block** when one fits (`caption-kinetic-slam` / `caption-editorial-emphasis` / …): `npx hyperframes add` + set words / `emphasis_words` / palette / font.\n- Else hand-author: one full-duration `.clip`; a `.group` per scene (flex-centered); words as spans; explicit `gsap.fromTo()` entrances per scene `motion`; emphasis words → `glow` / `scale_pulse` on the beat; seek-safe `autoAlpha` only on inner non-clip elements. Honor `references/builder-contract.md`.\n- Reference impl: prototype `v0-text-motion-demo` + `pipeline-demo`.\n\nArchive v1.0.22: 25 files, 55861 bytes\n\nFiles: agents/builder.md (4071b), agents/director.md (6078b), agents/finalize.md (1071b), catalog-map.md (10641b), categories/asset-fusion/module.md (3968b), categories/charts/module.md (1982b), categories/kinetic-type/module.md (1607b), categories/logo-reveal/module.md (1131b), categories/lower-thirds/module.md (1493b), categories/maps/bake-basemap.mjs (14726b), categories/maps/module.md (9587b), categories/news/module.md (5425b), categories/stat/module.md (1330b), categories/tweet/module.md (1015b), categories/webpage/module.md (2538b), grounding/locate.mjs (8236b), grounding/PROTOCOL.md (3108b), phases/source/guide.md (1962b), references/builder-contract.md (2818b), references/motion-vocabulary.md (3978b), references/shot-plan-ir.md (2616b), samples/asset-fusion/_ref-circle-highlight.html (10674b), skill-card.md (2033b), SKILL.md (16216b), _meta.json (135b)\n\nFile v1.0.22:SKILL.md\n\n---\nname: motion-graphics\ndescription: >\n  A short, design-led motion graphic where motion is the message — kinetic\n  typography, stat count-up, chart/data-viz hit, logo sting / brand lockup,\n  lower-third / callout / social overlay, animated map (highlight regions,\n  connect places, zoom to a location), animated tweet / news-article /\n  headline, webpage / UI animation (scroll, cursor, callouts), or fusing a\n  real image's geometry into a chart. Usually under 10s (up to ~30s), no\n  narration or live-action subject; renders to MP4 or transparent overlay.\n  Longer / narrated / multi-scene → /general-video. Unclear → /hyperframes.\n---\n\n**Plugin installs:** Before setup or freshness commands, follow [plugin execution rules](../hyperframes/references/plugin-installation.md) when this skill is inside a HyperFrames plugin. Standalone installs keep the update instructions below.\n\n> **First, keep this skill fresh — confirm with the user before running:** `npx hyperframes skills update motion-graphics`. A fast no-op when everything is current; otherwise it refreshes this skill plus the core domain skills it depends on before you rely on them.\n\n> **figma source**: If the logo/asset/animation to build from comes from a figma.com URL, run `/figma` first — asset export, brand tokens, and Motion→GSAP translation if the graphic is a Figma Motion import — then build from its output. Don't drive Figma via raw MCP tools directly: that skips SVG sanitization, `.media/manifest.jsonl` provenance, and brand-token `var()` binding, so a later brand change can't propagate without a full re-import.\n\n# motion-graphics — dispatch entry\n\n> **The front door is `/hyperframes`.** This skill makes a **short, design-led, unnarrated motion graphic** (motion is the message; ~under 10s, no voice-over). Anything longer, narrated, or multi-scene — or any uncertainty → read `/hyperframes` first: the intent layer owns every route decision.\n\nThis workflow is **autonomous by design** — at most one clarifying question (`agents/director.md`), then build through verification without intermediate review. The intent layer (`/hyperframes` → `references/intent-interview.md`) routes here directly without run-shape questions; a storyboard and companion session add little to a piece this short. Rendering is still user-gated: after checks and proof snapshots pass, open the Studio preview and ask the canonical “render now, or what changes?” question from `../hyperframes/references/brief-contract.md`. When a `BRIEF.md` exists, read it before the director's question.\n\nA short design-led motion graphic. **Asset-first**: decide the asset strategy and source real material _before_ designing the shot, then design the shot around what you have, then compose by reusing catalog capabilities. All artifacts go to `PROJECT_DIR = videos/<project-name>/` (created in Step 0); all paths below are relative to it.\n\n| Phase    | Execution                                                             | Primary artifact                                                 | Detailed flow                 |\n| -------- | --------------------------------------------------------------------- | ---------------------------------------------------------------- | ----------------------------- |\n| init     | Bash                                                                  | `hyperframes.json`                                               | Step 0                        |\n| plan     | subagent — **decide search?** + classify + asset strategy             | `shot-plan.json` (draft: category, `asset_needs` queries, brief) | `agents/director.md` (Part 1) |\n| source ◇ | Bash — media-use resolve (**skip if `asset_needs` is empty**)         | `assets/` + `assets/index.md`                                    | `phases/source/guide.md`      |\n| design   | subagent — shot design around resolved assets                         | `shot-plan.json` (final: block(s) + layout + motion + positions) | `agents/director.md` (Part 2) |\n| build    | subagent — reuse-first composition                                    | `compositions/index.html`                                        | `agents/builder.md`           |\n| verify   | Bash — `lint`, `check`, proof snapshots; repair on failure            | `snapshots/contact-sheet.jpg`                                    | Step 5                        |\n| approve  | Open the preview; ask render or changes; wait for the answer          | explicit render approval                                         | Step 6                        |\n| render   | Bash — `hyperframes render` (MP4, or `--format webm/mov` for overlay) | `renders/video.mp4` or transparent overlay                       | Step 6                        |\n\n`◇ source` runs only when the chosen category declares assets. Pure code/text categories (e.g. `kinetic-type`, most `charts`/`stat`) have `asset_needs: []` and skip straight from plan to design.\n\n## Categories — split by the search decision\n\n`plan`'s **first decision is: does this need a search?** That fork splits the categories into two groups; then the specific category is picked — for search-driven, **by the type of content the search returns**. Each category is one `categories/<id>/module.md` (its planning + build rules); the shared motion vocabulary lives in `references/motion-vocabulary.md` (→ `hyperframes-animation` rules/blueprints + registry blocks).\n\n**Form categories — no search; the user supplies the content:**\n\n| Category       | Intent                                                                                                         | Leans on                                                                    |\n| -------------- | -------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |\n| `kinetic-type` | punchy line / quote / title, motion-first text                                                                 | `caption-*` blocks + animation rules                                        |\n| `stat`         | single hero number / count-up + ring                                                                           | `apple-money-count` / `rules/{counting-dynamic-scale, stat-bars-and-fills}` |\n| `charts`       | bar / line / pie / race / % from data                                                                          | `data-chart` block                                                          |\n| `logo-reveal`  | logo sting / brand lockup (user logo)                                                                          | `logo-outro` / `rules/svg-path-draw`                                        |\n| `lower-thirds` | name / title bars, callouts, social overlays                                                                   | `caption-*` + registry overlay blocks                                       |\n| `maps`         | geographic motion — highlight regions, connect places, zoom to a location (vector lane, or baked basemap lane) | `us-map` / `world-map` family + `bake-basemap.mjs`                          |\n\n**Search-driven categories — search first, then animate by content type** (the RWA path):\n\n| Returned content | Category       | Animation                                                      |\n| ---------------- | -------------- | -------------------------------------------------------------- |\n| webpage / link   | `webpage`      | webpage / UI animation (scroll, reveal, cursor, callouts)      |\n| news article     | `news`         | headline reveal + source card + key-fact callouts              |\n| tweet            | `tweet`        | animated tweet card                                            |\n| image / entity   | `asset-fusion` | the asset's geometry _becomes_ the chart (RWA diegetic fusion) |\n\nBuild order: one at a time, coverage-first (rough is fine). `kinetic-type` ported from the prototype; the rest follow.\n\n## Prerequisites\n\nmacOS Apple Silicon or Linux x64. System tools: `brew install node ffmpeg`. `npx hyperframes doctor` once. macOS GPU render: `export PRODUCER_BROWSER_GPU_MODE=hardware`.\n\nOptional keys (local fallbacks if unset) — only needed by categories that source/generate assets via media-use:\n\n| Key                                 | Used for                                                    | Fallback                        |\n| ----------------------------------- | ----------------------------------------------------------- | ------------------------------- |\n| `GEMINI_API_KEY` / `GOOGLE_API_KEY` | image generation (media-use resolve)                        | skip generate / search-only     |\n| (asset_scout / search providers)    | `webpage`/`news`/`tweet` + `asset-fusion` real-asset search | category degrades to asset-free |\n\n## Flow\n\n### Step 0 — Initialize\n\ncwd is the agent workspace root; write all artifacts under `PROJECT_DIR = videos/<project-name>/`. `<project-name>`: use the dir the user gave, else a short kebab-case name from the intent (`<subject>-motion`). Not the workspace basename or a timestamp.\n\nOnly when `$PROJECT_DIR/hyperframes.json` is absent:\n\n```bash\nPROJECT_DIR=\"${MOTION_GRAPHICS_DIR:-videos/<project-name>}\"\nmkdir -p \"$(dirname \"$PROJECT_DIR\")\"\nnpx hyperframes init \"$PROJECT_DIR\" --non-interactive --example=blank --skill=motion-graphics\n```\n\n`init` checks the installed skills against the latest on GitHub and updates the global set if any are out of date.\n\n**Constraints:** never `hyperframes init` in the workspace root; never nest another `hyperframes/` inside `PROJECT_DIR`; every Bash command (master + subagents) is a `(cd \"$PROJECT_DIR\" && ...)` subshell — never bare `cd`.\n\n### Step 1 — Plan (subagent: Director Part 1)\n\nDispatch one subagent. prompt = full `agents/director.md` + `## Dispatch context` (`SKILL_DIR` / `PROJECT_DIR` / the user's request / `Schema: <SKILL_DIR>/references/shot-plan-ir.md`). It must:\n\n1. **Decide: does this need a search?** (the first fork)\n   - **No** → pick a **form category** (kinetic-type / stat / charts / logo-reveal / lower-thirds); content is user-supplied; `asset_needs: []`.\n   - **Yes** → emit a **search plan** into `asset_needs[]` (news / web / tweet / image; two-pole queries). The specific **search-driven category** (webpage / news / tweet / asset-fusion) is confirmed by the content type returned in Step 2, and finalized in Step 3.\n2. Write a draft `shot-plan.json` (envelope + chosen form category _or_ search intent + `asset_needs` + a one-paragraph shot brief). Schema: `references/shot-plan-ir.md`.\n\nValidation: `[ -s \"$PROJECT_DIR/shot-plan.json\" ] && echo ok || echo missing`.\n\n### Step 2 — Source ◇ (Bash: media-use, conditional)\n\nIf `shot-plan.json.asset_needs` is non-empty, resolve assets (search / generate / fetch → frozen project-local paths + ledger). See `phases/source/guide.md` (wraps `media-use resolve`; the search-driven categories use the news/web/tweet/image search). If `asset_needs` is empty, **skip to Step 3**.\n\n```bash\n# illustrative — see phases/source/guide.md\n(cd \"$PROJECT_DIR\" && node <SKILL_DIR>/phases/source/resolve.mjs --plan ./shot-plan.json --out ./assets)\n```\n\nDegrade gracefully: if a search/provider is unavailable, the category falls back to asset-free (note it in `context.log`).\n\n### Step 3 — Design (subagent: Director Part 2)\n\nDispatch a subagent (prompt = `agents/director.md` Part 2 + dispatch context including the resolved `assets/index.md` if Step 2 ran + `catalog-map.md`). It designs the shot **around the available assets**: pick the catalog block(s) + the `hyperframes-animation` rules/blueprints, the layout, the motion, beats, and (for `asset-fusion`) the `element_positions` + eyedropper palette. Finalizes `shot-plan.json` (`content.block` + `content.customize` + per-category content).\n\n### Step 4 — Build (subagent: Builder, reuse-first)\n\nInclude the shared [motion principles](../hyperframes-creative/references/motion-principles.md) in the Builder's dispatch context. For `charts` and `stat`, also include [data in motion](../hyperframes-creative/references/data-in-motion.md). The Builder reads these guides before writing the timeline.\n\nDispatch a subagent. prompt = full `agents/builder.md` + dispatch context (`shot-plan.json`, `catalog-map.md`, the category's `module.md`, `references/motion-vocabulary.md`, `references/builder-contract.md`). **Reuse-first**: `npx hyperframes add <block>` + customize in place; hand-author only gaps + the asset-fusion affordance. Output `compositions/index.html` honoring the HF contract (paused GSAP timeline on `window.__timelines`, `class=\"clip\"` + stable ids, `tl.seek(0)`, deterministic).\n\n### Step 5 — Verify (Bash → repair subagent on failure)\n\n```bash\n(cd \"$PROJECT_DIR\" && npx hyperframes lint .)\n(cd \"$PROJECT_DIR\" && npx hyperframes check .)\n(cd \"$PROJECT_DIR\" && npx hyperframes snapshot --at <proof-times>)\n```\n\nChoose proof times that show the opening state, signature move, and final hold. Inspect the generated contact or snapshot sheet before continuing. On `lint`, `check`, or snapshot failure, dispatch the repair subagent (`agents/finalize.md`) for one in-place fix pass, then rerun the failed gate. Never change a fixed duration merely to hide a defect.\n\n### Step 6 — Approve and render (Bash)\n\nOpen Studio, then ask one question: “render now, or what changes?” After revisions, return to the same gate:\n\n```bash\n(cd \"$PROJECT_DIR\" && npx hyperframes preview --background)\n```\n\nRender only after an explicit render answer:\n\n```bash\n(cd \"$PROJECT_DIR\" && npx hyperframes render . --skill=motion-graphics -q high -o ./renders/video.mp4)\n# transparent overlay variant: --format webm  (or mov)\n```\n\nVerify the output exists, is non-empty, and has the intended duration. The final handoff names the artifact, actual duration, composition or frame id, proof times, and the inspected contact or snapshot sheet. Flags live in `/hyperframes-cli` → `references/preview-render.md`.\n\n## Resume table\n\n| State                                                    | Continue from              |\n| -------------------------------------------------------- | -------------------------- |\n| no `shot-plan.json`                                      | Step 1 (plan)              |\n| `shot-plan.json` has `asset_needs`, no `assets/`         | Step 2 (source)            |\n| `shot-plan.json` final, no `compositions/index.html`     | Step 3/4 (design+build)    |\n| `compositions/index.html` exists, proof snapshots absent | Step 5 (verify)            |\n| checks and proof snapshots pass, no approved render      | Step 6 (approval)          |\n| approved render exists                                   | verify output, then report |\n\n## Design notes (maintainers — execution does not read this)\n\n- **Asset-first rationale:** sourcing is front-loaded and informs shot design (the RWA flow: analyze → search → review → compose). the search-driven categories (`webpage`/`news`/`tweet`) and `asset-fusion` both lean on media-use search (news/web/tweet/image), which is media-use's documented RWA lineage.\n- **Reuse-first:** the in-ecosystem analog of LLM-generated templates is \"compose catalog blocks + `hyperframes-animation` rules\". HF's paused GSAP timeline ≙ Remotion's `useCurrentFrame`.\n- **Category module contract:** one `categories/<id>/module.md` (planning + build), sharing `references/motion-vocabulary.md` (+ optional eval). Adding a category = drop the folder + register its classifier line in `agents/director.md` + its row in `catalog-map.md`; the phase pipeline is untouched.\n- **Directory shape:**\n  ```\n  videos/<project-name>/\n    hyperframes.json  context.log\n    shot-plan.json            # the IR (Director output)\n    assets/  assets/index.md  # media-use output (if sourced)\n    compositions/index.html   # Builder output\n    renders/video.mp4\n  ```\n- **Registration:** in `hyperframes` router — add the \"design-led short motion graphic\" intent + Workflow description; carve the motion-graphics triggers out of `/general-video`; add reverse Do-NOT-use edges. See `motion-graphics-genre.md` §5-7.\n\nFile v1.0.22:_meta.json\n\n{\n  \"ownerId\": \"kn77d06grj6xqp3dqwkk4bavhn89pegt\",\n  \"slug\": \"motion-graphics\",\n  \"version\": \"1.0.22\",\n  \"publishedAt\": 1791119314905\n}\n\nFile v1.0.22:references/builder-contract.md\n\n# Builder contract — composition rules (detail behind agents/builder.md)\n\n## Root must be sized\n\nRoot `#stage` (`data-composition-id`) needs `position: relative; width: <W>px; height: <H>px`. Without a resolved height, flex children collapse to ~0 and content piles into the top-left. Automated gates may miss it, so inspect proof snapshots.\n\n## Layout before animation\n\n1. Identify the **hero frame** (the moment most elements are visible) → build THAT in static CSS first, no GSAP.\n2. `.scene-content` fills the scene with padding, not offsets:\n   ```css\n   display: flex;\n   flex-direction: column;\n   justify-content: center;\n   width: 100%;\n   height: 100%;\n   padding: 120px 160px;\n   gap: 24px;\n   box-sizing: border-box;\n   ```\n   Never `position:absolute; top:Npx` on a content container (it overflows). Reserve absolute for decoratives. Keep ≥80px padding (title-safe margin).\n3. **Entrances**: use `gsap.from()` only for a non-clip element active from `t=0`. Inside `.clip`, in sub-compositions, and for later entrances, use explicit `fromTo()`. The CSS position is ground truth; the tween is the journey to it.\n4. **Exits**: only the final scene animates elements out; between scenes the transition IS the exit.\n\n## Timeline / clip contract\n\n- ONE `gsap.timeline({paused:true})` on `window.__timelines[\"<id>\"]`; `tl.seek(0)`; never `tl.play()`.\n- Timed elements: `class=\"clip\"` + `data-start`/`data-duration`/`data-track-index` + a stable `id`. Timeline-driven groups inside one full-duration clip don't each need timing attrs.\n- Deterministic only — no `Date.now()` / `Math.random()` / network. Count-ups tween a proxy object via `onUpdate` (seek-safe), never a wall-clock counter.\n\n## Correctness\n\n- **Seek-safe reveal of delayed elements**: on a non-clip element or wrapper inside a clip, use one registered timeline `fromTo()` with an explicit `{ autoAlpha: 0 }` start and `{ autoAlpha: 1, ... }` end. Do not page-load `gsap.set()` a later `.clip`, and never target `.clip` visibility; the framework owns its lifecycle. _(Eval finding.)_\n- **Count-ups** tween a proxy via `onUpdate`; they only render when the host advances the timeline **with events enabled** (`tl.time()` / non-suppressed seek). A bare `seek(t, true)` freezes them at 0 — the HF render host must seek with events on. _(Eval finding.)_\n- Clamp at tween bounds; don't let a spring overshoot past a held value.\n- Allowed eases: `power1–4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine` (`.in/.out/.inOut`).\n- One motif per scene. Run `hyperframes check`; mark intentional overflow `data-layout-allow-overflow=\"true\"`.\n- **Palette discipline**: define all colors in one `palette` object / CSS custom properties — no inline hex scattered through the markup (for `asset-fusion`, eyedropper the palette from the asset).\n\nFile v1.0.22:references/motion-vocabulary.md\n\n# text module · motion vocabulary (primitive → GSAP)\n\n<!-- registry-items: allow= -->\n\n**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 \"<what you want>\" --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`.\n\nNamed primitives the Director references in `motion` strings and the Builder implements. `code_hint`s are framework-neutral physics; the GSAP recipe is the HF implementation. Prefer an HF **registry component** (bottom) when one fits — don't reinvent.\n\n## Entry\n\n| primitive                     | GSAP recipe (into CSS end-state)                               | suits                     |\n| ----------------------------- | -------------------------------------------------------------- | ------------------------- |\n| `slide_bottom/top/left/right` | `from({ y:±150 / x:±200, opacity:0, ease:\"power4.out\" })`      | calm, build, professional |\n| `scale_grow`                  | `from({ scale:0, opacity:0, duration:.6, ease:\"power2.out\" })` | calm, gentle              |\n| `scale_punch`                 | `from({ scale:.6, opacity:0, ease:\"back.out(2.2)\" })`          | impact, energetic         |\n| `fade_in`                     | `from({ opacity:0, duration:.4 })`                             | subtle                    |\n| `fade_blur`                   | `from({ opacity:0, filter:\"blur(14px)\" })`                     | cinematic, dreamy         |\n| `typewriter`                  | reveal via clip/`SplitText` width step                         | technical, narrative      |\n| `word_reveal`                 | per-word `from({opacity:0,y:..}, stagger:.1)`                  | storytelling              |\n| `wave`                        | per-letter `from({y:..}, stagger:{each:.04})`                  | flowing, musical          |\n| `bounce_in`                   | `from({y:-120}, ease:\"bounce.out\")`                            | playful                   |\n| `slam`                        | `from({ y:-300, ease:\"power4.out\" })` + shake on land          | impact, heavy             |\n\n## Emphasis (in place, often on a beat)\n\n| primitive     | GSAP recipe                                                          | suits              |\n| ------------- | -------------------------------------------------------------------- | ------------------ |\n| `scale_pulse` | `to({ scale:1.12, yoyo:true, repeat:1, ease:\"sine.inOut\" })` at beat | rhythmic, peak     |\n| `shake`       | `to({ keyframes:[{x:-9},{x:9},{x:0}], ease:\"none\" })`                | urgent, intense    |\n| `glow`        | `to({ textShadow:\"0 0 46px <ink/accent>\", yoyo:true, repeat:1 })`    | important, magical |\n| `color_shift` | `to({ color:\"<accent>\" })` (or accent on the word in CSS)            | dynamic            |\n\n## Exit\n\n| primitive   | GSAP recipe                                        | suits      |\n| ----------- | -------------------------------------------------- | ---------- |\n| `fade_out`  | `to({ opacity:0, duration:.4, ease:\"power2.in\" })` | ending     |\n| `slide_out` | `to({ y/x: off, opacity:0, ease:\"power2.in\" })`    | transition |\n| `scale_out` | `to({ scale:1.06, opacity:0, ease:\"power2.in\" })`  | transition |\n\n## Accent graphics (not text)\n\n`underline_sweep` `fromTo({scaleX:0},{scaleX:1}, transformOrigin:\"left center\")` · `bar_wipe` · `hold_breath` `to({scale:1.015, ease:\"sine.inOut\"})`.\n\n## Prefer HF registry components when they fit\n\n`caption-kinetic-slam` · `caption-editorial-emphasis` · `caption-neon-glow` · `caption-glitch-rgb` · `caption-particle-burst` · `caption-weight-shift` · `caption-matrix-decode` · `caption-pill-karaoke` · `shimmer-sweep`. These are pre-built, in-ecosystem, and already render-tested — the Builder should reach for them before hand-rolling an equivalent.\n\nFile v1.0.22:references/shot-plan-ir.md\n\n# shot-plan IR\n\nThe single contract between Director and Builder. One file: `PROJECT_DIR/shot-plan.json`.\n\n```jsonc\n{\n  // ── envelope (every category) ──\n  \"category\": \"kinetic-type | stat | charts | logo-reveal | lower-thirds | webpage | news | tweet | asset-fusion\",\n  \"duration_s\": 6,\n  \"fps\": 30,\n  \"canvas\": { \"w\": 1080, \"h\": 1920, \"aspect\": \"9:16\" },\n  \"style\": \"free-form visual direction (mood / energy / reference)\",\n  \"palette\": [\"#…\"], // or \"derive-from-asset\"\n  \"font\": \"<HF embed-list font>\",\n  \"beats\": [12, 37], // optional accent frames/seconds\n  \"export\": \"mp4\", // or \"alpha-overlay\" (transparent webm/mov)\n\n  // ── sourcing seam (Director Part 1) — [] means skip the source phase ──\n  \"asset_needs\": [\n    {\n      \"role\": \"hero\",\n      \"kind\": \"image|icon|logo|svg|news|web|tweet\",\n      \"query\": \"…\",\n      \"source\": \"…\",\n      \"treatment\": \"cutout|recolor|vectorize|none\",\n    },\n  ],\n\n  // ── build directive (Director Part 2, reuse-first) ──\n  \"block\": \"<catalog block id, e.g. data-chart | caption-kinetic-slam>\", // optional\n  \"customize\": {\n    /* what to change on the block: data, text, palette, positions */\n  },\n\n  // ── category-specific content ──\n  \"content\": {\n    /* shape varies by category, below */\n  },\n}\n```\n\n**Per-category `content` shapes:**\n\n- `kinetic-type` → `scenes[]` `{ id, start, end, text, emphasis_words[], emotion, motion, beats[] }`\n- `stat` → `{ value, prefix, suffix, label, ring: bool }`\n- `charts` → `{ type: bar|line|pie|race|pct, data[], labels[], headline, axes: bool }`\n- `logo-reveal` → `{ logo: <asset path>, tagline, url }`\n- `lower-thirds` → `{ name, role, position, brand_colors[] }`\n- `webpage` → `{ url, capture, highlights: [ { selector|region, label } ] }` (step-highlight a real captured page)\n- `news` → `{ outlet, headline, body, keyword, layout: A|B, logo?, date?, subject? }` (article-highlight: lay text out readable — **no zoom** — then sweep a marker band over the keyword in place. Layout **A** = centered-emphasis 9:16 text-only; **B** = full article 16:9 with `logo` + `date` + `subject` (a person photo → `remove-background` cutout))\n- `tweet` → `{ author, handle, avatar, text, metrics }`\n- `asset-fusion` → `{ data_type, asset: <path>, affordance, element_positions: {center, extent, safe[], avoid[]}, derived_palette[], connectors[] }`\n\n**Invariants:** `scenes` (if present) partition `[0, duration_s]` with no gaps/overlaps · empty `asset_needs` ⇒ Step 2 (source) is skipped · a named `block` ⇒ the Builder reuses + customizes it rather than hand-authoring.\n\nFile v1.0.22:agents/builder.md\n\n# Motion-Graphics Builder\n\nTurn `shot-plan.json` into one renderable HyperFrames composition (`compositions/index.html`). Everything stays in the HF ecosystem — HTML is the source of truth; a single **paused** GSAP timeline carries all motion; the engine seeks it. Category-specific build rules live in `categories/<id>/module.md`; this file is the shared contract.\n\n## Reuse-first (the default)\n\nDefault = **compose existing catalog capabilities, not hand-author**:\n\n- **Search first, for every named effect** — `npx hyperframes catalog --query \"<the move, in plain English>\" --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`.\n- `npx hyperframes add <block>` (registry) → customize in place. Most blocks bake content/data into their own script (only a few expose CSS-var params), so reuse = **add + edit**.\n- `hyperframes-animation` rules / blueprints / transitions for motion; runtime adapters (GSAP default).\n\nHand-author only (a) gaps no block/rule covers, (b) the `asset-fusion` affordance binding. The Director named the block(s) + customizations in `shot-plan.json` (`content.block` + `content.customize`); see `catalog-map.md`.\n\n## The HF contract (non-negotiable)\n\n- Root `#stage` carries `data-composition-id`, `data-start=\"0\"`, `data-duration=<s>`, `data-fps`, `data-width`, `data-height`.\n- Exactly ONE `gsap.timeline({ paused:true })`; register `window.__timelines[\"<id>\"] = tl;`; end with `tl.seek(0)`. **Never `tl.play()`** for render-critical motion. No timers / async / event-driven timeline build. Finite repeats only.\n- **Timed clips** need `class=\"clip\"` + a stable `id`. Timeline-driven groups inside one full-duration clip don't each need timing attrs.\n- **Fonts**: prefer local `@font-face` (.woff2) for deterministic / offline render; CDN Google Fonts do render (compiler caches + injects `@font-face`) but warn + need network.\n- **Deterministic only** — no `Date.now()` / `Math.random()` / network.\n\n## Layout before animation\n\nBuild the **hero-frame end-state** in CSS first (flex + padding; never absolute offsets on content containers; the root must be sized). Use `fromTo()` for elements inside `.clip` and for any delayed entrance; `from()` is safe only for non-clip elements active from `t=0`. Exits belong to transitions or the final scene. Full rules: `references/builder-contract.md`.\n\n## IR → composition\n\n- `content.block` → `hyperframes add` it (or inline) + apply `content.customize`.\n- per-category `content` (text scenes / chart data / fusion positions / news-tweet content) → realize per `categories/<id>/module.md`.\n- resolved `asset_needs` → reference **frozen project-local paths** (never a remote URL or a prompt).\n- `palette[-1]` / bg + `font` from the envelope.\n- `export: alpha-overlay` → transparent bg; render `--format webm` (or `mov`).\n\n## Critical correctness (GSAP / seek)\n\nOpacity-gate delayed elements (set hidden until their entrance). Clamp at tween bounds (no overshoot past a held value). Allowed eases: `power1–4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine` (`.in/.out/.inOut`). One motif per scene. Run `hyperframes check` for overflow / collisions.\n\n## Motion quality\n\nBefore writing the timeline, read and follow the shared [motion principles](../../hyperframes-creative/references/motion-principles.md). For `charts` and `stat`, also read [data in motion](../../hyperframes-creative/references/data-in-motion.md) before laying out or animating the data.\n\n## Hand off for verification\n\nSelf-check the authored file, then return it to the orchestrator. Step 5 runs `hyperframes lint`, `hyperframes check`, and proof snapshots on the assembled project. Do not render. When redispatched with a finding, fix the offending element and never change a fixed `data-duration` during repair. Remotion-source migrations use `/remotion-to-hyperframes` and its SSIM harness instead.\n\nFile v1.0.22:agents/director.md\n\n# Motion-Graphics Director\n\nTurn a request into a `shot-plan.json` for a short (~3–30s) **design-led motion graphic**. You run in **two parts** around the asset-sourcing step: **Part 1 (plan)** before sourcing, **Part 2 (design)** after. You do NOT write composition code — that's the Builder. Schema: `references/shot-plan-ir.md`.\n\n## Part 1 — Plan (before sourcing)\n\nEmit a DRAFT `shot-plan.json`.\n\n0. **Decide first: does this need a search?** No → a **form category** (user supplies content). Yes → emit a search plan; the specific **search-driven category** (`webpage` / `news` / `tweet` / `asset-fusion`) is confirmed by what the search returns (Step 2 → finalized in Part 2).\n\n1. **Classify** — form categories by intent below; search-driven categories are picked post-search:\n\n   | Category       | Pick when…                                                                                                                                                                         |\n   | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n   | `kinetic-type` | a punchy line / quote / title; text is the hero                                            \n\nArchive v1.0.21: 25 files, 55863 bytes\n\nFiles: agents/builder.md (4071b), agents/director.md (6078b), agents/finalize.md (1071b), catalog-map.md (10641b), categories/asset-fusion/module.md (3968b), categories/charts/module.md (1982b), categories/kinetic-type/module.md (1607b), categories/logo-reveal/module.md (1131b), categories/lower-thirds/module.md (1493b), categories/maps/bake-basemap.mjs (14726b), categories/maps/module.md (9587b), categories/news/module.md (5425b), categories/stat/module.md (1330b), categories/tweet/module.md (1015b), categories/webpage/module.md (2538b), grounding/locate.mjs (8236b), grounding/PROTOCOL.md (3108b), phases/source/guide.md (1962b), references/builder-contract.md (2818b), references/motion-vocabulary.md (3978b), references/shot-plan-ir.md (2616b), samples/asset-fusion/_ref-circle-highlight.html (10674b), skill-card.md (2055b), SKILL.md (16217b), _meta.json (135b)\n\nArchive v1.0.20: 25 files, 55443 bytes\n\nFiles: agents/builder.md (3764b), agents/director.md (6078b), agents/finalize.md (1071b), catalog-map.md (10641b), categories/asset-fusion/module.md (3968b), categories/charts/module.md (1769b), categories/kinetic-type/module.md (1607b), categories/logo-reveal/module.md (1131b), categories/lower-thirds/module.md (1493b), categories/maps/bake-basemap.mjs (14726b), categories/maps/module.md (9587b), categories/news/module.md (5425b), categories/stat/module.md (1200b), categories/tweet/module.md (1015b), categories/webpage/module.md (2538b), grounding/locate.mjs (8236b), grounding/PROTOCOL.md (3108b), phases/source/guide.md (1962b), references/builder-contract.md (2818b), references/motion-vocabulary.md (3978b), references/shot-plan-ir.md (2616b), samples/asset-fusion/_ref-circle-highlight.html (10674b), skill-card.md (2068b), SKILL.md (15915b), _meta.json (135b)\n\nArchive v1.0.19: 25 files, 55693 bytes\n\nFiles: agents/builder.md (3764b), agents/director.md (6078b), agents/finalize.md (1071b), catalog-map.md (10641b), categories/asset-fusion/module.md (3968b), categories/charts/module.md (1769b), categories/kinetic-type/module.md (1607b), categories/logo-reveal/module.md (1131b), categories/lower-thirds/module.md (1493b), categories/maps/bake-basemap.mjs (14726b), categories/maps/module.md (9587b), categories/news/module.md (5425b), categories/stat/module.md (1200b), categories/tweet/module.md (1015b), categories/webpage/module.md (2538b), grounding/locate.mjs (8236b), grounding/PROTOCOL.md (3108b), phases/source/guide.md (1962b), references/builder-contract.md (2818b), references/motion-vocabulary.md (3978b), references/shot-plan-ir.md (2616b), samples/asset-fusion/_ref-circle-highlight.html (10674b), skill-card.md (2863b), SKILL.md (15671b), _meta.json (135b)\n\nArchive v1.0.18: 25 files, 55655 bytes\n\nFiles: agents/builder.md (3764b), agents/director.md (6078b), agents/finalize.md (1071b), catalog-map.md (10641b), categories/asset-fusion/module.md (3968b), categories/charts/module.md (1769b), categories/kinetic-type/module.md (1607b), categories/logo-reveal/module.md (1131b), categories/lower-thirds/module.md (1493b), categories/maps/bake-basemap.mjs (14726b), categories/maps/module.md (9587b), categories/news/module.md (5404b), categories/stat/module.md (1200b), categories/tweet/module.md (1015b), categories/webpage/module.md (2538b), grounding/locate.mjs (8236b), grounding/PROTOCOL.md (3108b), phases/source/guide.md (1962b), references/builder-contract.md (2818b), references/motion-vocabulary.md (3978b), references/shot-plan-ir.md (2616b), samples/asset-fusion/_ref-circle-highlight.html (10674b), skill-card.md (2755b), SKILL.md (15671b), _meta.json (135b)\n\nArchive v1.0.17: 25 files, 56068 bytes\n\nFiles: agents/builder.md (3764b), agents/director.md (6078b), agents/finalize.md (1071b), catalog-map.md (11808b), categories/asset-fusion/module.md (3968b), categories/charts/module.md (1769b), categories/kinetic-type/module.md (1607b), categories/logo-reveal/module.md (1131b), categories/lower-thirds/module.md (1493b), categories/maps/bake-basemap.mjs (14726b), categories/maps/module.md (9587b), categories/news/module.md (5404b), categories/stat/module.md (1200b), categories/tweet/module.md (1015b), categories/webpage/module.md (2538b), grounding/locate.mjs (8236b), grounding/PROTOCOL.md (3108b), phases/source/guide.md (1962b), references/builder-contract.md (2818b), references/motion-vocabulary.md (3978b), references/shot-plan-ir.md (2616b), samples/asset-fusion/_ref-circle-highlight.html (10674b), skill-card.md (3046b), SKILL.md (15671b), _meta.json (135b)\n\nArchive v1.0.16: 25 files, 56092 bytes\n\nFiles: agents/builder.md (3764b), agents/director.md (6078b), agents/finalize.md (1071b), catalog-map.md (11808b), categories/asset-fusion/module.md (3968b), categories/charts/module.md (1769b), categories/kinetic-type/module.md (1607b), categories/logo-reveal/module.md (1131b), categories/lower-thirds/module.md (1493b), categories/maps/bake-basemap.mjs (14726b), categories/maps/module.md (9587b), categories/news/module.md (5404b), categories/stat/module.md (1200b), categories/tweet/module.md (1015b), categories/webpage/module.md (2538b), grounding/locate.mjs (8236b), grounding/PROTOCOL.md (3108b), phases/source/guide.md (1962b), references/builder-contract.md (2818b), references/motion-vocabulary.md (3978b), references/shot-plan-ir.md (2616b), samples/asset-fusion/_ref-circle-highlight.html (10674b), skill-card.md (3131b), SKILL.md (15676b), _meta.json (135b)\n\nArchive v1.0.15: 25 files, 54405 bytes\n\nFiles: agents/builder.md (3394b), agents/director.md (5756b), agents/finalize.md (1071b), catalog-map.md (10595b), categories/asset-fusion/module.md (3968b), categories/charts/module.md (1611b), categories/kinetic-type/module.md (1607b), categories/logo-reveal/module.md (1131b), categories/lower-thirds/module.md (1081b), categories/maps/bake-basemap.mjs (14726b), categories/maps/module.md (9587b), categories/news/module.md (5404b), categories/stat/module.md (1200b), categories/tweet/module.md (1015b), categories/webpage/module.md (2538b), grounding/locate.mjs (8236b), grounding/PROTOCOL.md (3108b), phases/source/guide.md (1962b), references/builder-contract.md (2818b), references/motion-vocabulary.md (3566b), references/shot-plan-ir.md (2616b), samples/asset-fusion/_ref-circle-highlight.html (10674b), skill-card.md (2689b), SKILL.md (15676b), _meta.json (135b)","readmeExcerpt":"Skill: motion-graphics Owner: heygen-com Summary: A short, design-led motion graphic where motion is the message — kinetic typography, stat count-up, chart/data-viz hit, logo sting / brand lockup, lower-third / callout / social overlay, animated map (highlight regions, connect places, zoom to a location), animated tweet / news-article / headline, webpage / UI animation (scroll, cursor, callouts), or fusing a real ima","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"PROJECT_DIR=\"${MOTION_GRAPHICS_DIR:-videos/<project-name>}\"\nmkdir -p \"$(dirname \"$PROJECT_DIR\")\"\nnpx hyperframes init \"$PROJECT_DIR\" --non-interactive --example=blank --skill=motion-graphics"},{"language":"bash","snippet":"(cd \"$PROJECT_DIR\" && npx hyperframes check .)\n(cd \"$PROJECT_DIR\" && npx hyperframes snapshot --at <proof-times>)"},{"language":"bash","snippet":"(cd \"$PROJECT_DIR\" && npx hyperframes preview --background)"},{"language":"bash","snippet":"(cd \"$PROJECT_DIR\" && npx hyperframes render . --skill=motion-graphics -q high -o ./renders/video.mp4)\n# transparent overlay variant: --format webm  (or mov)"},{"language":"text","snippet":"videos/<project-name>/\n    hyperframes.json  context.log\n    shot-plan.json            # the IR (Director output)\n    assets/  assets/index.md  # media-use output (if sourced)\n    compositions/index.html   # Builder output\n    renders/video.mp4"},{"language":"css","snippet":"display: flex;\n   flex-direction: column;\n   justify-content: center;\n   width: 100%;\n   height: 100%;\n   padding: 120px 160px;\n   gap: 24px;\n   box-sizing: border-box;"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: motion-graphics\ndescription: >\n  A short, design-led motion graphic where motion is the message — kinetic\n  typography, stat count-up, chart/data-viz hit, logo sting / brand lockup,\n  lower-third / callout / social overlay, animated map (highlight regions,\n  connect places, zoom to a location), animated tweet / news-article /\n  headline, webpage / UI animation (scroll, cursor, callouts), or fusing a\n  real image's geometry into a chart. Usually under 10s (up to ~30s), no\n  narration or live-action subject; renders to MP4 or transparent overlay.\n  Longer / narrated / multi-scene → /general-video. Unclear → /hyperframes.\n---\n\n**Plugin installs:** Before setup or freshness commands, follow [plugin execution rules](../hyperframes/references/plugin-installation.md) when this skill is inside a HyperFrames plugin. Standalone installs keep the update instructions below.\n\n> **First, keep this skill fresh — confirm with the user before running:** `npx hyperframes skills update motion-graphics`. A fast no-op when everything is current; otherwise it refreshes this skill plus the core domain skills it depends on before you rely on them.\n\n> **figma source**: If the logo/asset/animation to build from comes from a figma.com URL, run `/figma` first — asset export, brand tokens, and Motion→GSAP translation if the graphic is a Figma Motion import — then build from its output. Don't drive Figma via raw MCP tools directly: that skips SVG sanitization, `.media/manifest.jsonl` provenance, and brand-token `var()` binding, so a later brand change can't propagate without a full re-import.\n\n# motion-graphics — dispatch entry\n\n> **The front door is `/hyperframes`.** This skill makes a **short, design-led, unnarrated motion graphic** (motion is the message; ~under 10s, no voice-over). Anything longer, narrated, or multi-scene — or any uncertainty → read `/hyperframes` first: the intent layer owns every route decision.\n\nThis workflow is **autonomous by design** — at most one clarifying question (`agents/director.md`), then build through verification without intermediate review. The intent layer (`/hyperframes` → `references/intent-interview.md`) routes here directly without run-shape questions; a storyboard and companion session add little to a piece this short. Rendering is still user-gated: after checks and proof snapshots pass, open the Studio preview and ask the canonical “render now, or what changes?” question from `../hyperframes/references/brief-contract.md`. When a `BRIEF.md` exists, read it before the director's question.\n\nA short design-led motion graphic. **Asset-first**: decide the asset strategy and source real material _before_ designing the shot, then design the shot around what you have, then compose by reusing catalog capabilities. All artifacts go to `PROJECT_DIR = videos/<project-name>/` (created in Step 0); all paths below are relative to it.\n\n| Phase    | Execution                                                             | Primary artifact   "},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn77d06grj6xqp3dqwkk4bavhn89pegt\",\n  \"slug\": \"motion-graphics\",\n  \"version\": \"1.0.24\",\n  \"publishedAt\": 1791142299200\n}"},{"path":"references/builder-contract.md","content":"# Builder contract — composition rules (detail behind agents/builder.md)\n\n## Root must be sized\n\nRoot `#stage` (`data-composition-id`) needs `position: relative; width: <W>px; height: <H>px`. Without a resolved height, flex children collapse to ~0 and content piles into the top-left. Automated gates may miss it, so inspect proof snapshots.\n\n## Layout before animation\n\n1. Identify the **hero frame** (the moment most elements are visible) → build THAT in static CSS first, no GSAP.\n2. `.scene-content` fills the scene with padding, not offsets:\n   ```css\n   display: flex;\n   flex-direction: column;\n   justify-content: center;\n   width: 100%;\n   height: 100%;\n   padding: 120px 160px;\n   gap: 24px;\n   box-sizing: border-box;\n   ```\n   Never `position:absolute; top:Npx` on a content container (it overflows). Reserve absolute for decoratives. Keep ≥80px padding (title-safe margin).\n3. **Entrances**: use `gsap.from()` only for a non-clip element active from `t=0`. Inside `.clip`, in sub-compositions, and for later entrances, use explicit `fromTo()`. The CSS position is ground truth; the tween is the journey to it.\n4. **Exits**: only the final scene animates elements out; between scenes the transition IS the exit.\n\n## Timeline / clip contract\n\n- ONE `gsap.timeline({paused:true})` on `window.__timelines[\"<id>\"]`; `tl.seek(0)`; never `tl.play()`.\n- Timed elements: `class=\"clip\"` + `data-start`/`data-duration`/`data-track-index` + a stable `id`. Timeline-driven groups inside one full-duration clip don't each need timing attrs.\n- Deterministic only — no `Date.now()` / `Math.random()` / network. Count-ups tween a proxy object via `onUpdate` (seek-safe), never a wall-clock counter.\n\n## Correctness\n\n- **Seek-safe reveal of delayed elements**: on a non-clip element or wrapper inside a clip, use one registered timeline `fromTo()` with an explicit `{ autoAlpha: 0 }` start and `{ autoAlpha: 1, ... }` end. Do not page-load `gsap.set()` a later `.clip`, and never target `.clip` visibility; the framework owns its lifecycle. _(Eval finding.)_\n- **Count-ups** tween a proxy via `onUpdate`; they only render when the host advances the timeline **with events enabled** (`tl.time()` / non-suppressed seek). A bare `seek(t, true)` freezes them at 0 — the HF render host must seek with events on. _(Eval finding.)_\n- Clamp at tween bounds; don't let a spring overshoot past a held value.\n- Allowed eases: `power1–4`, `back`, `bounce`, `circ`, `elastic`, `expo`, `sine` (`.in/.out/.inOut`).\n- One motif per scene. Run `hyperframes check`; mark intentional overflow `data-layout-allow-overflow=\"true\"`.\n- **Palette discipline**: define all colors in one `palette` object / CSS custom properties — no inline hex scattered through the markup (for `asset-fusion`, eyedropper the palette from the asset)."},{"path":"references/motion-vocabulary.md","content":"# text module · motion vocabulary (primitive → GSAP)\n\n<!-- registry-items: allow= -->\n\n**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 \"<what you want>\" --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`.\n\nNamed primitives the Director references in `motion` strings and the Builder implements. `code_hint`s are framework-neutral physics; the GSAP recipe is the HF implementation. Prefer an HF **registry component** (bottom) when one fits — don't reinvent.\n\n## Entry\n\n| primitive                     | GSAP recipe (into CSS end-state)                               | suits                     |\n| ----------------------------- | -------------------------------------------------------------- | ------------------------- |\n| `slide_bottom/top/left/right` | `from({ y:±150 / x:±200, opacity:0, ease:\"power4.out\" })`      | calm, build, professional |\n| `scale_grow`                  | `from({ scale:0, opacity:0, duration:.6, ease:\"power2.out\" })` | calm, gentle              |\n| `scale_punch`                 | `from({ scale:.6, opacity:0, ease:\"back.out(2.2)\" })`          | impact, energetic         |\n| `fade_in`                     | `from({ opacity:0, duration:.4 })`                             | subtle                    |\n| `fade_blur`                   | `from({ opacity:0, filter:\"blur(14px)\" })`                     | cinematic, dreamy         |\n| `typewriter`                  | reveal via clip/`SplitText` width step                         | technical, narrative      |\n| `word_reveal`                 | per-word `from({opacity:0,y:..}, stagger:.1)`                  | storytelling              |\n| `wave`                        | per-letter `from({y:..}, stagger:{each:.04})`                  | flowing, musical          |\n| `bounce_in`                   | `from({y:-120}, ease:\"bounce.out\")`                            | playful                   |\n| `slam`                        | `from({ y:-300, ease:\"power4.out\" })` + shake on land          | impact, heavy             |\n\n## Emphasis (in place, often on a beat)\n\n| primitive     | GSAP recipe                                                          | suits              |\n| ------------- | -------------------------------------------------------------------- | ------------------ |\n| `scale_pulse` | `to({ scale:1.12, yoyo:true, repeat:1, ease:\"sine.inOut\" })` at beat | rhythmic, peak     |\n| `shake`       | `to({ keyframes:[{x:-9},{x:9},{x:0}], ease:\"none\" })`                | urgent, intense    |\n| `glow`        | `to({ textShadow:\"0 0 46px <ink/accent>\", yoyo:true, repeat:1 })`    | important, magical |\n| `color_shift` | `to({ color:\"<accent>\" })` (or accent on the word in CSS)            | dynamic            |\n\n## Exit\n\n| primitive   | GSAP recipe            "},{"path":"references/shot-plan-ir.md","content":"# shot-plan IR\n\nThe single contract between Director and Builder. One file: `PROJECT_DIR/shot-plan.json`.\n\n```jsonc\n{\n  // ── envelope (every category) ──\n  \"category\": \"kinetic-type | stat | charts | logo-reveal | lower-thirds | webpage | news | tweet | asset-fusion\",\n  \"duration_s\": 6,\n  \"fps\": 30,\n  \"canvas\": { \"w\": 1080, \"h\": 1920, \"aspect\": \"9:16\" },\n  \"style\": \"free-form visual direction (mood / energy / reference)\",\n  \"palette\": [\"#…\"], // or \"derive-from-asset\"\n  \"font\": \"<HF embed-list font>\",\n  \"beats\": [12, 37], // optional accent frames/seconds\n  \"export\": \"mp4\", // or \"alpha-overlay\" (transparent webm/mov)\n\n  // ── sourcing seam (Director Part 1) — [] means skip the source phase ──\n  \"asset_needs\": [\n    {\n      \"role\": \"hero\",\n      \"kind\": \"image|icon|logo|svg|news|web|tweet\",\n      \"query\": \"…\",\n      \"source\": \"…\",\n      \"treatment\": \"cutout|recolor|vectorize|none\",\n    },\n  ],\n\n  // ── build directive (Director Part 2, reuse-first) ──\n  \"block\": \"<catalog block id, e.g. data-chart | caption-kinetic-slam>\", // optional\n  \"customize\": {\n    /* what to change on the block: data, text, palette, positions */\n  },\n\n  // ── category-specific content ──\n  \"content\": {\n    /* shape varies by category, below */\n  },\n}\n```\n\n**Per-category `content` shapes:**\n\n- `kinetic-type` → `scenes[]` `{ id, start, end, text, emphasis_words[], emotion, motion, beats[] }`\n- `stat` → `{ value, prefix, suffix, label, ring: bool }`\n- `charts` → `{ type: bar|line|pie|race|pct, data[], labels[], headline, axes: bool }`\n- `logo-reveal` → `{ logo: <asset path>, tagline, url }`\n- `lower-thirds` → `{ name, role, position, brand_colors[] }`\n- `webpage` → `{ url, capture, highlights: [ { selector|region, label } ] }` (step-highlight a real captured page)\n- `news` → `{ outlet, headline, body, keyword, layout: A|B, logo?, date?, subject? }` (article-highlight: lay text out readable — **no zoom** — then sweep a marker band over the keyword in place. Layout **A** = centered-emphasis 9:16 text-only; **B** = full article 16:9 with `logo` + `date` + `subject` (a person photo → `remove-background` cutout))\n- `tweet` → `{ author, handle, avatar, text, metrics }`\n- `asset-fusion` → `{ data_type, asset: <path>, affordance, element_positions: {center, extent, safe[], avoid[]}, derived_palette[], connectors[] }`\n\n**Invariants:** `scenes` (if present) partition `[0, duration_s]` with no gaps/overlaps · empty `asset_needs` ⇒ Step 2 (source) is skipped · a named `block` ⇒ the Builder reuses + customizes it rather than hand-authoring."}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"A short, design-led motion graphic where motion is the message — kinetic typography, stat count-up, chart/data-viz hit, logo sting / brand lockup, lower-third / callout / social overlay, animated map (highlight regions, connect places, zoom to a location), animated tweet / news-article / headline, webpage / UI animation (scroll, cursor, callouts), or fusing a real image's geometry into a chart. Usually under 10s (up to ~30s), no narration or live-action subject; renders to MP4 or transparent overlay. Longer / narrated / multi-scene → /general-video. Unclear → /hyperframes. Skill: motion-graphics Owner: heygen-com Summary: A short, design-led motion graphic where motion is the message — kinetic typography, stat count-up, chart/data-viz hit, logo sting / brand lockup, lower-third / callout / social overlay, animated map (highlight regions, connect places, zoom to a location), animated tweet / news-article / headline, webpage / UI animation (scroll, cursor, callouts), or fusing a real ima","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1718,"uniquenessScore":53,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T13:21:17.706Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T13:21:17.706Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T23:09:08.369Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}