hyperframes: add HTML/CSS/GSAP as a parallel composition runtime
Separates creative grammar (renderer_family) from technical engine (render_runtime) so HyperFrames can stand alongside Remotion as a first-class runtime instead of masquerading as a Remotion sub-case. Locks runtime choice at proposal stage and enforces it end-to-end: the schemas require it, video_compose routes by it, the reviewer fails closed on silent swaps, and a parametrized contract test walks every pipeline manifest to ensure each planning-stage skill explains the conversation to the user. Adds hyperframes_compose (scaffold/lint/ validate/render/doctor/add_block), a playbook -> CSS style bridge, and vendored HyperFrames Layer 3 skills from commit d291358, pinned via PROVENANCE.md for future re-sync. Final_review now records render_runtime_used and runtime_swap_detected so compose lies are catchable after the fact.
This commit is contained in:
@@ -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 sub-composition 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 `data-composition-src` 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-composition-id` (must match the block's internal composition ID), `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