mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-01 19:42:03 +00:00
feat(skills): hyperframes-registry skill (#261)
## What
New skill `hyperframes-registry` that teaches AI coding agents how to install and wire registry blocks and components into HyperFrames compositions.
### Skill structure
```
skills/hyperframes-registry/
SKILL.md — triggers, overview, quick reference
references/
install-locations.md — default paths, hyperframes.json config
wiring-blocks.md — iframe inclusion, data attributes, positioning
wiring-components.md — snippet merging (HTML, CSS, JS, timeline)
discovery.md — manifest reading, item fields, available items table
demo-html-pattern.md — why components ship demo.html, structure conventions
examples/
add-block.md — worked example: data-chart block install + wiring
add-component.md — worked example: shimmer-sweep component install + wiring
```
## Why
Phase B of the catalog plan (PR 10). Without this skill, agents using `hyperframes add` have to guess how to wire installed items into compositions. The skill encodes the iframe/snippet patterns so agents get it right on the first attempt.
## How
- SKILL.md frontmatter triggers on: `hyperframes add`, "block", "component", `hyperframes.json`
- References cover every step: discovery, install, wiring blocks (iframe), wiring components (snippet merge), and the demo.html convention
- Two worked examples walk through complete install-to-preview workflows
- Updated CLAUDE.md skills table + trigger rules, README.md skills table, docs/packages/cli.mdx
## Test plan
- [x] `scripts/lint-skills.ts` passes (checked 4 skill files, no issues)
- [x] `oxfmt --check` passes on all markdown files
- [x] SKILL.md frontmatter has valid `name` and `description`
- [x] All reference links in SKILL.md resolve to existing files
- [x] CLAUDE.md, README.md, and docs CLI page updated with new skill
This commit is contained in:
@@ -6,11 +6,12 @@ This repo ships skills that are installed globally via `npx hyperframes skills`
|
||||
|
||||
### Skills
|
||||
|
||||
| Skill | Invoke with | When to use |
|
||||
| ------------------- | ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **hyperframes** | `/hyperframes` | Creating or editing HTML compositions, captions/subtitles, TTS narration, audio-reactive animation, marker highlights. Composition authoring rules. |
|
||||
| **hyperframes-cli** | `/hyperframes-cli` | CLI commands: init, lint, preview, render, transcribe, tts, doctor. Use when scaffolding, validating, previewing, or rendering. |
|
||||
| **gsap** | `/gsap` | GSAP animations — tweens, timelines, easing, ScrollTrigger, plugins (Flip, Draggable, SplitText, etc.), React/Vue/Svelte, performance optimization. |
|
||||
| Skill | Invoke with | When to use |
|
||||
| ------------------------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **hyperframes** | `/hyperframes` | Creating or editing HTML compositions, captions/subtitles, TTS narration, audio-reactive animation, marker highlights. Composition authoring rules. |
|
||||
| **hyperframes-cli** | `/hyperframes-cli` | CLI commands: init, lint, preview, render, transcribe, tts, doctor. Use when scaffolding, validating, previewing, or rendering. |
|
||||
| **hyperframes-registry** | `/hyperframes-registry` | Installing and wiring registry blocks and components via `hyperframes add`. Install locations, block iframe wiring, component snippet merging, discovery. |
|
||||
| **gsap** | `/gsap` | GSAP animations — tweens, timelines, easing, ScrollTrigger, plugins (Flip, Draggable, SplitText, etc.), React/Vue/Svelte, performance optimization. |
|
||||
|
||||
### Why this matters
|
||||
|
||||
@@ -19,6 +20,7 @@ The skills encode HyperFrames-specific patterns (e.g., required `class="clip"` o
|
||||
### Rules
|
||||
|
||||
- When creating or modifying HTML compositions, captions, TTS, audio-reactive, or marker highlights → invoke `/hyperframes` BEFORE writing any code
|
||||
- When installing or wiring registry blocks/components (`hyperframes add`, `hyperframes.json`, block iframes, component snippets) → invoke `/hyperframes-registry` BEFORE writing any code
|
||||
- When writing GSAP animations (tweens, timelines, ScrollTrigger, plugins) → invoke `/gsap` BEFORE writing any code
|
||||
- After creating or editing any `.html` composition → run `npx hyperframes lint` and `npx hyperframes validate` in parallel, fix all errors before opening the studio or considering the task complete. `lint` checks the HTML structure statically; `validate` loads the composition in headless Chrome and catches runtime JS errors, missing assets, and failed network requests. Always validate before `npx hyperframes preview`.
|
||||
|
||||
|
||||
@@ -101,10 +101,10 @@ npx skills add greensock/gsap-skills
|
||||
|
||||
### Installed Skills
|
||||
|
||||
| Source | Skills | What they teach |
|
||||
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
|
||||
| **HyperFrames** | `hyperframes-compose`, `hyperframes-captions` | HTML composition structure, `class="clip"` rules, `data-*` attributes, timeline registration, rendering constraints |
|
||||
| **[GSAP](https://github.com/greensock/gsap-skills)** | `gsap-core`, `gsap-timeline`, `gsap-performance`, `gsap-plugins`, `gsap-scrolltrigger`, `gsap-utils`, `gsap-react`, `gsap-frameworks` | Core API, timeline sequencing, ScrollTrigger, plugin usage, performance best practices |
|
||||
| Source | Skills | What they teach |
|
||||
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **HyperFrames** | `hyperframes-compose`, `hyperframes-captions`, `hyperframes-registry` | HTML composition structure, `class="clip"` rules, `data-*` attributes, timeline registration, rendering constraints, registry block/component install and wiring |
|
||||
| **[GSAP](https://github.com/greensock/gsap-skills)** | `gsap-core`, `gsap-timeline`, `gsap-performance`, `gsap-plugins`, `gsap-scrolltrigger`, `gsap-utils`, `gsap-react`, `gsap-frameworks` | Core API, timeline sequencing, ScrollTrigger, plugin usage, performance best practices |
|
||||
|
||||
In Claude Code, invoke with `/hyperframes-compose`, `/hyperframes-captions`, `/gsap-core`, etc.
|
||||
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Data Chart"
|
||||
description: "Animated bar + line chart with staggered reveal, NYT-style typography, and value labels"
|
||||
---
|
||||
|
||||
# Data Chart
|
||||
|
||||
Animated bar + line chart with staggered reveal, NYT-style typography, and value labels
|
||||
|
||||
`data` `chart` `statistics`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="/images/catalog/blocks/data-chart.mp4" poster="/images/catalog/blocks/data-chart.png" muted loop playsInline autoPlay />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add data-chart
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 15s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `data-chart.html` | `compositions/data-chart.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="data-chart" data-composition-src="compositions/data-chart.html" data-start="0" data-duration="15" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Flowchart"
|
||||
description: "Animated decision tree with SVG connectors, sticky-note nodes, cursor interaction, and typing correction"
|
||||
---
|
||||
|
||||
# Flowchart
|
||||
|
||||
Animated decision tree with SVG connectors, sticky-note nodes, cursor interaction, and typing correction
|
||||
|
||||
`diagram` `flowchart` `interactive`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="/images/catalog/blocks/flowchart.mp4" poster="/images/catalog/blocks/flowchart.png" muted loop playsInline autoPlay />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add flowchart
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 12s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `flowchart.html` | `compositions/flowchart.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="flowchart" data-composition-src="compositions/flowchart.html" data-start="0" data-duration="12" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,44 @@
|
||||
---
|
||||
title: "Logo Outro"
|
||||
description: "Cinematic logo reveal with piece-by-piece assembly, glow bloom, tagline fade-in, and URL pill"
|
||||
---
|
||||
|
||||
# Logo Outro
|
||||
|
||||
Cinematic logo reveal with piece-by-piece assembly, glow bloom, tagline fade-in, and URL pill
|
||||
|
||||
`branding` `outro` `logo`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="/images/catalog/blocks/logo-outro.mp4" poster="/images/catalog/blocks/logo-outro.png" muted loop playsInline autoPlay />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add logo-outro
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Block |
|
||||
| Dimensions | 1920×1080 |
|
||||
| Duration | 6s |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `logo-outro.html` | `compositions/logo-outro.html` | hyperframes:composition |
|
||||
|
||||
## Usage
|
||||
|
||||
After installing, add the block to your host composition:
|
||||
|
||||
```html
|
||||
<div data-composition-id="logo-outro" data-composition-src="compositions/logo-outro.html" data-start="0" data-duration="6" data-track-index="1" data-width="1920" data-height="1080"></div>
|
||||
```
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: "Grain Overlay"
|
||||
description: "Animated film grain texture overlay using CSS keyframes — adds warmth and analog character to any composition"
|
||||
---
|
||||
|
||||
# Grain Overlay
|
||||
|
||||
Animated film grain texture overlay using CSS keyframes — adds warmth and analog character to any composition
|
||||
|
||||
`texture` `grain` `overlay` `film`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="/images/catalog/components/grain-overlay.mp4" poster="/images/catalog/components/grain-overlay.png" muted loop playsInline autoPlay />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add grain-overlay
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Component |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `grain-overlay.html` | `compositions/components/grain-overlay.html` | hyperframes:snippet |
|
||||
|
||||
## Usage
|
||||
|
||||
Open `compositions/components/grain-overlay.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: "Grid Pixelate Wipe"
|
||||
description: "Transition effect where the screen dissolves into a grid of squares that fade out with staggered timing — use between scenes"
|
||||
---
|
||||
|
||||
# Grid Pixelate Wipe
|
||||
|
||||
Transition effect where the screen dissolves into a grid of squares that fade out with staggered timing — use between scenes
|
||||
|
||||
`transition` `wipe` `grid` `pixelate`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="/images/catalog/components/grid-pixelate-wipe.mp4" poster="/images/catalog/components/grid-pixelate-wipe.png" muted loop playsInline autoPlay />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add grid-pixelate-wipe
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Component |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `grid-pixelate-wipe.html` | `compositions/components/grid-pixelate-wipe.html` | hyperframes:snippet |
|
||||
|
||||
## Usage
|
||||
|
||||
Open `compositions/components/grid-pixelate-wipe.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
title: "Shimmer Sweep"
|
||||
description: "Animated light sweep across text or elements using a CSS gradient mask — ideal for AI accents and premium reveals"
|
||||
---
|
||||
|
||||
# Shimmer Sweep
|
||||
|
||||
Animated light sweep across text or elements using a CSS gradient mask — ideal for AI accents and premium reveals
|
||||
|
||||
`text` `shimmer` `highlight` `effect`
|
||||
|
||||
<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="/images/catalog/components/shimmer-sweep.mp4" poster="/images/catalog/components/shimmer-sweep.png" muted loop playsInline autoPlay />
|
||||
|
||||
## Install
|
||||
|
||||
<CodeGroup>
|
||||
|
||||
```bash Terminal
|
||||
npx hyperframes add shimmer-sweep
|
||||
```
|
||||
|
||||
</CodeGroup>
|
||||
|
||||
## Details
|
||||
|
||||
| Property | Value |
|
||||
| --- | --- |
|
||||
| Type | Component |
|
||||
|
||||
## Files
|
||||
|
||||
| File | Target | Type |
|
||||
| --- | --- | --- |
|
||||
| `shimmer-sweep.html` | `compositions/components/shimmer-sweep.html` | hyperframes:snippet |
|
||||
|
||||
## Usage
|
||||
|
||||
Open `compositions/components/shimmer-sweep.html` and paste its contents into your composition. See the comment header in the file for detailed instructions.
|
||||
+33
-3
@@ -51,7 +51,11 @@
|
||||
"groups": [
|
||||
{
|
||||
"group": "Getting Started",
|
||||
"pages": ["introduction", "quickstart", "examples"]
|
||||
"pages": [
|
||||
"introduction",
|
||||
"quickstart",
|
||||
"examples"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Concepts",
|
||||
@@ -89,16 +93,42 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tab": "Catalog",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Blocks",
|
||||
"pages": [
|
||||
"catalog/blocks/data-chart",
|
||||
"catalog/blocks/flowchart",
|
||||
"catalog/blocks/logo-outro"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Components",
|
||||
"pages": [
|
||||
"catalog/components/grain-overlay",
|
||||
"catalog/components/grid-pixelate-wipe",
|
||||
"catalog/components/shimmer-sweep"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"tab": "Reference",
|
||||
"groups": [
|
||||
{
|
||||
"group": "Reference",
|
||||
"pages": ["reference/html-schema"]
|
||||
"pages": [
|
||||
"reference/html-schema"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Contributing",
|
||||
"pages": ["contributing", "contributing/testing-local-changes"]
|
||||
"pages": [
|
||||
"contributing",
|
||||
"contributing/testing-local-changes"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
@@ -538,7 +538,7 @@ This is suppressed in CI environments, non-TTY shells, and when `HYPERFRAMES_NO_
|
||||
| `--codex` | Install to Codex CLI (`~/.codex/skills/`) |
|
||||
| `--cursor` | Install to Cursor (`.cursor/skills/` in current project) |
|
||||
|
||||
Skills are fetched from GitHub and include composition authoring, GSAP animation patterns, and other domain-specific knowledge. The `init` command also offers to install skills automatically after scaffolding a project.
|
||||
Skills are fetched from GitHub and include composition authoring, GSAP animation patterns, registry block/component wiring, and other domain-specific knowledge. The `init` command also offers to install skills automatically after scaffolding a project.
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
[
|
||||
{
|
||||
"name": "data-chart",
|
||||
"type": "block",
|
||||
"title": "Data Chart",
|
||||
"description": "Animated bar + line chart with staggered reveal, NYT-style typography, and value labels",
|
||||
"tags": [
|
||||
"data",
|
||||
"chart",
|
||||
"statistics"
|
||||
],
|
||||
"href": "/catalog/blocks/data-chart",
|
||||
"preview": "/images/catalog/blocks/data-chart.png"
|
||||
},
|
||||
{
|
||||
"name": "flowchart",
|
||||
"type": "block",
|
||||
"title": "Flowchart",
|
||||
"description": "Animated decision tree with SVG connectors, sticky-note nodes, cursor interaction, and typing correction",
|
||||
"tags": [
|
||||
"diagram",
|
||||
"flowchart",
|
||||
"interactive"
|
||||
],
|
||||
"href": "/catalog/blocks/flowchart",
|
||||
"preview": "/images/catalog/blocks/flowchart.png"
|
||||
},
|
||||
{
|
||||
"name": "grain-overlay",
|
||||
"type": "component",
|
||||
"title": "Grain Overlay",
|
||||
"description": "Animated film grain texture overlay using CSS keyframes — adds warmth and analog character to any composition",
|
||||
"tags": [
|
||||
"texture",
|
||||
"grain",
|
||||
"overlay",
|
||||
"film"
|
||||
],
|
||||
"href": "/catalog/components/grain-overlay",
|
||||
"preview": "/images/catalog/components/grain-overlay.png"
|
||||
},
|
||||
{
|
||||
"name": "grid-pixelate-wipe",
|
||||
"type": "component",
|
||||
"title": "Grid Pixelate Wipe",
|
||||
"description": "Transition effect where the screen dissolves into a grid of squares that fade out with staggered timing — use between scenes",
|
||||
"tags": [
|
||||
"transition",
|
||||
"wipe",
|
||||
"grid",
|
||||
"pixelate"
|
||||
],
|
||||
"href": "/catalog/components/grid-pixelate-wipe",
|
||||
"preview": "/images/catalog/components/grid-pixelate-wipe.png"
|
||||
},
|
||||
{
|
||||
"name": "logo-outro",
|
||||
"type": "block",
|
||||
"title": "Logo Outro",
|
||||
"description": "Cinematic logo reveal with piece-by-piece assembly, glow bloom, tagline fade-in, and URL pill",
|
||||
"tags": [
|
||||
"branding",
|
||||
"outro",
|
||||
"logo"
|
||||
],
|
||||
"href": "/catalog/blocks/logo-outro",
|
||||
"preview": "/images/catalog/blocks/logo-outro.png"
|
||||
},
|
||||
{
|
||||
"name": "shimmer-sweep",
|
||||
"type": "component",
|
||||
"title": "Shimmer Sweep",
|
||||
"description": "Animated light sweep across text or elements using a CSS gradient mask — ideal for AI accents and premium reveals",
|
||||
"tags": [
|
||||
"text",
|
||||
"shimmer",
|
||||
"highlight",
|
||||
"effect"
|
||||
],
|
||||
"href": "/catalog/components/shimmer-sweep",
|
||||
"preview": "/images/catalog/components/shimmer-sweep.png"
|
||||
}
|
||||
]
|
||||
@@ -139,9 +139,9 @@ describe("add command pure helpers", () => {
|
||||
});
|
||||
|
||||
describe("buildSnippet", () => {
|
||||
it("wraps blocks in an iframe with start/duration", () => {
|
||||
it("wraps blocks in a div with data-composition-src and duration", () => {
|
||||
const snip = buildSnippet(BLOCK_ITEM, "src/scenes/my-block.html");
|
||||
expect(snip).toContain('src="src/scenes/my-block.html"');
|
||||
expect(snip).toContain('data-composition-src="src/scenes/my-block.html"');
|
||||
expect(snip).toContain('data-duration="6"');
|
||||
});
|
||||
|
||||
|
||||
@@ -55,7 +55,11 @@ export function remapTarget(
|
||||
export function buildSnippet(item: RegistryItem, relativeTarget: string): string {
|
||||
if (item.type === "hyperframes:block") {
|
||||
// data-start omitted — adjust to your timeline position after pasting.
|
||||
return `<iframe src="${relativeTarget}" data-duration="${item.duration}"></iframe>`;
|
||||
const dims =
|
||||
"dimensions" in item && item.dimensions
|
||||
? ` data-width="${item.dimensions.width}" data-height="${item.dimensions.height}"`
|
||||
: "";
|
||||
return `<div data-composition-src="${relativeTarget}" data-duration="${item.duration}"${dims}></div>`;
|
||||
}
|
||||
if (item.type === "hyperframes:component") {
|
||||
return `<!-- paste from ${relativeTarget} into your composition -->`;
|
||||
|
||||
@@ -29,19 +29,7 @@
|
||||
data-duration="5"
|
||||
>
|
||||
<!-- Background content to demonstrate the overlay -->
|
||||
<div
|
||||
class="demo-bg"
|
||||
style="
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
background: linear-gradient(135deg, #f5f0e0 0%, #e8d8b8 50%, #d4c4a0 100%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: "Inter", sans-serif;
|
||||
position: relative;
|
||||
"
|
||||
>
|
||||
<div class="demo-bg">
|
||||
<div style="text-align: center; z-index: 1">
|
||||
<div
|
||||
class="demo-title"
|
||||
@@ -75,6 +63,17 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.demo-bg {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
background: linear-gradient(135deg, #f5f0e0 0%, #e8d8b8 50%, #d4c4a0 100%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: "Inter", sans-serif;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@keyframes grain-noise {
|
||||
0%,
|
||||
100% {
|
||||
@@ -115,7 +114,7 @@
|
||||
left: -50%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
background: url("https://www.transparenttextures.com/patterns/natural-paper.png");
|
||||
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
|
||||
opacity: 0.15;
|
||||
animation: grain-noise 0.5s steps(1) infinite;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
left: -50%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
background: url("https://www.transparenttextures.com/patterns/natural-paper.png");
|
||||
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
|
||||
opacity: 0.15;
|
||||
animation: grain-noise 0.5s steps(1) infinite;
|
||||
}
|
||||
|
||||
@@ -29,19 +29,7 @@
|
||||
data-duration="8"
|
||||
>
|
||||
<!-- Scene A -->
|
||||
<div
|
||||
id="scene-a"
|
||||
style="
|
||||
position: absolute;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: "Inter", sans-serif;
|
||||
"
|
||||
>
|
||||
<div id="scene-a" class="demo-scene scene-a">
|
||||
<div style="text-align: center; color: white">
|
||||
<div style="font-size: 80px; font-weight: 800">Scene A</div>
|
||||
<div style="font-size: 32px; margin-top: 20px; opacity: 0.7">
|
||||
@@ -51,20 +39,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Scene B (hidden initially) -->
|
||||
<div
|
||||
id="scene-b"
|
||||
style="
|
||||
position: absolute;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: "Inter", sans-serif;
|
||||
opacity: 0;
|
||||
"
|
||||
>
|
||||
<div id="scene-b" class="demo-scene scene-b">
|
||||
<div style="text-align: center; color: white">
|
||||
<div style="font-size: 80px; font-weight: 800">Scene B</div>
|
||||
<div style="font-size: 32px; margin-top: 20px; opacity: 0.7">Revealed from the grid</div>
|
||||
@@ -98,6 +73,27 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.demo-scene {
|
||||
position: absolute;
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: "Inter", sans-serif;
|
||||
}
|
||||
|
||||
.scene-a {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
}
|
||||
|
||||
.scene-b {
|
||||
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||||
opacity: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
const COLS = 16;
|
||||
|
||||
@@ -28,20 +28,7 @@
|
||||
data-height="1080"
|
||||
data-duration="6"
|
||||
>
|
||||
<div
|
||||
class="demo-canvas"
|
||||
style="
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
background: #0a0a0f;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 60px;
|
||||
font-family: "Inter", sans-serif;
|
||||
"
|
||||
>
|
||||
<div class="demo-canvas">
|
||||
<!-- Example 1: Large heading -->
|
||||
<div class="shimmer-sweep-target" style="--shimmer-color: rgba(255, 255, 255, 0.5)">
|
||||
<div
|
||||
@@ -86,6 +73,18 @@
|
||||
|
||||
<!-- Shimmer Sweep component -->
|
||||
<style>
|
||||
.demo-canvas {
|
||||
width: 1920px;
|
||||
height: 1080px;
|
||||
background: #0a0a0f;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 60px;
|
||||
font-family: "Inter", sans-serif;
|
||||
}
|
||||
|
||||
.shimmer-sweep-target {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
|
||||
@@ -16,7 +16,12 @@
|
||||
import { readdirSync, readFileSync, existsSync, mkdirSync, writeFileSync, rmSync } from "node:fs";
|
||||
import { join, resolve, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { type RegistryItem, isBlockItem, ITEM_TYPE_DIRS } from "@hyperframes/core";
|
||||
// Import from source — bun workspace linking doesn't resolve for scripts outside packages/.
|
||||
import {
|
||||
type RegistryItem,
|
||||
isBlockItem,
|
||||
ITEM_TYPE_DIRS,
|
||||
} from "../packages/core/src/registry/types.js";
|
||||
|
||||
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = resolve(scriptDir, "..");
|
||||
@@ -95,11 +100,10 @@ function generateItemMdx(kind: ItemKind, manifest: RegistryItem): string {
|
||||
lines.push(tagBadges, "");
|
||||
}
|
||||
|
||||
// Preview — rendered by CI preview pipeline (PR 8).
|
||||
// The image/video may not exist yet if previews haven't been generated.
|
||||
// Preview video with poster fallback — matches the examples page pattern.
|
||||
const previewPath = `/images/catalog/${typeDir(kind)}/${manifest.name}`;
|
||||
lines.push(
|
||||
`<img className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="${previewPath}.png" alt="${manifest.title} preview" />`,
|
||||
`<video className="w-full aspect-video rounded-xl object-cover bg-zinc-100 dark:bg-zinc-800" src="${previewPath}.mp4" poster="${previewPath}.png" muted loop playsInline autoPlay />`,
|
||||
"",
|
||||
);
|
||||
|
||||
@@ -155,13 +159,15 @@ function generateItemMdx(kind: ItemKind, manifest: RegistryItem): string {
|
||||
const primaryTarget = primaryFile?.target ?? `compositions/${manifest.name}.html`;
|
||||
|
||||
if (kind === "block" && isBlockItem(manifest)) {
|
||||
const w = manifest.dimensions.width;
|
||||
const h = manifest.dimensions.height;
|
||||
lines.push(
|
||||
"## Usage",
|
||||
"",
|
||||
"After installing, add the block to your host composition as an iframe:",
|
||||
"After installing, add the block to your host composition:",
|
||||
"",
|
||||
"```html",
|
||||
`<iframe src="${primaryTarget}" data-start="0" data-duration="${manifest.duration}" data-track-index="1"></iframe>`,
|
||||
`<div data-composition-id="${manifest.name}" data-composition-src="${primaryTarget}" data-start="0" data-duration="${manifest.duration}" data-track-index="1" data-width="${w}" data-height="${h}"></div>`,
|
||||
"```",
|
||||
"",
|
||||
);
|
||||
|
||||
@@ -16,10 +16,19 @@
|
||||
* npx tsx scripts/generate-catalog-previews.ts --skip-video # thumbnails only
|
||||
*/
|
||||
|
||||
import { readdirSync, readFileSync, existsSync, mkdirSync, cpSync, rmSync } from "node:fs";
|
||||
import {
|
||||
readdirSync,
|
||||
readFileSync,
|
||||
existsSync,
|
||||
mkdirSync,
|
||||
cpSync,
|
||||
rmSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { join, resolve, dirname } from "node:path";
|
||||
import { tmpdir } from "node:os";
|
||||
import { fileURLToPath } from "node:url";
|
||||
// Import from source — bun workspace linking doesn't resolve for scripts outside packages/.
|
||||
import {
|
||||
createFileServer,
|
||||
createCaptureSession,
|
||||
@@ -29,7 +38,7 @@ import {
|
||||
closeCaptureSession,
|
||||
createRenderJob,
|
||||
executeRenderJob,
|
||||
} from "@hyperframes/producer";
|
||||
} from "../packages/producer/src/index.js";
|
||||
|
||||
const scriptDir = dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = resolve(scriptDir, "..");
|
||||
@@ -115,6 +124,43 @@ function prepareProjectDir(item: CatalogItem): string {
|
||||
const tmpDir = join(tmpdir(), `hf-catalog-${item.name}-${Date.now()}`);
|
||||
mkdirSync(tmpDir, { recursive: true });
|
||||
cpSync(item.sourceDir, tmpDir, { recursive: true });
|
||||
|
||||
// The HyperFrames producer navigates to index.html at the project root.
|
||||
// Blocks and component demos are standalone HTML files, not index.html.
|
||||
// Create a wrapper index.html that loads the entry file as a sub-composition.
|
||||
if (!existsSync(join(tmpDir, "index.html"))) {
|
||||
const manifestPath = join(tmpDir, "registry-item.json");
|
||||
let width = 1920;
|
||||
let height = 1080;
|
||||
let duration = 5;
|
||||
if (existsSync(manifestPath)) {
|
||||
const m = JSON.parse(readFileSync(manifestPath, "utf-8"));
|
||||
width = m.dimensions?.width ?? width;
|
||||
height = m.dimensions?.height ?? height;
|
||||
duration = m.duration ?? duration;
|
||||
}
|
||||
|
||||
const wrapper = `<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=${width}, height=${height}" />
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
<style>* { margin: 0; padding: 0; } html, body { width: ${width}px; height: ${height}px; overflow: hidden; }</style>
|
||||
</head>
|
||||
<body>
|
||||
<div data-composition-id="preview-root" data-width="${width}" data-height="${height}" data-start="0" data-duration="${duration}">
|
||||
<div data-composition-id="${item.name}" data-composition-src="${item.entryFile}" data-start="0" data-duration="${duration}" data-track-index="0" data-width="${width}" data-height="${height}"></div>
|
||||
</div>
|
||||
<script>
|
||||
window.__timelines = window.__timelines || {};
|
||||
window.__timelines["preview-root"] = gsap.timeline({ paused: true });
|
||||
</script>
|
||||
</body>
|
||||
</html>`;
|
||||
writeFileSync(join(tmpDir, "index.html"), wrapper, "utf-8");
|
||||
}
|
||||
|
||||
return tmpDir;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
---
|
||||
name: hyperframes-registry
|
||||
description: Install and wire registry blocks and components into HyperFrames compositions. Use when running hyperframes add, installing a block or component, wiring an installed item into index.html, or working with hyperframes.json. Covers the add command, install locations, block iframe wiring, component snippet merging, and registry discovery.
|
||||
---
|
||||
|
||||
# HyperFrames Registry
|
||||
|
||||
The registry provides reusable blocks and components installable via `hyperframes add <name>`.
|
||||
|
||||
- **Blocks** — standalone sub-compositions (own dimensions, duration, timeline). Included via `<iframe>` in a host composition.
|
||||
- **Components** — effect snippets (no own dimensions). Pasted directly into a host composition's HTML.
|
||||
|
||||
## When to use this skill
|
||||
|
||||
- User mentions `hyperframes add`, "block", "component", or `hyperframes.json`
|
||||
- Output from `hyperframes add` appears in the session (file paths, clipboard snippet)
|
||||
- You need to wire an installed item into an existing composition
|
||||
- You want to discover what's available in the registry
|
||||
|
||||
## Quick reference
|
||||
|
||||
```bash
|
||||
hyperframes add data-chart # install a block
|
||||
hyperframes add grain-overlay # install a component
|
||||
hyperframes add shimmer-sweep --dir . # target a specific project
|
||||
hyperframes add data-chart --json # machine-readable output
|
||||
hyperframes add data-chart --no-clipboard # skip clipboard (CI/headless)
|
||||
```
|
||||
|
||||
After install, the CLI prints which files were written and a snippet to paste into your host composition. The snippet is a starting point — you'll need to add `data-start` and `data-track-index` attributes when wiring blocks.
|
||||
|
||||
Note: `hyperframes add` only works for blocks and components. For examples, use `hyperframes init <dir> --example <name>` instead.
|
||||
|
||||
## Install locations
|
||||
|
||||
Blocks install to `compositions/<name>.html` by default.
|
||||
Components install to `compositions/components/<name>.html` by default.
|
||||
|
||||
These paths are configurable in `hyperframes.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"registry": "https://raw.githubusercontent.com/heygen-com/hyperframes/main/registry",
|
||||
"paths": {
|
||||
"blocks": "compositions",
|
||||
"components": "compositions/components",
|
||||
"assets": "assets"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
See [install-locations.md](./references/install-locations.md) for full details.
|
||||
|
||||
## Wiring blocks
|
||||
|
||||
Blocks are standalone compositions — include them via `data-composition-src` in your host `index.html`:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="data-chart"
|
||||
data-composition-src="compositions/data-chart.html"
|
||||
data-start="2"
|
||||
data-duration="15"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
|
||||
Key attributes:
|
||||
|
||||
- `data-composition-src` — path to the block HTML file
|
||||
- `data-composition-id` — must match the block's internal ID
|
||||
- `data-start` — when the block appears in the host timeline (seconds)
|
||||
- `data-duration` — how long the block plays
|
||||
- `data-width` / `data-height` — block canvas dimensions
|
||||
- `data-track-index` — layer ordering (higher = in front)
|
||||
|
||||
See [wiring-blocks.md](./references/wiring-blocks.md) for full details.
|
||||
|
||||
## Wiring components
|
||||
|
||||
Components are snippets — paste their HTML into your composition's markup, their CSS into your style block, and their JS into your script (if any):
|
||||
|
||||
1. Read the installed file (e.g., `compositions/components/grain-overlay.html`)
|
||||
2. Copy the HTML elements into your composition's `<div data-composition-id="...">`
|
||||
3. Copy the `<style>` block into your composition's styles
|
||||
4. Copy any `<script>` content into your composition's script (before your timeline code)
|
||||
5. If the component exposes GSAP timeline integration (see the comment block in the snippet), add those calls to your timeline
|
||||
|
||||
See [wiring-components.md](./references/wiring-components.md) for full details.
|
||||
|
||||
## Discovery
|
||||
|
||||
Browse available items:
|
||||
|
||||
```bash
|
||||
# Read the registry manifest
|
||||
curl -s https://raw.githubusercontent.com/heygen-com/hyperframes/main/registry/registry.json
|
||||
```
|
||||
|
||||
Each item's `registry-item.json` contains: name, type, title, description, tags, dimensions (blocks only), duration (blocks only), and file list.
|
||||
|
||||
See [discovery.md](./references/discovery.md) for details on filtering by type and tags.
|
||||
@@ -0,0 +1,51 @@
|
||||
# Worked Example: Adding a Block
|
||||
|
||||
## Scenario
|
||||
|
||||
User has an existing HyperFrames project and wants to add an animated chart alongside their video content.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Install the block
|
||||
|
||||
```bash
|
||||
hyperframes add data-chart
|
||||
```
|
||||
|
||||
### 2. Wire into index.html
|
||||
|
||||
```html
|
||||
<div id="stage" data-composition-id="main" data-width="1920" data-height="1080" data-duration="30">
|
||||
<video
|
||||
id="speaker"
|
||||
src="speaker.mp4"
|
||||
data-start="0"
|
||||
data-duration="30"
|
||||
data-track-index="0"
|
||||
style="position: absolute; width: 60%; height: 100%; left: 0; top: 0; object-fit: cover;"
|
||||
></video>
|
||||
|
||||
<!-- Data chart appears at 5s in the right 40% of the screen -->
|
||||
<div
|
||||
data-composition-id="data-chart"
|
||||
data-composition-src="compositions/data-chart.html"
|
||||
data-start="5"
|
||||
data-duration="15"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
style="position: absolute; right: 0; top: 0; width: 40%; height: 100%;"
|
||||
></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
### 3. Lint and preview
|
||||
|
||||
```bash
|
||||
hyperframes lint
|
||||
hyperframes preview
|
||||
```
|
||||
|
||||
### 4. Customize (optional)
|
||||
|
||||
Edit `compositions/data-chart.html` — data arrays are at the top of the script, colors are in the CSS rules scoped under `[data-composition-id="data-chart"]`.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Worked Example: Adding a Component
|
||||
|
||||
## Scenario
|
||||
|
||||
User wants to add a shimmer light sweep effect to their title text.
|
||||
|
||||
## Steps
|
||||
|
||||
### 1. Install the component
|
||||
|
||||
```bash
|
||||
hyperframes add shimmer-sweep
|
||||
```
|
||||
|
||||
### 2. Read the snippet
|
||||
|
||||
Open `compositions/components/shimmer-sweep.html` and read the comment header.
|
||||
|
||||
### 3. Wire into your composition
|
||||
|
||||
**HTML** — wrap target elements:
|
||||
|
||||
```html
|
||||
<div class="shimmer-sweep-target" style="--shimmer-color: rgba(255, 255, 255, 0.5)">
|
||||
<h1 class="title">AI-Powered Video</h1>
|
||||
</div>
|
||||
```
|
||||
|
||||
**CSS** — paste the `.shimmer-sweep-target` and `.shimmer-mask` rules from the snippet.
|
||||
|
||||
**JS** — paste the auto-injection script (before timeline code):
|
||||
|
||||
```js
|
||||
document.querySelectorAll(".shimmer-sweep-target").forEach((el) => {
|
||||
if (!el.querySelector(".shimmer-mask")) {
|
||||
const mask = document.createElement("div");
|
||||
mask.className = "shimmer-mask";
|
||||
el.appendChild(mask);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
**Timeline** — add the sweep:
|
||||
|
||||
```js
|
||||
tl.fromTo(
|
||||
".shimmer-sweep-target",
|
||||
{
|
||||
"--shimmer-pos": "-20%",
|
||||
},
|
||||
{
|
||||
"--shimmer-pos": "120%",
|
||||
duration: 1.2,
|
||||
ease: "power2.inOut",
|
||||
stagger: 0.15,
|
||||
},
|
||||
1.5,
|
||||
);
|
||||
```
|
||||
|
||||
### 4. Lint and preview
|
||||
|
||||
```bash
|
||||
hyperframes lint
|
||||
hyperframes preview
|
||||
```
|
||||
|
||||
### 5. Customize
|
||||
|
||||
- `--shimmer-color`: highlight color per element
|
||||
- `--shimmer-width`: light band width (default 20%)
|
||||
- `--shimmer-angle`: sweep direction (default 120deg)
|
||||
- Timeline `duration`, `ease`, `stagger`: control speed and feel
|
||||
@@ -0,0 +1,54 @@
|
||||
# The demo.html Convention
|
||||
|
||||
## Why components ship demo.html
|
||||
|
||||
Every component in the registry ships a companion `demo.html` file alongside its snippet. The demo serves two purposes:
|
||||
|
||||
1. **Preview fixture** — the CI preview pipeline renders the demo to generate thumbnail images and preview videos for the catalog docs page.
|
||||
|
||||
2. **Usage example** — the demo shows the component effect applied to representative content, serving as a working reference.
|
||||
|
||||
## Demo structure
|
||||
|
||||
A demo is a complete, standalone HTML composition:
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=1920, height=1080" />
|
||||
<title>Component Name — Demo</title>
|
||||
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
|
||||
<style>
|
||||
/* reset + canvas size */
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div data-composition-id="<name>-demo" data-width="1920" data-height="1080" data-duration="N">
|
||||
<!-- Demo content showing the effect -->
|
||||
<!-- Component snippet inlined here -->
|
||||
</div>
|
||||
<script>
|
||||
// GSAP timeline demonstrating the effect
|
||||
window.__timelines = window.__timelines || {};
|
||||
window.__timelines["<name>-demo"] = tl;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Key conventions:
|
||||
|
||||
- `data-composition-id` is `<component-name>-demo` to avoid collisions
|
||||
- The demo is self-contained — all CSS and JS from the snippet is inlined
|
||||
- The GSAP timeline is registered on `window.__timelines`
|
||||
- Duration should be long enough to showcase the effect (typically 5-8 seconds)
|
||||
|
||||
## Blocks don't need demo.html
|
||||
|
||||
Blocks are already standalone compositions that can be rendered directly. Only components need the demo wrapper.
|
||||
|
||||
## Demos are not installed
|
||||
|
||||
The `demo.html` is NOT installed by `hyperframes add` — it exists only in the registry for preview generation and as a reference.
|
||||
@@ -0,0 +1,53 @@
|
||||
# Registry Discovery
|
||||
|
||||
## Reading the registry manifest
|
||||
|
||||
The top-level `registry.json` lists all available items:
|
||||
|
||||
```bash
|
||||
curl -s https://raw.githubusercontent.com/heygen-com/hyperframes/main/registry/registry.json
|
||||
```
|
||||
|
||||
Each entry has `name` and `type` (`hyperframes:example`, `hyperframes:block`, or `hyperframes:component`).
|
||||
|
||||
## Reading an item's manifest
|
||||
|
||||
Each item has a `registry-item.json` with full metadata:
|
||||
|
||||
```
|
||||
<base>/<type-dir>/<name>/registry-item.json
|
||||
```
|
||||
|
||||
Where `<type-dir>` is `examples`, `blocks`, or `components`.
|
||||
|
||||
## Item manifest fields
|
||||
|
||||
| Field | Type | Required | Description |
|
||||
| ---------------------- | -------- | -------- | ---------------------------------------------- |
|
||||
| `name` | string | yes | Kebab-case identifier |
|
||||
| `type` | string | yes | `hyperframes:block` or `hyperframes:component` |
|
||||
| `title` | string | yes | Human-readable title |
|
||||
| `description` | string | yes | One-line description |
|
||||
| `tags` | string[] | no | Filter tags (e.g., `["data", "chart"]`) |
|
||||
| `dimensions` | object | blocks | `{ width, height }` — blocks only |
|
||||
| `duration` | number | blocks | Duration in seconds — blocks only |
|
||||
| `files` | array | yes | Files to install (`path`, `target`, `type`) |
|
||||
| `registryDependencies` | string[] | no | Other registry items this depends on |
|
||||
|
||||
## Available items
|
||||
|
||||
### Blocks
|
||||
|
||||
| Name | Description | Tags |
|
||||
| ------------ | ----------------------------------------------- | ------------------------------- |
|
||||
| `data-chart` | Animated bar + line chart with staggered reveal | data, chart, statistics |
|
||||
| `flowchart` | Decision tree with SVG connectors and cursor | diagram, flowchart, interactive |
|
||||
| `logo-outro` | Cinematic logo reveal with tagline | branding, outro, logo |
|
||||
|
||||
### Components
|
||||
|
||||
| Name | Description | Tags |
|
||||
| -------------------- | --------------------------------------- | -------------------------------- |
|
||||
| `grain-overlay` | Animated film grain texture overlay | texture, grain, overlay, film |
|
||||
| `shimmer-sweep` | CSS gradient light sweep for AI accents | text, shimmer, highlight, effect |
|
||||
| `grid-pixelate-wipe` | Grid dissolve transition between scenes | transition, wipe, grid, pixelate |
|
||||
@@ -0,0 +1,45 @@
|
||||
# Install Locations
|
||||
|
||||
## Default paths
|
||||
|
||||
| Item type | Default install path | Configured by |
|
||||
| --------- | ------------------------------------- | ----------------------------------- |
|
||||
| Block | `compositions/<name>.html` | `hyperframes.json#paths.blocks` |
|
||||
| Component | `compositions/components/<name>.html` | `hyperframes.json#paths.components` |
|
||||
|
||||
## How path remapping works
|
||||
|
||||
The `target` field in each item's `registry-item.json` specifies a default install path. The `add` command remaps the prefix based on `hyperframes.json#paths`:
|
||||
|
||||
- Block targets starting with `compositions/` get remapped to `<paths.blocks>/`
|
||||
- Component targets starting with `compositions/components/` get remapped to `<paths.components>/`
|
||||
|
||||
## hyperframes.json
|
||||
|
||||
Created automatically by `hyperframes init`. If it doesn't exist when you run `add`, the CLI creates it with defaults:
|
||||
|
||||
```json
|
||||
{
|
||||
"$schema": "https://hyperframes.heygen.com/schema/hyperframes.json",
|
||||
"registry": "https://raw.githubusercontent.com/heygen-com/hyperframes/main/registry",
|
||||
"paths": {
|
||||
"blocks": "compositions",
|
||||
"components": "compositions/components",
|
||||
"assets": "assets"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Custom layouts
|
||||
|
||||
To install blocks into a `scenes/` directory instead of `compositions/`:
|
||||
|
||||
```json
|
||||
{
|
||||
"paths": {
|
||||
"blocks": "scenes"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then `hyperframes add data-chart` writes to `scenes/data-chart.html` instead of `compositions/data-chart.html`. The snippet output reflects the remapped path.
|
||||
@@ -0,0 +1,91 @@
|
||||
# Wiring Blocks
|
||||
|
||||
Blocks are standalone compositions with their own `data-composition-id`, dimensions, duration, and GSAP timeline. Include them in a host composition using `data-composition-src` on a `<div>`.
|
||||
|
||||
## Basic wiring
|
||||
|
||||
After `hyperframes add data-chart`, wire it into your `index.html`:
|
||||
|
||||
```html
|
||||
<div id="stage" data-composition-id="main" data-width="1920" data-height="1080" data-duration="20">
|
||||
<video id="a-roll" src="video.mp4" data-start="0" data-duration="20" data-track-index="0"></video>
|
||||
|
||||
<!-- Block: appears at 2s, plays for 15s, on layer 1 -->
|
||||
<div
|
||||
data-composition-id="data-chart"
|
||||
data-composition-src="compositions/data-chart.html"
|
||||
data-start="2"
|
||||
data-duration="15"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Required attributes
|
||||
|
||||
| Attribute | Description |
|
||||
| ---------------------- | -------------------------------------------------------------------- |
|
||||
| `data-composition-src` | Path to the block HTML file (relative to index.html) |
|
||||
| `data-composition-id` | Unique ID matching the block's internal composition ID |
|
||||
| `data-start` | When the block appears in the host timeline (seconds) |
|
||||
| `data-duration` | How long the block plays (seconds, at most the block's own duration) |
|
||||
| `data-track-index` | Layer ordering — higher numbers render in front |
|
||||
| `data-width` | Block canvas width (match the block's dimensions) |
|
||||
| `data-height` | Block canvas height (match the block's dimensions) |
|
||||
|
||||
## Timeline coordination
|
||||
|
||||
The block's internal GSAP timeline runs independently from the host timeline. The HyperFrames runtime loads the sub-composition, finds its `window.__timelines` registration, and seeks the block in sync with the host, offset by `data-start`. You do NOT need to reference the block's timeline in your host's GSAP code.
|
||||
|
||||
## Positioning blocks
|
||||
|
||||
To position a block in a specific area of the screen, add CSS:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="data-chart"
|
||||
data-composition-src="compositions/data-chart.html"
|
||||
data-start="2"
|
||||
data-duration="15"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
style="position: absolute; right: 0; top: 0; width: 40%; height: 100%;"
|
||||
></div>
|
||||
```
|
||||
|
||||
## Multiple blocks
|
||||
|
||||
Include multiple blocks sequentially or overlapping:
|
||||
|
||||
```html
|
||||
<div
|
||||
data-composition-id="data-chart"
|
||||
data-composition-src="compositions/data-chart.html"
|
||||
data-start="0"
|
||||
data-duration="15"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
<div
|
||||
data-composition-id="flowchart"
|
||||
data-composition-src="compositions/flowchart.html"
|
||||
data-start="15"
|
||||
data-duration="12"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
<div
|
||||
data-composition-id="logo-outro"
|
||||
data-composition-src="compositions/logo-outro.html"
|
||||
data-start="27"
|
||||
data-duration="6"
|
||||
data-track-index="1"
|
||||
data-width="1920"
|
||||
data-height="1080"
|
||||
></div>
|
||||
```
|
||||
@@ -0,0 +1,77 @@
|
||||
# Wiring Components
|
||||
|
||||
Components are effect snippets — HTML, CSS, and optionally JS that you merge directly into an existing composition. Unlike blocks, components have no standalone timeline; they participate in the host composition's timeline.
|
||||
|
||||
## General process
|
||||
|
||||
1. Run `hyperframes add <component-name>`
|
||||
2. Open the installed file (e.g., `compositions/components/grain-overlay.html`)
|
||||
3. Read the comment header for usage instructions
|
||||
4. Copy the parts into your host composition:
|
||||
- **HTML elements** — inside your `<div data-composition-id="...">`
|
||||
- **CSS styles** — into your composition's `<style>` block
|
||||
- **JS setup** — into your composition's `<script>`, before your timeline code
|
||||
- **Timeline calls** — into your GSAP timeline (if the component exposes them)
|
||||
|
||||
## Example: grain-overlay (CSS-only, no timeline integration)
|
||||
|
||||
```html
|
||||
<!-- Paste the overlay div into your composition -->
|
||||
<div
|
||||
id="grain-overlay"
|
||||
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 100;"
|
||||
>
|
||||
<div class="grain-texture"></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Then paste the CSS keyframes and `.grain-texture` rule into your styles. No GSAP timeline calls needed — the grain animates via CSS `@keyframes`.
|
||||
|
||||
## Example: shimmer-sweep (needs timeline integration)
|
||||
|
||||
Wrap target elements, paste CSS and JS, then drive the sweep from your timeline:
|
||||
|
||||
```js
|
||||
tl.fromTo(
|
||||
".shimmer-sweep-target",
|
||||
{
|
||||
"--shimmer-pos": "-20%",
|
||||
},
|
||||
{
|
||||
"--shimmer-pos": "120%",
|
||||
duration: 1.2,
|
||||
ease: "power2.inOut",
|
||||
stagger: 0.15,
|
||||
},
|
||||
2.0,
|
||||
);
|
||||
```
|
||||
|
||||
## Example: grid-pixelate-wipe (scene transition)
|
||||
|
||||
Paste the overlay HTML and CSS, then drive `.grid-cell` scale in your timeline:
|
||||
|
||||
```js
|
||||
// Cover screen
|
||||
tl.to(
|
||||
".grid-cell",
|
||||
{ scale: 1, duration: 0.6, stagger: { amount: 0.6, from: "center" }, ease: "power2.inOut" },
|
||||
5.0,
|
||||
);
|
||||
// Swap scenes
|
||||
tl.set("#scene-a", { opacity: 0 }, 5.6);
|
||||
tl.set("#scene-b", { opacity: 1 }, 5.6);
|
||||
// Reveal
|
||||
tl.to(
|
||||
".grid-cell",
|
||||
{ scale: 0, duration: 0.6, stagger: { amount: 0.6, from: "edges" }, ease: "power2.inOut" },
|
||||
5.6,
|
||||
);
|
||||
```
|
||||
|
||||
## Key principles
|
||||
|
||||
- Components inherit the host composition's dimensions and duration
|
||||
- Place component HTML at the appropriate z-index relative to your content
|
||||
- Read the comment header in each snippet for customizable values
|
||||
- Run `hyperframes lint` after wiring to catch structural issues
|
||||
Reference in New Issue
Block a user