--- title: Contributing to the Catalog description: How to add blocks and components to the HyperFrames registry. --- Your agent already knows how to build video components. It writes HTML. HyperFrames renders it. The registry is the collection of everything that's been built — 113 blocks and 25 components. This guide shows you how to add to it. **Quick version** — Fork the repo. Write one HTML file with a paused GSAP timeline. Add `registry-item.json`. Run `hyperframes lint` + `hyperframes check`. Publish with `npx hyperframes publish`. Open a PR. ## Why Contribute? Every block in the registry exists because someone needed it and built it. When you add a block, every HyperFrames user gets it with one command: ```bash npx hyperframes add instagram-follow ``` The registry grows, HyperFrames gets more useful, and your work ships to everyone. ## Two Paths ### Ideas (No Code) You spot visual trends before anyone. That's the most valuable contribution. - Screen-record a caption style from TikTok/YouTube that doesn't exist yet - Sketch a lower-third in Figma with fonts, colors, and timing - Install a component, preview it, report what feels off Open an issue on [GitHub](https://github.com/heygen-com/hyperframes/issues) with a visual reference. Tag it `component-request`. The bar for ideas is low. We'd rather have 100 and build the best 10. ### Build It Every block is a single HTML file. No build step, no framework. If you use Claude Code with HyperFrames skills: > "I want to contribute a new transition that looks like \[description\]" The `/hyperframes-registry` skill scaffolds the structure, validates, renders a preview, publishes to [hyperframes.dev](https://hyperframes.dev), and prepares the PR. ## What Goes in the Registry **Blocks** (`registry/blocks/`) — full standalone compositions. Fixed dimensions, fixed duration. Caption styles, VFX effects, title cards, transitions. **Components** (`registry/components/`) — reusable snippets. No fixed size. CSS effects, text treatments, overlays that adapt to any composition. ### Structure A block is two files. A component is three, because it also ships the demo the catalog renders it inside. ``` registry/blocks/my-block/ my-block.html ← the composition registry-item.json ← metadata registry/components/my-effect/ my-effect.html ← the snippet demo.html ← the composition the catalog previews it in registry-item.json ← metadata ``` `demo.html` is required for components. Preview generation skips any component without one, which fails the catalog CI job for your item. ### registry-item.json ```json { "$schema": "https://hyperframes.heygen.com/schema/registry-item.json", "name": "my-block", "type": "hyperframes:block", "title": "My Block", "description": "What this block does in one sentence", "tags": ["category", "subcategory"], "dimensions": { "width": 1920, "height": 1080 }, "duration": 5, "params": [ { "key": "--accent", "label": "Accent", "type": "color", "default": "#ff4d4d" } ], "files": [ { "path": "my-block.html", "target": "compositions/my-block.html", "type": "hyperframes:composition" } ] } ``` #### Expose your block's knobs with `params` Declare `params` and Studio opens a live customization panel the moment someone adds your block. Each entry maps a label to a CSS variable your composition reads, so a user can restyle it without editing HTML. ```json "params": [ { "key": "--bg-color", "label": "Background", "type": "color", "default": "#faf9f6" }, { "key": "--headline", "label": "Headline", "type": "text", "default": "Ship it" }, { "key": "--speed", "label": "Speed", "type": "number", "default": "1", "min": 0.5, "max": 2, "step": 0.1 } ] ``` Types are `color`, `text`, `number`, and `select` (which takes an `options` array). If your block has any brand surface — a color, a headline, a logo slot — expose it as a param. A block nobody can restyle gets forked instead of reused. #### Other optional fields | Field | What it does | |-------|--------------| | `author` / `authorUrl` | Credits you on the catalog page | | `relatedSkill` | Links the catalog page to the skill that authors this kind of block | | `registryDependencies` | Other registry items installed alongside yours | | `license` | SPDX identifier, if yours differs from the repo's | | `sourcePrompt` | The prompt that produced the block, for people remixing it | | `minCliVersion` | Guards against installing into a CLI too old to run it | | `deprecated` | Marks the item superseded, with the migration note as the value | ## The Rules Five things that must be true for every registry item: No `Math.random()`, no `Date.now()`. Use seeded PRNG only. `gsap.timeline({ paused: true })`. The player controls playback. `window.__timelines["id"]` must match `data-composition-id`. Use `tl.eventCallback("onUpdate", render)` for Three.js/WebGL scenes. `tl.set(el, { opacity: 0, visibility: "hidden" }, group.end)` — no lingering text. Break any of these and renders won't be reproducible. The renderer captures every frame by seeking the timeline — if your animation depends on real time or random state, it breaks. Prefix every element ID with a 2-3 letter abbreviation of your item's name (`hz-cg-0`, `vc-canvas`). Unprefixed IDs collide when your block is used as a sub-composition. ## Quality Bar Not everything belongs in the registry. The bar is production quality. | Type | Minimum standard | |------|-----------------| | Captions | 96px+ font (64-72px for monospace), text-stroke or shadow, `window.__hyperframes.fitTextFontSize()` on every group | | VFX | Solves a problem that takes 4+ hours from scratch | | Transitions | Smoother than CSS — if opacity 0→1 works, it's not a transition | | Blocks | Would a professional use this in a client project? | ### Motion review Passing `check` isn't the same as the motion being good. Watch your rendered preview once at full speed and answer these: | Rule | Ask yourself | |------|-------------| | Key information holds still before the block ends | Does the headline or number sit motionless for at least a second after it lands, or is it still drifting at the cut? | | Speed comes from acceleration, not constant velocity | Is anything moving at a constant rate? Linear motion reads as a slide deck. | | Default one notch slower than feels right | Was there anything you couldn't read on the first watch? | | One hero per block | Count what's animating in the first second. More than one and the eye has nowhere to land. | | Light effects aren't sprayed | Count the glints and sweeps. More than one, or any that spills past a rounded corner, is a cut. | ### Common rejection reasons 1. **"Looks like a demo"** — a spinning cube is not a component 2. **"Text unreadable"** — font too small, no contrast treatment 3. **"Non-deterministic"** — `Math.random()` or `Date.now()` 4. **"Timeline not found"** — ID mismatch between HTML and JS 5. **"Breaks as sub-composition"** — element IDs collide (prefix everything) 6. **"Nothing to tune"** — a branded block with no `params` ## Workflow Fork [heygen-com/hyperframes](https://github.com/heygen-com/hyperframes) and create your block directory: ```bash mkdir -p registry/blocks/your-block ``` Create the HTML composition and `registry-item.json`. Use the templates above. For a component, add `demo.html` too. ```bash hyperframes lint hyperframes check npx oxfmt registry/blocks/your-block/*.html ``` ```bash # Add to registry index # Update registry/registry.json npx tsx scripts/generate-catalog-pages.ts ``` ```bash hyperframes render -o preview.mp4 ``` ```bash npx hyperframes publish ``` Open a PR with your [hyperframes.dev](https://hyperframes.dev) preview link. Commit your item directory, `registry/registry.json`, and the generated `docs/catalog/` page. CI renders the catalog PNG and MP4 for every block or component your PR touches, so there's nothing to attach by hand. A maintainer publishes the final catalog image before merge. ### What to write in the PR body The one-line `description` tells a reader what your block looks like. It doesn't tell them when to reach for it, which is what decides whether it gets used. Three lines in the PR body: - **When to use it** — name the moment, e.g. "second beat of a product promo, right after the hero card lands" - **Duration range** — your block has a fixed `duration`; say what range still reads correctly - **Known pitfalls** — a font that must be loaded, a background it needs contrast against, a length past which it stops working **HeyGen internal:** run `scripts/upload-docs-images.sh` to push catalog PNGs. ## What's Needed Right Now The catalog is lopsided. It has 29 transitions and 33 code blocks, and almost nothing for the moments that carry a video's shape. These gaps are sorted by the job the shot does, not by the technique it uses. | Job in the video | Blocks today | Gap | |------------------|--------------|-----| | Opening / hero reveal | 2 | The most-used moment in any promo has two options | | Outro / end card | 1 | Every video needs one | | Beat-driven cuts | 0 | Speed ramps, freeze frames, cut-on-the-beat — nothing, despite a whole music-to-video workflow | | Interaction demo | 0 | Command palette summon, type-and-filter, cursor performance, theme switch — nothing, despite HyperFrames capturing real product pages | | Data readout | 1 generic | Odometer digit roll, gauge sweep, before-and-after slider scrub | | Captions | 0 blocks | 15 caption components exist, but no ready-to-drop caption block | Four specific holes that survived the last round: | Category | Gap | Difficulty | |----------|-----|-----------| | Captions | RTL language layouts (Arabic, Hebrew) | Medium | | Data viz | Sankey / flow diagrams | Medium | | VFX | Particle system with physics (collisions, gravity) | Hard | | VFX | Product turntable with HDRI | Hard | Pick one, and your first contribution fills a hole instead of being the 30th transition.