docs: restructure README with skills-first quick start, demo GIF, catalog, and fix pnpm refs (#277)

## What

Restructures the README to lead with skills-first onboarding, adds a demo GIF, surfaces the catalog, fixes incorrect pnpm references in contributing docs, and corrects the HTML example to use actual attribute names.

## Why

The README told a CLI-first story while the homepage (hyperframes.heygen.com) tells an AI-agent-first story. For a project that brands itself "built for agents," the GitHub landing page should match. Additionally, 50+ catalog blocks were invisible from GitHub, the player and shader-transitions packages were missing from the packages table, and the contributing docs referenced pnpm while the repo uses bun.

## How

**README changes:**
- Quick Start restructured: skills install as Option 1 (recommended), manual CLI as Option 2
- Added demo GIF rendered with HyperFrames itself (HTML + GSAP composition → MP4 → GIF)
- Added Catalog section with install examples and link
- Added `@hyperframes/player` and `@hyperframes/shader-transitions` to packages table
- Added npm downloads badge
- Fixed HTML example: `data-track` → `data-track-index`, added missing `class="clip"` on img
- Condensed Skills section into a concise table
- Documentation link now points to `/introduction` (Mintlify docs) instead of the landing page

**testing-local-changes.mdx:**
- All `pnpm` references replaced with `bun` (14 occurrences)
- Path references updated from `hyperframes-oss` to `hyperframes`

## Test plan

- [ ] Verify README renders correctly on GitHub (logo, badges, GIF, tables, code blocks)
- [ ] Verify GIF loops and is readable at GitHub's default README width
- [ ] Verify all links resolve (docs site, catalog, packages, contributing)
- [ ] Read through testing-local-changes.mdx for any remaining pnpm references
- [x] Documentation updated (if applicable)
This commit is contained in:
James Russo
2026-04-14 19:10:44 -07:00
committed by GitHub
parent d3f2295d80
commit cd17074f3b
5 changed files with 602 additions and 80 deletions
+78 -57
View File
@@ -8,40 +8,54 @@
<p align="center">
<a href="https://www.npmjs.com/package/hyperframes"><img src="https://img.shields.io/npm/v/hyperframes.svg?style=flat" alt="npm version"></a>
<a href="https://www.npmjs.com/package/hyperframes"><img src="https://img.shields.io/npm/dm/hyperframes.svg?style=flat" alt="npm downloads"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue.svg" alt="License"></a>
<a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%3E%3D22-brightgreen" alt="Node.js"></a>
</p>
**Write HTML. Render video. Built for agents.**
<p align="center"><b>Write HTML. Render video. Built for agents.</b></p>
Hyperframes is an open-source video rendering framework that lets you create, preview, and render HTML-based video compositions — with first-class support for AI agents via MCP.
<p align="center">
<img src="docs/images/readme-demo.gif" alt="HyperFrames demo — HTML code on the left transforms into a rendered video on the right" width="800">
</p>
## Why Hyperframes?
- **HTML-native** — AI agents already speak HTML. No React required.
- **Frame Adapter pattern** — bring your own animation runtime (GSAP, Lottie, CSS, Three.js).
- **Deterministic rendering** — same input = identical output. Built for automated pipelines.
- **AI-first design** — not a bolted-on afterthought.
Hyperframes is an open-source video rendering framework that lets you create, preview, and render HTML-based video compositions — with first-class support for AI agents.
## Quick Start
### Option 1: With an AI coding agent (recommended)
Install the HyperFrames skills, then describe the video you want:
```bash
npx skills add heygen-com/hyperframes
```
This teaches your agent (Claude Code, Cursor, Gemini CLI, Codex) how to write correct compositions and GSAP animations. Then just prompt it:
> "Create a 10-second product intro video with a fade-in title, a background video, and background music"
The agent handles scaffolding, animation, and rendering.
### Option 2: Start a project manually
```bash
npx hyperframes init my-video
cd my-video
```
Then open the project with your AI coding agent (Claude Code, Cursor, etc.) — it has HyperFrames skills installed and knows how to create and edit compositions.
```bash
npx hyperframes preview # preview in browser (live reload)
npx hyperframes render # render to MP4
npx hyperframes render # render to MP4
```
`hyperframes init` installs skills automatically, so you can hand off to your AI agent at any point.
**Requirements:** Node.js >= 22, FFmpeg
## Documentation
## Why Hyperframes?
Full documentation at **[hyperframes.heygen.com](https://hyperframes.heygen.com)** — start with the [Quickstart](https://hyperframes.heygen.com/quickstart), then explore guides, concepts, API reference, and package docs.
- **HTML-native** — compositions are HTML files with data attributes. No React, no proprietary DSL.
- **AI-first** — agents already speak HTML. The CLI is non-interactive by default, designed for agent-driven workflows.
- **Deterministic rendering** — same input = identical output. Built for automated pipelines.
- **Frame Adapter pattern** — bring your own animation runtime (GSAP, Lottie, CSS, Three.js).
## How It Works
@@ -53,73 +67,80 @@ Define your video as HTML with data attributes:
id="clip-1"
data-start="0"
data-duration="5"
data-track="0"
data-track-index="0"
src="intro.mp4"
muted
playsinline
></video>
<img id="overlay" data-start="2" data-duration="3" data-track="1" src="logo.png" />
<img
id="overlay"
class="clip"
data-start="2"
data-duration="3"
data-track-index="1"
src="logo.png"
/>
<audio
id="bg-music"
data-start="0"
data-duration="9"
data-track="2"
data-track-index="2"
data-volume="0.5"
src="music.wav"
></audio>
</div>
```
Preview instantly in the browser. Render to MP4 locally. Let AI agents compose videos using tools they already understand.
Preview instantly in the browser. Render to MP4 locally or in Docker.
## Catalog
50+ ready-to-use blocks and components — social overlays, shader transitions, data visualizations, and cinematic effects:
```bash
npx hyperframes add flash-through-white # shader transition
npx hyperframes add instagram-follow # social overlay
npx hyperframes add data-chart # animated chart
```
Browse the full catalog at **[hyperframes.heygen.com/catalog](https://hyperframes.heygen.com/catalog/blocks/data-chart)**.
## Documentation
Full documentation at **[hyperframes.heygen.com/introduction](https://hyperframes.heygen.com/introduction)** — [Quickstart](https://hyperframes.heygen.com/quickstart) | [Guides](https://hyperframes.heygen.com/guides/gsap-animation) | [API Reference](https://hyperframes.heygen.com/packages/core) | [Catalog](https://hyperframes.heygen.com/catalog/blocks/data-chart)
## Packages
| Package | Description |
| -------------------------------------------- | ----------------------------------------------------------- |
| [`hyperframes`](packages/cli) | CLI — create, preview, lint, and render compositions |
| [`@hyperframes/core`](packages/core) | Types, parsers, generators, linter, runtime, frame adapters |
| [`@hyperframes/engine`](packages/engine) | Seekable page-to-video capture engine (Puppeteer + FFmpeg) |
| [`@hyperframes/producer`](packages/producer) | Full rendering pipeline (capture + encode + audio mix) |
| [`@hyperframes/studio`](packages/studio) | Browser-based composition editor UI |
| Package | Description |
| ---------------------------------------------------------------- | ----------------------------------------------------------- |
| [`hyperframes`](packages/cli) | CLI — create, preview, lint, and render compositions |
| [`@hyperframes/core`](packages/core) | Types, parsers, generators, linter, runtime, frame adapters |
| [`@hyperframes/engine`](packages/engine) | Seekable page-to-video capture engine (Puppeteer + FFmpeg) |
| [`@hyperframes/producer`](packages/producer) | Full rendering pipeline (capture + encode + audio mix) |
| [`@hyperframes/studio`](packages/studio) | Browser-based composition editor UI |
| [`@hyperframes/player`](packages/player) | Embeddable `<hyperframes-player>` web component |
| [`@hyperframes/shader-transitions`](packages/shader-transitions) | WebGL shader transitions for compositions |
## AI Agent Skills
## Skills
HyperFrames ships skills that teach AI coding agents (Claude Code, Gemini CLI, Codex, Cursor) how to write correct compositions and GSAP animations. **Use these instead of writing from scratch — they encode framework-specific patterns that generic docs don't cover.**
### Install via CLI (recommended)
HyperFrames ships [skills](https://github.com/vercel-labs/skills) that teach AI agents framework-specific patterns that generic docs don't cover.
```bash
# Install all skills (HyperFrames + GSAP) — runs automatically during `hyperframes init`
npx hyperframes skills
# Or install to a specific agent
npx hyperframes skills --claude
npx hyperframes skills --cursor
npx skills add heygen-com/hyperframes # HyperFrames skills
npx skills add greensock/gsap-skills # GSAP animation skills
```
### Or via `npx skills add`
```bash
# HyperFrames skills (hyperframes-compose, hyperframes-captions)
npx skills add heygen-com/hyperframes
# GSAP skills (gsap-core, gsap-timeline, gsap-scrolltrigger, gsap-plugins, gsap-performance, gsap-utils, gsap-react, gsap-frameworks)
npx skills add greensock/gsap-skills
```
### Installed Skills
| 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.
| Skill | What it teaches |
| ------------------------------------------------- | ---------------------------------------------------------------------- |
| `hyperframes-compose` | HTML composition structure, `data-*` attributes, timeline registration |
| `hyperframes-captions` | Caption/subtitle authoring and transcript integration |
| `hyperframes-registry` | Block and component installation via `hyperframes add` |
| `gsap-core`, `gsap-timeline`, `gsap-plugins`, ... | GSAP animation API, sequencing, ScrollTrigger, performance |
## Contributing
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines on how to contribute.
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
## License
See [LICENSE](LICENSE) for details.
[Apache 2.0](LICENSE)
+19 -23
View File
@@ -11,26 +11,25 @@ Build the monorepo first. Every time you change source files, rebuild before tes
```bash
# From the monorepo root
pnpm build
bun run build
```
## Option 1: pnpm link (recommended)
## Option 1: bun link (recommended)
`pnpm link --global` makes the `hyperframes` binary in your `$PATH` point at your local build. It survives across terminal sessions and auto-picks up new builds without re-linking.
`bun link` makes the `hyperframes` binary in your `$PATH` point at your local build. It survives across terminal sessions and auto-picks up new builds without re-linking.
```bash
# If you previously installed hyperframes globally, remove it first —
# a global install takes priority over pnpm link and shadows your local build.
pnpm remove -g hyperframes 2>/dev/null || npm uninstall -g hyperframes 2>/dev/null
# a global install takes priority over bun link and shadows your local build.
npm uninstall -g hyperframes 2>/dev/null
# Link your local build
cd packages/cli
pnpm link --global
bun link
# Verify — should print your local version AND point to the monorepo
hyperframes --version
which hyperframes
# The path should contain your monorepo, NOT pnpm/global/.pnpm/hyperframes@...
```
Now use `hyperframes` normally in any directory:
@@ -40,12 +39,12 @@ cd ~/my-video-project
hyperframes preview .
```
**After every `pnpm build`** the linked binary is already up to date — no re-linking needed.
**After every `bun run build`** the linked binary is already up to date — no re-linking needed.
To restore the published release when you're done:
```bash
pnpm unlink --global hyperframes
bun unlink hyperframes
npm install -g hyperframes@latest
```
@@ -55,13 +54,13 @@ If you don't want to touch your global `$PATH`, add a shell alias or call `node`
```bash
# Temporary alias for your current shell session
alias hyperframes="node /path/to/hyperframes-oss/packages/cli/dist/cli.js"
alias hyperframes="node /path/to/hyperframes/packages/cli/dist/cli.js"
# Or invoke directly
node /path/to/hyperframes-oss/packages/cli/dist/cli.js preview .
node /path/to/hyperframes/packages/cli/dist/cli.js preview .
```
Replace `/path/to/hyperframes-oss` with your actual monorepo path.
Replace `/path/to/hyperframes` with your actual monorepo path.
## Option 3: npm pack (test the exact published artifact)
@@ -74,9 +73,9 @@ npm pack
# Test it in an isolated directory
mkdir /tmp/pack-test && cd /tmp/pack-test
npx /path/to/hyperframes-oss/packages/cli/hyperframes-<version>.tgz init my-video
npx /path/to/hyperframes/packages/cli/hyperframes-<version>.tgz init my-video
cd my-video
npx /path/to/hyperframes-oss/packages/cli/hyperframes-<version>.tgz preview .
npx /path/to/hyperframes/packages/cli/hyperframes-<version>.tgz preview .
```
## Testing the fix branches
@@ -105,26 +104,23 @@ Common test scenarios:
## Troubleshooting
**Changes not reflected after `pnpm build`**
**Changes not reflected after `bun run build`**
The CLI binary is a single bundled file at `packages/cli/dist/cli.js`. If your change is in `@hyperframes/core` or another workspace package, make sure `pnpm build` rebuilt _all_ packages — the CLI bundles its dependencies at build time.
The CLI binary is a single bundled file at `packages/cli/dist/cli.js`. If your change is in `@hyperframes/core` or another workspace package, make sure `bun run build` rebuilt _all_ packages — the CLI bundles its dependencies at build time.
**`hyperframes` still shows the old version / old UI**
A globally installed `hyperframes` package shadows `pnpm link`. Check which binary is active:
A globally installed `hyperframes` package shadows `bun link`. Check which binary is active:
```bash
which hyperframes
# BAD: /Users/you/Library/pnpm/hyperframes → pnpm/global/.pnpm/hyperframes@0.x.x/...
# GOOD: /Users/you/Library/pnpm/hyperframes → your-monorepo/packages/cli/dist/cli.js
```
If it points to the global store, remove the global install and re-link:
If it points to a global store rather than your monorepo, remove the global install and re-link:
```bash
pnpm remove -g hyperframes
npm uninstall -g hyperframes # in case it was installed via npm
cd packages/cli && pnpm link --global
npm uninstall -g hyperframes
cd packages/cli && bun link
```
**Port already in use**
+505
View File
@@ -0,0 +1,505 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=1920, height=1080" />
<title>HyperFrames README Demo</title>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600&display=block"
rel="stylesheet"
/>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
margin: 0;
width: 1920px;
height: 1080px;
overflow: hidden;
background: #0a0a0f;
font-family: "Inter", -apple-system, sans-serif;
color: #fff;
}
#root {
width: 1920px;
height: 1080px;
position: relative;
overflow: hidden;
}
/* ── Subtle grid background ── */
.bg-grid {
position: absolute;
inset: 0;
background-image:
linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
background-size: 60px 60px;
opacity: 0;
}
/* ── Gradient accent orbs ── */
.accent-orb {
position: absolute;
width: 800px;
height: 800px;
border-radius: 50%;
filter: blur(120px);
opacity: 0;
}
.orb-1 {
background: radial-gradient(circle, rgba(116, 225, 185, 0.25), transparent 70%);
top: -200px;
right: -100px;
}
.orb-2 {
background: radial-gradient(circle, rgba(106, 220, 255, 0.2), transparent 70%);
bottom: -300px;
left: -100px;
}
/* ── Code panel ── */
.code-panel {
position: absolute;
top: 100px;
left: 80px;
width: 840px;
height: 640px;
background: rgba(20, 20, 30, 0.9);
border: 1px solid rgba(255,255,255,0.08);
border-radius: 16px;
padding: 28px 32px;
opacity: 0;
overflow: hidden;
}
.code-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 20px;
}
.code-dot { width: 12px; height: 12px; border-radius: 50%; }
.code-dot:nth-child(1) { background: #ff5f57; }
.code-dot:nth-child(2) { background: #febc2e; }
.code-dot:nth-child(3) { background: #28c840; }
.code-filename {
font-family: "JetBrains Mono", monospace;
font-size: 14px;
color: rgba(255,255,255,0.4);
margin-left: 12px;
}
.code-content {
font-family: "JetBrains Mono", monospace;
font-size: 18px;
line-height: 1.7;
white-space: pre;
}
.code-line { display: block; opacity: 0; }
.c-tag { color: #7dd3fc; }
.c-attr { color: #c084fc; }
.c-val { color: #86efac; }
.c-str { color: #fbbf24; }
.c-cmt { color: rgba(255,255,255,0.3); font-style: italic; }
/* ── Output panel ── */
.output-panel {
position: absolute;
top: 100px;
right: 80px;
width: 840px;
height: 640px;
border-radius: 16px;
overflow: hidden;
opacity: 0;
border: 1px solid rgba(255,255,255,0.08);
}
.output-label {
position: absolute;
top: 14px;
right: 18px;
font-size: 12px;
font-weight: 500;
color: rgba(255,255,255,0.25);
text-transform: uppercase;
letter-spacing: 2px;
z-index: 10;
}
.preview-stage {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
}
.preview-content { text-align: center; }
.preview-title {
font-size: 64px;
font-weight: 800;
line-height: 1.2;
opacity: 0;
}
.preview-title .line-1 { display: block; color: #fff; }
.preview-title .line-2 { display: block; color: #74e1b9; font-size: 72px; }
.preview-subtitle {
font-size: 22px;
color: rgba(255,255,255,0.5);
margin-top: 16px;
opacity: 0;
}
.preview-btn {
margin-top: 28px;
padding: 14px 36px;
background: linear-gradient(135deg, #74e1b9, #6adcff);
border-radius: 30px;
font-size: 18px;
font-weight: 600;
color: #0a0a0f;
opacity: 0;
display: inline-block;
}
/* ── Arrow ── */
.arrow {
position: absolute;
top: 395px;
left: 938px;
width: 44px;
height: 44px;
opacity: 0;
}
/* ── Showcase strip ── */
.showcase-strip {
position: absolute;
bottom: 50px;
left: 0;
right: 0;
height: 170px;
display: flex;
justify-content: center;
gap: 20px;
opacity: 0;
}
.showcase-card {
width: 240px;
height: 150px;
border-radius: 12px;
overflow: hidden;
opacity: 0;
transform: translateY(30px);
border: 1px solid rgba(255,255,255,0.1);
position: relative;
}
.card-label {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 8px 12px;
background: linear-gradient(transparent, rgba(0,0,0,0.85));
font-size: 12px;
font-weight: 500;
color: rgba(255,255,255,0.8);
}
/* Mini chart */
.mini-chart {
padding: 20px 16px;
background: #faf9f6;
height: 100%;
display: flex;
align-items: flex-end;
gap: 8px;
padding-bottom: 36px;
}
.mini-bar {
flex: 1;
background: #2d2d2d;
border-radius: 3px 3px 0 0;
transform-origin: bottom;
}
/* Mini social */
.mini-social {
background: #1a1a2e;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
}
.mini-tweet {
background: rgba(255,255,255,0.06);
border-radius: 12px;
padding: 12px 14px;
width: 100%;
}
.mini-tweet-header {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
}
.mini-avatar {
width: 22px;
height: 22px;
border-radius: 50%;
background: linear-gradient(135deg, #74e1b9, #6adcff);
}
.mini-name { font-size: 11px; font-weight: 600; }
.mini-handle { font-size: 10px; color: rgba(255,255,255,0.4); margin-left: 4px; }
.mini-text { font-size: 10px; color: rgba(255,255,255,0.6); line-height: 1.4; }
/* Mini transition */
.mini-transition { height: 100%; position: relative; }
.mini-transition .half-a {
position: absolute; inset: 0;
background: linear-gradient(135deg, #667eea, #764ba2);
}
.mini-transition .half-b {
position: absolute; inset: 0;
background: linear-gradient(135deg, #f093fb, #f5576c);
clip-path: circle(0% at 50% 50%);
}
/* Mini kinetic */
.mini-kinetic {
background: #0a0a0f;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.mini-kinetic-text {
font-size: 28px;
font-weight: 900;
text-transform: uppercase;
letter-spacing: 4px;
opacity: 0;
}
/* Mini app */
.mini-app {
background: linear-gradient(135deg, #e8e4d9, #d4cfbf);
height: 100%;
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
}
.mini-phone {
width: 36px;
height: 64px;
background: #1a1a2e;
border-radius: 6px;
border: 1px solid rgba(255,255,255,0.1);
opacity: 0;
transform: translateY(20px);
}
/* ── Tagline ── */
.tagline {
position: absolute;
bottom: 24px;
left: 0;
right: 0;
text-align: center;
font-size: 18px;
color: rgba(255,255,255,0.25);
letter-spacing: 3px;
text-transform: uppercase;
opacity: 0;
}
.tagline span { color: #74e1b9; font-weight: 600; }
</style>
</head>
<body>
<div id="root" data-composition-id="readme-demo" data-start="0" data-duration="5.5" data-width="1920" data-height="1080">
<div class="bg-grid" id="bg-grid"></div>
<div class="accent-orb orb-1" id="orb-1"></div>
<div class="accent-orb orb-2" id="orb-2"></div>
<!-- Code panel -->
<div class="code-panel" id="code-panel">
<div class="code-header">
<div class="code-dot"></div>
<div class="code-dot"></div>
<div class="code-dot"></div>
<span class="code-filename">index.html</span>
</div>
<div class="code-content">
<span class="code-line" id="cl-1"><span class="c-tag">&lt;div</span> <span class="c-attr">data-composition-id</span>=<span class="c-val">"hero"</span><span class="c-tag">&gt;</span></span>
<span class="code-line" id="cl-2"></span>
<span class="code-line" id="cl-3"> <span class="c-tag">&lt;h1</span> <span class="c-attr">class</span>=<span class="c-val">"clip"</span></span>
<span class="code-line" id="cl-4"> <span class="c-attr">data-start</span>=<span class="c-val">"0"</span> <span class="c-attr">data-duration</span>=<span class="c-val">"5"</span><span class="c-tag">&gt;</span></span>
<span class="code-line" id="cl-5"> Launch Day</span>
<span class="code-line" id="cl-6"> <span class="c-tag">&lt;/h1&gt;</span></span>
<span class="code-line" id="cl-7"></span>
<span class="code-line" id="cl-8"> <span class="c-tag">&lt;p</span> <span class="c-attr">class</span>=<span class="c-val">"clip"</span></span>
<span class="code-line" id="cl-9"> <span class="c-attr">data-start</span>=<span class="c-val">"0.8"</span> <span class="c-attr">data-duration</span>=<span class="c-val">"4"</span><span class="c-tag">&gt;</span></span>
<span class="code-line" id="cl-10"> The future of video</span>
<span class="code-line" id="cl-11"> <span class="c-tag">&lt;/p&gt;</span></span>
<span class="code-line" id="cl-12"></span>
<span class="code-line" id="cl-13"> <span class="c-cmt">&lt;!-- GSAP handles animation --&gt;</span></span>
<span class="code-line" id="cl-14"> <span class="c-tag">&lt;script&gt;</span></span>
<span class="code-line" id="cl-15"> tl.<span class="c-attr">from</span>(<span class="c-str">"h1"</span>, {<span class="c-attr">y</span>: <span class="c-val">-60</span>, <span class="c-attr">opacity</span>: <span class="c-val">0</span>})</span>
<span class="code-line" id="cl-16"> tl.<span class="c-attr">from</span>(<span class="c-str">"p"</span>, {<span class="c-attr">y</span>: <span class="c-val">40</span>, <span class="c-attr">opacity</span>: <span class="c-val">0</span>})</span>
<span class="code-line" id="cl-17"> <span class="c-tag">&lt;/script&gt;</span></span>
<span class="code-line" id="cl-18"><span class="c-tag">&lt;/div&gt;</span></span>
</div>
</div>
<!-- Arrow -->
<div class="arrow" id="arrow">
<svg viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 22h28M28 14l8 8-8 8" stroke="#74e1b9" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<!-- Output panel -->
<div class="output-panel" id="output-panel">
<span class="output-label">rendered output</span>
<div class="preview-stage">
<div class="preview-content">
<div class="preview-title" id="preview-title">
<span class="line-1">Launch Day</span>
<span class="line-2">is here.</span>
</div>
<p class="preview-subtitle" id="preview-subtitle">The future of video</p>
<div class="preview-btn" id="preview-btn">Get started</div>
</div>
</div>
</div>
<!-- Showcase strip -->
<div class="showcase-strip" id="showcase-strip">
<div class="showcase-card" id="sc-1">
<div class="mini-chart">
<div class="mini-bar" style="height: 35%"></div>
<div class="mini-bar" style="height: 60%"></div>
<div class="mini-bar" style="height: 85%"></div>
<div class="mini-bar" style="height: 50%"></div>
<div class="mini-bar" style="height: 95%"></div>
<div class="mini-bar" style="height: 72%"></div>
</div>
<div class="card-label">Data Charts</div>
</div>
<div class="showcase-card" id="sc-2">
<div class="mini-social">
<div class="mini-tweet">
<div class="mini-tweet-header">
<div class="mini-avatar"></div>
<span class="mini-name">HyperFrames</span>
<span class="mini-handle">@hyperframes</span>
</div>
<div class="mini-text">Write HTML. Render video.</div>
</div>
</div>
<div class="card-label">Social Overlays</div>
</div>
<div class="showcase-card" id="sc-3">
<div class="mini-transition">
<div class="half-a"></div>
<div class="half-b" id="transition-b"></div>
</div>
<div class="card-label">Shader Transitions</div>
</div>
<div class="showcase-card" id="sc-4">
<div class="mini-kinetic">
<span class="mini-kinetic-text" id="kinetic-text">BOLD</span>
</div>
<div class="card-label">Kinetic Type</div>
</div>
<div class="showcase-card" id="sc-5">
<div class="mini-app">
<div class="mini-phone" id="phone-1"></div>
<div class="mini-phone" id="phone-2" style="height: 72px; width: 40px"></div>
<div class="mini-phone" id="phone-3"></div>
</div>
<div class="card-label">App Showcases</div>
</div>
</div>
<!-- Tagline -->
<div class="tagline" id="tagline">
Write HTML &middot; Render Video &middot; <span>Built for agents</span>
</div>
</div>
<script>
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
// Background
tl.to("#bg-grid", { opacity: 1, duration: 0.8 }, 0);
tl.to("#orb-1", { opacity: 1, duration: 1.2 }, 0.2);
tl.to("#orb-2", { opacity: 1, duration: 1.2 }, 0.4);
// Code panel slides in
tl.fromTo("#code-panel",
{ opacity: 0, x: -40 },
{ opacity: 1, x: 0, duration: 0.6, ease: "power2.out" }, 0.3);
// Code lines type in
const lines = [];
for (let i = 1; i <= 18; i++) lines.push("#cl-" + i);
tl.to(lines.join(","), {
opacity: 1, duration: 0.06, stagger: 0.055, ease: "none"
}, 0.5);
// Arrow
tl.to("#arrow", { opacity: 1, duration: 0.3 }, 1.5);
// Output panel slides in
tl.fromTo("#output-panel",
{ opacity: 0, x: 40 },
{ opacity: 1, x: 0, duration: 0.6, ease: "power2.out" }, 1.3);
// Preview content animates — mirrors what the code would render
tl.fromTo("#preview-title",
{ opacity: 0, y: -60 },
{ opacity: 1, y: 0, duration: 0.7, ease: "power3.out" }, 1.7);
tl.fromTo("#preview-subtitle",
{ opacity: 0, y: 40 },
{ opacity: 1, y: 0, duration: 0.5, ease: "power2.out" }, 2.1);
tl.fromTo("#preview-btn",
{ opacity: 0, scale: 0.8 },
{ opacity: 1, scale: 1, duration: 0.4, ease: "back.out(2)" }, 2.4);
// Showcase strip
tl.to("#showcase-strip", { opacity: 1, duration: 0.4 }, 3.0);
tl.to(["#sc-1","#sc-2","#sc-3","#sc-4","#sc-5"].join(","), {
opacity: 1, y: 0, duration: 0.4, stagger: 0.1, ease: "power2.out"
}, 3.2);
// Mini card animations
tl.fromTo("#sc-1 .mini-bar",
{ scaleY: 0 },
{ scaleY: 1, duration: 0.5, stagger: 0.05, ease: "power2.out" }, 3.4);
tl.to("#transition-b",
{ clipPath: "circle(75% at 50% 50%)", duration: 1.0, ease: "power2.inOut" }, 3.5);
tl.fromTo("#kinetic-text",
{ opacity: 0, scale: 3 },
{ opacity: 1, scale: 1, duration: 0.3, ease: "power4.out" }, 3.6);
tl.to(["#phone-1","#phone-2","#phone-3"].join(","), {
opacity: 1, y: 0, duration: 0.4, stagger: 0.08, ease: "power2.out"
}, 3.5);
// Tagline
tl.to("#tagline", { opacity: 1, duration: 0.6 }, 4.0);
// Hold
tl.set({}, {}, 5.5);
window.__timelines["readme-demo"] = tl;
</script>
</body>
</html>
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.