[object Object]

← back to Rentv Promos

RENTV: 4 HyperFrames promo videos (brand/deals/review/daily), cloned-voice narration

86470bbe470caa4c20965d70f317b82cb6aca686 · 2026-07-22 07:12:07 -0700 · Steve Abrams

Files touched

Diff

commit 86470bbe470caa4c20965d70f317b82cb6aca686
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 22 07:12:07 2026 -0700

    RENTV: 4 HyperFrames promo videos (brand/deals/review/daily), cloned-voice narration
---
 .gitignore                         |  11 ++++
 videos/brand/.media/narration.mp3  | Bin 0 -> 231593 bytes
 videos/brand/AGENTS.md             |  93 ++++++++++++++++++++++++++++++++
 videos/brand/CLAUDE.md             |  93 ++++++++++++++++++++++++++++++++
 videos/brand/hyperframes.json      |  12 +++++
 videos/brand/index.html            |  99 ++++++++++++++++++++++++++++++++++
 videos/brand/meta.json             |   5 ++
 videos/brand/package.json          |  11 ++++
 videos/daily/.media/narration.mp3  | Bin 0 -> 188125 bytes
 videos/daily/AGENTS.md             |  93 ++++++++++++++++++++++++++++++++
 videos/daily/CLAUDE.md             |  93 ++++++++++++++++++++++++++++++++
 videos/daily/hyperframes.json      |  12 +++++
 videos/daily/index.html            |  79 +++++++++++++++++++++++++++
 videos/daily/meta.json             |   5 ++
 videos/daily/package.json          |  11 ++++
 videos/deals/.media/narration.mp3  | Bin 0 -> 295123 bytes
 videos/deals/AGENTS.md             |  93 ++++++++++++++++++++++++++++++++
 videos/deals/CLAUDE.md             |  93 ++++++++++++++++++++++++++++++++
 videos/deals/hyperframes.json      |  12 +++++
 videos/deals/index.html            | 107 +++++++++++++++++++++++++++++++++++++
 videos/deals/meta.json             |   5 ++
 videos/deals/package.json          |  11 ++++
 videos/review/.media/narration.mp3 | Bin 0 -> 278822 bytes
 videos/review/AGENTS.md            |  93 ++++++++++++++++++++++++++++++++
 videos/review/CLAUDE.md            |  93 ++++++++++++++++++++++++++++++++
 videos/review/hyperframes.json     |  12 +++++
 videos/review/index.html           |  82 ++++++++++++++++++++++++++++
 videos/review/meta.json            |   5 ++
 videos/review/package.json         |  11 ++++
 29 files changed, 1234 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e591cb0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,11 @@
+node_modules/
+.env*
+tmp/
+*.log
+.DS_Store
+dist/
+build/
+.next/
+**/renders/
+**/.media/*.wav
+**/.cache/
diff --git a/videos/brand/.media/narration.mp3 b/videos/brand/.media/narration.mp3
new file mode 100644
index 0000000..0a49dda
Binary files /dev/null and b/videos/brand/.media/narration.mp3 differ
diff --git a/videos/brand/AGENTS.md b/videos/brand/AGENTS.md
new file mode 100644
index 0000000..a63562c
--- /dev/null
+++ b/videos/brand/AGENTS.md
@@ -0,0 +1,93 @@
+# HyperFrames Composition Project
+
+## Skills — USE THESE FIRST
+
+**Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
+
+**Doing anything with HyperFrames?** Start at `/hyperframes` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), confirms your brief up front (the intent layer), and routes every "make me a…" request (a video, a deck, a composition port) to the right workflow. Read it first, especially when there's no project context to orient you. The workflows it routes to:
+
+- `/product-launch-video` — any **website** URL or brief / script → a product launch / SaaS / promo video, or a site tour / showcase featuring the site's own captured visuals.
+- `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
+- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
+- `/talking-head-recut` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
+- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
+- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
+- `/music-to-video` — a **music track** (audio file, or video to pull audio from) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
+- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
+- `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition) and the home of **companion mode** — co-create with the full HyperFrames toolbox; the original hyperframes authoring flow, any length.
+
+**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
+
+The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-keyframes`, `/hyperframes-creative`, `/hyperframes-cli`, `/media-use`, `/hyperframes-registry`, `/figma`) and the full capability map live inside `/hyperframes` — it is the single source of truth for which skill handles which intent.
+
+> **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
+
+> **Skill missing or stale?** Run `npx hyperframes skills update <name>` to install/refresh
+> the specific skill you need (the `/hyperframes` router does this automatically before
+> entering a workflow), or bare `npx hyperframes skills update` to refresh the core set plus
+> everything already installed — neither pulls the full set. Restart the agent session so
+> newly installed skills load.
+
+## Commands
+
+```bash
+npm run dev          # start the preview server (long-running — keep it alive in background)
+npm run check        # lint + runtime + layout + motion + contrast (one command)
+npm run render       # render to MP4
+npm run publish      # publish and get a shareable link
+npx hyperframes lint --verbose  # include info-level findings
+npx hyperframes lint --json     # machine-readable output for CI
+npx hyperframes docs <topic> # reference docs in terminal
+```
+
+> **`npm run dev` is a long-running server, not a one-shot command.** It blocks until stopped.
+> In Claude Code, always run it with `run_in_background: true`. Never run it as a foreground
+> command — it will time out and the server will die, breaking the browser preview.
+
+> **Pinned CLI version.** These scripts pin an exact `hyperframes@X.Y.Z` so this project re-renders identically over time. Weeks later that pin lags fixes shipped since. To move up: `npx hyperframes@latest upgrade --project . --check` (shows the delta), then `npx hyperframes@latest upgrade --project .` to rewrite the pins. Always unpinned — the pinned script re-runs the old version against itself.
+
+## Documentation
+
+**For quick reference**, use the local CLI docs command (no network required):
+
+```bash
+npx hyperframes docs <topic>
+```
+
+Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
+
+**For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
+
+```
+https://hyperframes.heygen.com/llms.txt
+```
+
+## Project Structure
+
+- `index.html` — main composition (root timeline)
+- `compositions/` — sub-compositions referenced via `data-composition-src`
+- `meta.json` — project metadata (id, name)
+- `transcript.json` — whisper word-level transcript (if generated)
+
+## Linting — ALWAYS RUN AFTER CHANGES
+
+After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
+
+```bash
+npm run check
+```
+
+Fix all errors before presenting the result. Warnings should be reviewed before rendering.
+
+## Key Rules
+
+1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
+2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
+3. Timelines must be paused and registered on `window.__timelines`:
+   ```js
+   window.__timelines = window.__timelines || {};
+   window.__timelines["composition-id"] = gsap.timeline({ paused: true });
+   ```
+4. Videos use `muted` with a separate `<audio>` element for the audio track
+5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
+6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
diff --git a/videos/brand/CLAUDE.md b/videos/brand/CLAUDE.md
new file mode 100644
index 0000000..a63562c
--- /dev/null
+++ b/videos/brand/CLAUDE.md
@@ -0,0 +1,93 @@
+# HyperFrames Composition Project
+
+## Skills — USE THESE FIRST
+
+**Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
+
+**Doing anything with HyperFrames?** Start at `/hyperframes` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), confirms your brief up front (the intent layer), and routes every "make me a…" request (a video, a deck, a composition port) to the right workflow. Read it first, especially when there's no project context to orient you. The workflows it routes to:
+
+- `/product-launch-video` — any **website** URL or brief / script → a product launch / SaaS / promo video, or a site tour / showcase featuring the site's own captured visuals.
+- `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
+- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
+- `/talking-head-recut` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
+- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
+- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
+- `/music-to-video` — a **music track** (audio file, or video to pull audio from) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
+- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
+- `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition) and the home of **companion mode** — co-create with the full HyperFrames toolbox; the original hyperframes authoring flow, any length.
+
+**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
+
+The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-keyframes`, `/hyperframes-creative`, `/hyperframes-cli`, `/media-use`, `/hyperframes-registry`, `/figma`) and the full capability map live inside `/hyperframes` — it is the single source of truth for which skill handles which intent.
+
+> **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
+
+> **Skill missing or stale?** Run `npx hyperframes skills update <name>` to install/refresh
+> the specific skill you need (the `/hyperframes` router does this automatically before
+> entering a workflow), or bare `npx hyperframes skills update` to refresh the core set plus
+> everything already installed — neither pulls the full set. Restart the agent session so
+> newly installed skills load.
+
+## Commands
+
+```bash
+npm run dev          # start the preview server (long-running — keep it alive in background)
+npm run check        # lint + runtime + layout + motion + contrast (one command)
+npm run render       # render to MP4
+npm run publish      # publish and get a shareable link
+npx hyperframes lint --verbose  # include info-level findings
+npx hyperframes lint --json     # machine-readable output for CI
+npx hyperframes docs <topic> # reference docs in terminal
+```
+
+> **`npm run dev` is a long-running server, not a one-shot command.** It blocks until stopped.
+> In Claude Code, always run it with `run_in_background: true`. Never run it as a foreground
+> command — it will time out and the server will die, breaking the browser preview.
+
+> **Pinned CLI version.** These scripts pin an exact `hyperframes@X.Y.Z` so this project re-renders identically over time. Weeks later that pin lags fixes shipped since. To move up: `npx hyperframes@latest upgrade --project . --check` (shows the delta), then `npx hyperframes@latest upgrade --project .` to rewrite the pins. Always unpinned — the pinned script re-runs the old version against itself.
+
+## Documentation
+
+**For quick reference**, use the local CLI docs command (no network required):
+
+```bash
+npx hyperframes docs <topic>
+```
+
+Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
+
+**For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
+
+```
+https://hyperframes.heygen.com/llms.txt
+```
+
+## Project Structure
+
+- `index.html` — main composition (root timeline)
+- `compositions/` — sub-compositions referenced via `data-composition-src`
+- `meta.json` — project metadata (id, name)
+- `transcript.json` — whisper word-level transcript (if generated)
+
+## Linting — ALWAYS RUN AFTER CHANGES
+
+After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
+
+```bash
+npm run check
+```
+
+Fix all errors before presenting the result. Warnings should be reviewed before rendering.
+
+## Key Rules
+
+1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
+2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
+3. Timelines must be paused and registered on `window.__timelines`:
+   ```js
+   window.__timelines = window.__timelines || {};
+   window.__timelines["composition-id"] = gsap.timeline({ paused: true });
+   ```
+4. Videos use `muted` with a separate `<audio>` element for the audio track
+5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
+6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
diff --git a/videos/brand/hyperframes.json b/videos/brand/hyperframes.json
new file mode 100644
index 0000000..dc9ec2e
--- /dev/null
+++ b/videos/brand/hyperframes.json
@@ -0,0 +1,12 @@
+{
+  "$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"
+  },
+  "media": {
+    "autoProxy": true
+  }
+}
diff --git a/videos/brand/index.html b/videos/brand/index.html
new file mode 100644
index 0000000..8939556
--- /dev/null
+++ b/videos/brand/index.html
@@ -0,0 +1,99 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=1920, height=1080" />
+    <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
+    <style>
+      * { margin: 0; padding: 0; box-sizing: border-box; }
+      html, body { width: 1920px; height: 1080px; overflow: hidden; background: #0a0e14; }
+      body { font-family: "Georgia", "Times New Roman", serif; color: #f4f6f8; }
+      .sans { font-family: "Helvetica Neue", Arial, sans-serif; }
+      #root { position: relative; width: 1920px; height: 1080px; overflow: hidden;
+        background: radial-gradient(1400px 900px at 60% 30%, #16202e 0%, #0a0e14 70%); }
+      .scene { position: absolute; inset: 0; display: flex; flex-direction: column;
+        align-items: center; justify-content: center; opacity: 0; }
+      .red { color: #c8102e; }
+      .wordmark { font-weight: 700; letter-spacing: -2px; }
+      .kicker { letter-spacing: 8px; text-transform: uppercase; font-size: 26px; color: #8fa3b8; }
+      .headline { font-size: 96px; line-height: 1.04; text-align: center; max-width: 1500px; font-weight: 700; }
+      #ticker { position: absolute; left: 0; right: 0; bottom: 90px; display: flex; gap: 70px;
+        justify-content: center; }
+      .stat { text-align: center; }
+      .stat .v { font-size: 60px; font-weight: 700; }
+      .stat .l { font-size: 22px; letter-spacing: 3px; color: #8fa3b8; text-transform: uppercase; }
+      .rule { width: 0; height: 3px; background: #c8102e; margin: 26px 0; }
+      .sect { display: flex; gap: 40px; margin-top: 30px; flex-wrap: wrap; justify-content: center; max-width: 1500px; }
+      .sect span { font-family: "Helvetica Neue", Arial, sans-serif; font-size: 30px; letter-spacing: 4px;
+        text-transform: uppercase; color: #b9c6d4; opacity: 0; }
+    </style>
+  </head>
+  <body>
+    <div id="root" data-composition-id="main" data-start="0" data-duration="14.4" data-width="1920" data-height="1080">
+
+      <div id="s1" class="scene clip" data-start="0" data-duration="4" data-track-index="1">
+        <div class="wordmark" style="font-size:180px">REN<span class="red">TV</span><span style="font-size:150px">.com</span></div>
+        <div class="rule" id="s1rule"></div>
+        <div class="kicker sans" id="s1est">Commercial Real Estate &middot; Since 1998</div>
+      </div>
+
+      <div id="s2" class="scene clip" data-start="4" data-duration="4" data-track-index="1">
+        <div class="kicker sans" style="margin-bottom:34px">The Western U.S. Authority</div>
+        <div class="headline">The name commercial real estate <span class="red">trusts.</span></div>
+      </div>
+
+      <div id="s3" class="scene clip" data-start="8" data-duration="3.4" data-track-index="1">
+        <div class="headline" style="font-size:78px">From Los Angeles<br/>to the Mountain West</div>
+        <div class="sect sans">
+          <span>Financing</span><span>Leases</span><span>Development</span><span>Retail</span><span>Multifamily</span><span>Sales</span>
+        </div>
+      </div>
+
+      <div id="s4" class="scene clip" data-start="11.4" data-duration="3" data-track-index="1">
+        <div class="wordmark" style="font-size:150px">REN<span class="red">TV</span><span style="font-size:120px">.com</span></div>
+        <div class="rule" id="s4rule" style="width:220px"></div>
+        <div class="kicker sans" style="letter-spacing:12px; color:#f4f6f8">THE REGIONAL AUTHORITY</div>
+      </div>
+
+      <div id="ticker" class="sans clip" data-start="4" data-duration="7" data-track-index="2">
+        <div id="tickerInner" style="display:flex; gap:70px; justify-content:center; width:100%">
+          <div class="stat"><div class="v">23.1%</div><div class="l">LA Office Vac</div></div>
+          <div class="stat"><div class="v red">5.2%</div><div class="l">IE Industrial Cap</div></div>
+          <div class="stat"><div class="v">$124M</div><div class="l">Latest Deal</div></div>
+        </div>
+      </div>
+
+      <audio id="vo" src=".media/narration.wav" data-start="0" data-duration="14.4" data-track-index="10" data-volume="1"></audio>
+    </div>
+
+    <script>
+      window.__timelines = window.__timelines || {};
+      const tl = gsap.timeline({ paused: true });
+
+      tl.fromTo("#s1", {opacity:0}, {opacity:1, duration:0.6}, 0.1)
+        .from("#s1 .wordmark", {scale:0.86, y:20, filter:"blur(8px)", duration:1.0, ease:"power3.out"}, 0.2)
+        .to("#s1rule", {width:300, duration:0.8, ease:"power2.out"}, 0.9)
+        .from("#s1est", {opacity:0, y:14, duration:0.7}, 1.2)
+        .to("#s1", {opacity:0, duration:0.5}, 3.6);
+
+      tl.fromTo("#s2", {opacity:0}, {opacity:1, duration:0.5}, 4.1)
+        .from("#s2 .headline", {opacity:0, y:40, duration:0.9, ease:"power3.out"}, 4.2)
+        .fromTo("#tickerInner", {opacity:0}, {opacity:1, duration:0.6}, 4.6)
+        .from("#ticker .stat", {opacity:0, y:24, stagger:0.15, duration:0.6}, 4.8)
+        .to("#s2", {opacity:0, duration:0.5}, 7.6);
+
+      tl.fromTo("#s3", {opacity:0}, {opacity:1, duration:0.5}, 8.1)
+        .from("#s3 .headline", {opacity:0, y:36, duration:0.8, ease:"power3.out"}, 8.2)
+        .to("#s3 .sect span", {opacity:1, stagger:0.12, duration:0.4}, 8.9)
+        .to("#s3", {opacity:0, duration:0.5}, 11.0)
+        .to("#tickerInner", {opacity:0, duration:0.5}, 10.9)
+        .set("#tickerInner", {opacity:0}, 11.4);
+
+      tl.fromTo("#s4", {opacity:0}, {opacity:1, duration:0.6}, 11.5)
+        .from("#s4 .wordmark", {scale:0.9, opacity:0, duration:0.9, ease:"power3.out"}, 11.6)
+        .from("#s4 .kicker", {opacity:0, y:12, duration:0.9}, 12.2);
+
+      window.__timelines["main"] = tl;
+    </script>
+  </body>
+</html>
diff --git a/videos/brand/meta.json b/videos/brand/meta.json
new file mode 100644
index 0000000..20379e8
--- /dev/null
+++ b/videos/brand/meta.json
@@ -0,0 +1,5 @@
+{
+  "id": "brand",
+  "name": "brand",
+  "createdAt": "2026-07-22T13:58:19.313Z"
+}
\ No newline at end of file
diff --git a/videos/brand/package.json b/videos/brand/package.json
new file mode 100644
index 0000000..ee4d750
--- /dev/null
+++ b/videos/brand/package.json
@@ -0,0 +1,11 @@
+{
+  "name": "brand",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "npx --yes hyperframes@0.7.68 preview",
+    "check": "npx --yes hyperframes@0.7.68 check",
+    "render": "npx --yes hyperframes@0.7.68 render",
+    "publish": "npx --yes hyperframes@0.7.68 publish"
+  }
+}
diff --git a/videos/daily/.media/narration.mp3 b/videos/daily/.media/narration.mp3
new file mode 100644
index 0000000..f02dc09
Binary files /dev/null and b/videos/daily/.media/narration.mp3 differ
diff --git a/videos/daily/AGENTS.md b/videos/daily/AGENTS.md
new file mode 100644
index 0000000..a63562c
--- /dev/null
+++ b/videos/daily/AGENTS.md
@@ -0,0 +1,93 @@
+# HyperFrames Composition Project
+
+## Skills — USE THESE FIRST
+
+**Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
+
+**Doing anything with HyperFrames?** Start at `/hyperframes` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), confirms your brief up front (the intent layer), and routes every "make me a…" request (a video, a deck, a composition port) to the right workflow. Read it first, especially when there's no project context to orient you. The workflows it routes to:
+
+- `/product-launch-video` — any **website** URL or brief / script → a product launch / SaaS / promo video, or a site tour / showcase featuring the site's own captured visuals.
+- `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
+- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
+- `/talking-head-recut` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
+- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
+- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
+- `/music-to-video` — a **music track** (audio file, or video to pull audio from) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
+- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
+- `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition) and the home of **companion mode** — co-create with the full HyperFrames toolbox; the original hyperframes authoring flow, any length.
+
+**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
+
+The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-keyframes`, `/hyperframes-creative`, `/hyperframes-cli`, `/media-use`, `/hyperframes-registry`, `/figma`) and the full capability map live inside `/hyperframes` — it is the single source of truth for which skill handles which intent.
+
+> **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
+
+> **Skill missing or stale?** Run `npx hyperframes skills update <name>` to install/refresh
+> the specific skill you need (the `/hyperframes` router does this automatically before
+> entering a workflow), or bare `npx hyperframes skills update` to refresh the core set plus
+> everything already installed — neither pulls the full set. Restart the agent session so
+> newly installed skills load.
+
+## Commands
+
+```bash
+npm run dev          # start the preview server (long-running — keep it alive in background)
+npm run check        # lint + runtime + layout + motion + contrast (one command)
+npm run render       # render to MP4
+npm run publish      # publish and get a shareable link
+npx hyperframes lint --verbose  # include info-level findings
+npx hyperframes lint --json     # machine-readable output for CI
+npx hyperframes docs <topic> # reference docs in terminal
+```
+
+> **`npm run dev` is a long-running server, not a one-shot command.** It blocks until stopped.
+> In Claude Code, always run it with `run_in_background: true`. Never run it as a foreground
+> command — it will time out and the server will die, breaking the browser preview.
+
+> **Pinned CLI version.** These scripts pin an exact `hyperframes@X.Y.Z` so this project re-renders identically over time. Weeks later that pin lags fixes shipped since. To move up: `npx hyperframes@latest upgrade --project . --check` (shows the delta), then `npx hyperframes@latest upgrade --project .` to rewrite the pins. Always unpinned — the pinned script re-runs the old version against itself.
+
+## Documentation
+
+**For quick reference**, use the local CLI docs command (no network required):
+
+```bash
+npx hyperframes docs <topic>
+```
+
+Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
+
+**For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
+
+```
+https://hyperframes.heygen.com/llms.txt
+```
+
+## Project Structure
+
+- `index.html` — main composition (root timeline)
+- `compositions/` — sub-compositions referenced via `data-composition-src`
+- `meta.json` — project metadata (id, name)
+- `transcript.json` — whisper word-level transcript (if generated)
+
+## Linting — ALWAYS RUN AFTER CHANGES
+
+After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
+
+```bash
+npm run check
+```
+
+Fix all errors before presenting the result. Warnings should be reviewed before rendering.
+
+## Key Rules
+
+1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
+2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
+3. Timelines must be paused and registered on `window.__timelines`:
+   ```js
+   window.__timelines = window.__timelines || {};
+   window.__timelines["composition-id"] = gsap.timeline({ paused: true });
+   ```
+4. Videos use `muted` with a separate `<audio>` element for the audio track
+5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
+6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
diff --git a/videos/daily/CLAUDE.md b/videos/daily/CLAUDE.md
new file mode 100644
index 0000000..a63562c
--- /dev/null
+++ b/videos/daily/CLAUDE.md
@@ -0,0 +1,93 @@
+# HyperFrames Composition Project
+
+## Skills — USE THESE FIRST
+
+**Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
+
+**Doing anything with HyperFrames?** Start at `/hyperframes` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), confirms your brief up front (the intent layer), and routes every "make me a…" request (a video, a deck, a composition port) to the right workflow. Read it first, especially when there's no project context to orient you. The workflows it routes to:
+
+- `/product-launch-video` — any **website** URL or brief / script → a product launch / SaaS / promo video, or a site tour / showcase featuring the site's own captured visuals.
+- `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
+- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
+- `/talking-head-recut` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
+- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
+- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
+- `/music-to-video` — a **music track** (audio file, or video to pull audio from) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
+- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
+- `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition) and the home of **companion mode** — co-create with the full HyperFrames toolbox; the original hyperframes authoring flow, any length.
+
+**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
+
+The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-keyframes`, `/hyperframes-creative`, `/hyperframes-cli`, `/media-use`, `/hyperframes-registry`, `/figma`) and the full capability map live inside `/hyperframes` — it is the single source of truth for which skill handles which intent.
+
+> **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
+
+> **Skill missing or stale?** Run `npx hyperframes skills update <name>` to install/refresh
+> the specific skill you need (the `/hyperframes` router does this automatically before
+> entering a workflow), or bare `npx hyperframes skills update` to refresh the core set plus
+> everything already installed — neither pulls the full set. Restart the agent session so
+> newly installed skills load.
+
+## Commands
+
+```bash
+npm run dev          # start the preview server (long-running — keep it alive in background)
+npm run check        # lint + runtime + layout + motion + contrast (one command)
+npm run render       # render to MP4
+npm run publish      # publish and get a shareable link
+npx hyperframes lint --verbose  # include info-level findings
+npx hyperframes lint --json     # machine-readable output for CI
+npx hyperframes docs <topic> # reference docs in terminal
+```
+
+> **`npm run dev` is a long-running server, not a one-shot command.** It blocks until stopped.
+> In Claude Code, always run it with `run_in_background: true`. Never run it as a foreground
+> command — it will time out and the server will die, breaking the browser preview.
+
+> **Pinned CLI version.** These scripts pin an exact `hyperframes@X.Y.Z` so this project re-renders identically over time. Weeks later that pin lags fixes shipped since. To move up: `npx hyperframes@latest upgrade --project . --check` (shows the delta), then `npx hyperframes@latest upgrade --project .` to rewrite the pins. Always unpinned — the pinned script re-runs the old version against itself.
+
+## Documentation
+
+**For quick reference**, use the local CLI docs command (no network required):
+
+```bash
+npx hyperframes docs <topic>
+```
+
+Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
+
+**For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
+
+```
+https://hyperframes.heygen.com/llms.txt
+```
+
+## Project Structure
+
+- `index.html` — main composition (root timeline)
+- `compositions/` — sub-compositions referenced via `data-composition-src`
+- `meta.json` — project metadata (id, name)
+- `transcript.json` — whisper word-level transcript (if generated)
+
+## Linting — ALWAYS RUN AFTER CHANGES
+
+After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
+
+```bash
+npm run check
+```
+
+Fix all errors before presenting the result. Warnings should be reviewed before rendering.
+
+## Key Rules
+
+1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
+2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
+3. Timelines must be paused and registered on `window.__timelines`:
+   ```js
+   window.__timelines = window.__timelines || {};
+   window.__timelines["composition-id"] = gsap.timeline({ paused: true });
+   ```
+4. Videos use `muted` with a separate `<audio>` element for the audio track
+5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
+6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
diff --git a/videos/daily/hyperframes.json b/videos/daily/hyperframes.json
new file mode 100644
index 0000000..dc9ec2e
--- /dev/null
+++ b/videos/daily/hyperframes.json
@@ -0,0 +1,12 @@
+{
+  "$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"
+  },
+  "media": {
+    "autoProxy": true
+  }
+}
diff --git a/videos/daily/index.html b/videos/daily/index.html
new file mode 100644
index 0000000..dc6d793
--- /dev/null
+++ b/videos/daily/index.html
@@ -0,0 +1,79 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=1920, height=1080" />
+    <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
+    <style>
+      * { margin: 0; padding: 0; box-sizing: border-box; }
+      html, body { width: 1920px; height: 1080px; overflow: hidden; background: #0a0e14; }
+      body { font-family: "Georgia", "Times New Roman", serif; color: #f4f6f8; }
+      .sans { font-family: "Helvetica Neue", Arial, sans-serif; }
+      #root { position: relative; width: 1920px; height: 1080px; overflow: hidden;
+        background: radial-gradient(1400px 900px at 50% 35%, #16202e 0%, #0a0e14 72%); }
+      .scene { position: absolute; inset: 0; display: flex; flex-direction: column;
+        align-items: center; justify-content: center; opacity: 0; }
+      .red { color: #c8102e; }
+      .kicker { letter-spacing: 8px; text-transform: uppercase; font-size: 26px; color: #8fa3b8; }
+      .headline { font-size: 88px; line-height: 1.06; text-align: center; max-width: 1500px; font-weight: 700; }
+      .daily { font-size: 150px; font-weight:700; letter-spacing:-3px; }
+      /* email signup mock */
+      .signup { display:flex; margin-top:44px; border:2px solid #2b3a4d; border-radius:8px; overflow:hidden; }
+      .signup .in { font-family:"Helvetica Neue",Arial,sans-serif; font-size:34px; color:#8fa3b8;
+        padding:24px 34px; background:#0e1622; width:620px; text-align:left; }
+      .signup .btn { font-family:"Helvetica Neue",Arial,sans-serif; font-size:30px; font-weight:700; color:#fff;
+        background:#c8102e; padding:24px 44px; letter-spacing:2px; text-transform:uppercase; display:flex; align-items:center; }
+      .free { display:inline-block; font-family:"Helvetica Neue",Arial,sans-serif; font-size:24px; letter-spacing:4px;
+        text-transform:uppercase; color:#c8102e; border:1px solid #c8102e; padding:8px 20px; margin-top:30px; }
+      .wordmark { font-weight:700; letter-spacing:-2px; }
+    </style>
+  </head>
+  <body>
+    <div id="root" data-composition-id="main" data-start="0" data-duration="11.7" data-width="1920" data-height="1080">
+
+      <div id="s1" class="scene clip" data-start="0" data-duration="3.6" data-track-index="1">
+        <div class="headline">The market moves before<br/>your <span class="red">first coffee.</span></div>
+      </div>
+
+      <div id="s2" class="scene clip" data-start="3.6" data-duration="4.4" data-track-index="1">
+        <div class="kicker sans" style="margin-bottom:24px">Every Western CRE deal, each morning</div>
+        <div class="daily">REN<span class="red">TV</span> Daily</div>
+        <div class="signup">
+          <div class="in">you@company.com</div>
+          <div class="btn">Subscribe</div>
+        </div>
+        <div class="free" id="s2free">Free</div>
+      </div>
+
+      <div id="s3" class="scene clip" data-start="8" data-duration="3.7" data-track-index="1">
+        <div class="kicker sans" style="margin-bottom:26px">The deals · the numbers · the edge</div>
+        <div class="headline" style="font-size:66px">Subscribe at</div>
+        <div class="wordmark" style="font-size:130px; margin-top:16px">REN<span class="red">TV</span>.com</div>
+      </div>
+
+      <audio id="vo" src=".media/narration.wav" data-start="0" data-duration="11.7" data-track-index="10" data-volume="1"></audio>
+    </div>
+
+    <script>
+      window.__timelines = window.__timelines || {};
+      const tl = gsap.timeline({ paused: true });
+
+      tl.fromTo("#s1", {opacity:0}, {opacity:1, duration:0.6}, 0.1)
+        .from("#s1 .headline", {opacity:0, y:32, duration:0.9, ease:"power3.out"}, 0.3)
+        .to("#s1", {opacity:0, duration:0.5}, 3.2);
+
+      tl.fromTo("#s2", {opacity:0}, {opacity:1, duration:0.5}, 3.7)
+        .from("#s2 .kicker", {opacity:0, y:14, duration:0.5}, 3.9)
+        .from("#s2 .daily", {opacity:0, y:24, duration:0.8, ease:"power3.out"}, 4.2)
+        .from("#s2 .signup", {opacity:0, y:26, duration:0.7}, 4.8)
+        .from("#s2free", {scale:0.7, opacity:0, duration:0.5, ease:"back.out(2)"}, 5.5)
+        .to("#s2", {opacity:0, duration:0.5}, 7.6);
+
+      tl.fromTo("#s3", {opacity:0}, {opacity:1, duration:0.5}, 8.1)
+        .from("#s3 .kicker", {opacity:0, y:14, duration:0.6}, 8.3)
+        .from("#s3 .wordmark", {opacity:0, scale:0.9, duration:0.9, ease:"power3.out"}, 8.7);
+
+      window.__timelines["main"] = tl;
+    </script>
+  </body>
+</html>
diff --git a/videos/daily/meta.json b/videos/daily/meta.json
new file mode 100644
index 0000000..b4731a2
--- /dev/null
+++ b/videos/daily/meta.json
@@ -0,0 +1,5 @@
+{
+  "id": "daily",
+  "name": "daily",
+  "createdAt": "2026-07-22T14:07:35.330Z"
+}
\ No newline at end of file
diff --git a/videos/daily/package.json b/videos/daily/package.json
new file mode 100644
index 0000000..9a4e409
--- /dev/null
+++ b/videos/daily/package.json
@@ -0,0 +1,11 @@
+{
+  "name": "daily",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "npx --yes hyperframes@0.7.68 preview",
+    "check": "npx --yes hyperframes@0.7.68 check",
+    "render": "npx --yes hyperframes@0.7.68 render",
+    "publish": "npx --yes hyperframes@0.7.68 publish"
+  }
+}
diff --git a/videos/deals/.media/narration.mp3 b/videos/deals/.media/narration.mp3
new file mode 100644
index 0000000..3e8b953
Binary files /dev/null and b/videos/deals/.media/narration.mp3 differ
diff --git a/videos/deals/AGENTS.md b/videos/deals/AGENTS.md
new file mode 100644
index 0000000..a63562c
--- /dev/null
+++ b/videos/deals/AGENTS.md
@@ -0,0 +1,93 @@
+# HyperFrames Composition Project
+
+## Skills — USE THESE FIRST
+
+**Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
+
+**Doing anything with HyperFrames?** Start at `/hyperframes` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), confirms your brief up front (the intent layer), and routes every "make me a…" request (a video, a deck, a composition port) to the right workflow. Read it first, especially when there's no project context to orient you. The workflows it routes to:
+
+- `/product-launch-video` — any **website** URL or brief / script → a product launch / SaaS / promo video, or a site tour / showcase featuring the site's own captured visuals.
+- `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
+- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
+- `/talking-head-recut` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
+- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
+- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
+- `/music-to-video` — a **music track** (audio file, or video to pull audio from) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
+- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
+- `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition) and the home of **companion mode** — co-create with the full HyperFrames toolbox; the original hyperframes authoring flow, any length.
+
+**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
+
+The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-keyframes`, `/hyperframes-creative`, `/hyperframes-cli`, `/media-use`, `/hyperframes-registry`, `/figma`) and the full capability map live inside `/hyperframes` — it is the single source of truth for which skill handles which intent.
+
+> **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
+
+> **Skill missing or stale?** Run `npx hyperframes skills update <name>` to install/refresh
+> the specific skill you need (the `/hyperframes` router does this automatically before
+> entering a workflow), or bare `npx hyperframes skills update` to refresh the core set plus
+> everything already installed — neither pulls the full set. Restart the agent session so
+> newly installed skills load.
+
+## Commands
+
+```bash
+npm run dev          # start the preview server (long-running — keep it alive in background)
+npm run check        # lint + runtime + layout + motion + contrast (one command)
+npm run render       # render to MP4
+npm run publish      # publish and get a shareable link
+npx hyperframes lint --verbose  # include info-level findings
+npx hyperframes lint --json     # machine-readable output for CI
+npx hyperframes docs <topic> # reference docs in terminal
+```
+
+> **`npm run dev` is a long-running server, not a one-shot command.** It blocks until stopped.
+> In Claude Code, always run it with `run_in_background: true`. Never run it as a foreground
+> command — it will time out and the server will die, breaking the browser preview.
+
+> **Pinned CLI version.** These scripts pin an exact `hyperframes@X.Y.Z` so this project re-renders identically over time. Weeks later that pin lags fixes shipped since. To move up: `npx hyperframes@latest upgrade --project . --check` (shows the delta), then `npx hyperframes@latest upgrade --project .` to rewrite the pins. Always unpinned — the pinned script re-runs the old version against itself.
+
+## Documentation
+
+**For quick reference**, use the local CLI docs command (no network required):
+
+```bash
+npx hyperframes docs <topic>
+```
+
+Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
+
+**For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
+
+```
+https://hyperframes.heygen.com/llms.txt
+```
+
+## Project Structure
+
+- `index.html` — main composition (root timeline)
+- `compositions/` — sub-compositions referenced via `data-composition-src`
+- `meta.json` — project metadata (id, name)
+- `transcript.json` — whisper word-level transcript (if generated)
+
+## Linting — ALWAYS RUN AFTER CHANGES
+
+After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
+
+```bash
+npm run check
+```
+
+Fix all errors before presenting the result. Warnings should be reviewed before rendering.
+
+## Key Rules
+
+1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
+2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
+3. Timelines must be paused and registered on `window.__timelines`:
+   ```js
+   window.__timelines = window.__timelines || {};
+   window.__timelines["composition-id"] = gsap.timeline({ paused: true });
+   ```
+4. Videos use `muted` with a separate `<audio>` element for the audio track
+5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
+6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
diff --git a/videos/deals/CLAUDE.md b/videos/deals/CLAUDE.md
new file mode 100644
index 0000000..a63562c
--- /dev/null
+++ b/videos/deals/CLAUDE.md
@@ -0,0 +1,93 @@
+# HyperFrames Composition Project
+
+## Skills — USE THESE FIRST
+
+**Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
+
+**Doing anything with HyperFrames?** Start at `/hyperframes` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), confirms your brief up front (the intent layer), and routes every "make me a…" request (a video, a deck, a composition port) to the right workflow. Read it first, especially when there's no project context to orient you. The workflows it routes to:
+
+- `/product-launch-video` — any **website** URL or brief / script → a product launch / SaaS / promo video, or a site tour / showcase featuring the site's own captured visuals.
+- `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
+- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
+- `/talking-head-recut` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
+- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
+- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
+- `/music-to-video` — a **music track** (audio file, or video to pull audio from) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
+- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
+- `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition) and the home of **companion mode** — co-create with the full HyperFrames toolbox; the original hyperframes authoring flow, any length.
+
+**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
+
+The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-keyframes`, `/hyperframes-creative`, `/hyperframes-cli`, `/media-use`, `/hyperframes-registry`, `/figma`) and the full capability map live inside `/hyperframes` — it is the single source of truth for which skill handles which intent.
+
+> **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
+
+> **Skill missing or stale?** Run `npx hyperframes skills update <name>` to install/refresh
+> the specific skill you need (the `/hyperframes` router does this automatically before
+> entering a workflow), or bare `npx hyperframes skills update` to refresh the core set plus
+> everything already installed — neither pulls the full set. Restart the agent session so
+> newly installed skills load.
+
+## Commands
+
+```bash
+npm run dev          # start the preview server (long-running — keep it alive in background)
+npm run check        # lint + runtime + layout + motion + contrast (one command)
+npm run render       # render to MP4
+npm run publish      # publish and get a shareable link
+npx hyperframes lint --verbose  # include info-level findings
+npx hyperframes lint --json     # machine-readable output for CI
+npx hyperframes docs <topic> # reference docs in terminal
+```
+
+> **`npm run dev` is a long-running server, not a one-shot command.** It blocks until stopped.
+> In Claude Code, always run it with `run_in_background: true`. Never run it as a foreground
+> command — it will time out and the server will die, breaking the browser preview.
+
+> **Pinned CLI version.** These scripts pin an exact `hyperframes@X.Y.Z` so this project re-renders identically over time. Weeks later that pin lags fixes shipped since. To move up: `npx hyperframes@latest upgrade --project . --check` (shows the delta), then `npx hyperframes@latest upgrade --project .` to rewrite the pins. Always unpinned — the pinned script re-runs the old version against itself.
+
+## Documentation
+
+**For quick reference**, use the local CLI docs command (no network required):
+
+```bash
+npx hyperframes docs <topic>
+```
+
+Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
+
+**For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
+
+```
+https://hyperframes.heygen.com/llms.txt
+```
+
+## Project Structure
+
+- `index.html` — main composition (root timeline)
+- `compositions/` — sub-compositions referenced via `data-composition-src`
+- `meta.json` — project metadata (id, name)
+- `transcript.json` — whisper word-level transcript (if generated)
+
+## Linting — ALWAYS RUN AFTER CHANGES
+
+After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
+
+```bash
+npm run check
+```
+
+Fix all errors before presenting the result. Warnings should be reviewed before rendering.
+
+## Key Rules
+
+1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
+2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
+3. Timelines must be paused and registered on `window.__timelines`:
+   ```js
+   window.__timelines = window.__timelines || {};
+   window.__timelines["composition-id"] = gsap.timeline({ paused: true });
+   ```
+4. Videos use `muted` with a separate `<audio>` element for the audio track
+5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
+6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
diff --git a/videos/deals/hyperframes.json b/videos/deals/hyperframes.json
new file mode 100644
index 0000000..dc9ec2e
--- /dev/null
+++ b/videos/deals/hyperframes.json
@@ -0,0 +1,12 @@
+{
+  "$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"
+  },
+  "media": {
+    "autoProxy": true
+  }
+}
diff --git a/videos/deals/index.html b/videos/deals/index.html
new file mode 100644
index 0000000..f76a73b
--- /dev/null
+++ b/videos/deals/index.html
@@ -0,0 +1,107 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=1920, height=1080" />
+    <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
+    <style>
+      * { margin: 0; padding: 0; box-sizing: border-box; }
+      html, body { width: 1920px; height: 1080px; overflow: hidden; background: #0a0e14; }
+      body { font-family: "Georgia", "Times New Roman", serif; color: #f4f6f8; }
+      .sans { font-family: "Helvetica Neue", Arial, sans-serif; }
+      #root { position: relative; width: 1920px; height: 1080px; overflow: hidden;
+        background: radial-gradient(1400px 900px at 40% 30%, #16202e 0%, #0a0e14 70%); }
+      .scene { position: absolute; inset: 0; display: flex; flex-direction: column;
+        align-items: center; justify-content: center; opacity: 0; }
+      .red { color: #c8102e; }
+      .kicker { letter-spacing: 8px; text-transform: uppercase; font-size: 26px; color: #8fa3b8; }
+      .headline { font-size: 92px; line-height: 1.05; text-align: center; max-width: 1500px; font-weight: 700; }
+      .breaking { font-family: "Helvetica Neue", Arial, sans-serif; background:#c8102e; color:#fff;
+        padding:10px 26px; letter-spacing:5px; text-transform:uppercase; font-size:24px; font-weight:700; }
+      /* deal card */
+      .amt { font-size: 200px; font-weight: 700; letter-spacing:-4px; line-height:1; }
+      .buyer { font-size: 58px; font-weight:700; margin-top:14px; }
+      .loc { font-family:"Helvetica Neue",Arial,sans-serif; letter-spacing:5px; text-transform:uppercase;
+        font-size:28px; color:#8fa3b8; margin-top:16px; }
+      .cat { display:inline-block; font-family:"Helvetica Neue",Arial,sans-serif; font-size:20px; letter-spacing:3px;
+        text-transform:uppercase; color:#c8102e; border:1px solid #c8102e; padding:6px 16px; margin-top:22px; }
+      .sect span { font-family:"Helvetica Neue",Arial,sans-serif; font-size:34px; letter-spacing:5px;
+        text-transform:uppercase; color:#b9c6d4; opacity:0; margin:0 22px; }
+      .wordmark { font-weight:700; letter-spacing:-2px; }
+    </style>
+  </head>
+  <body>
+    <div id="root" data-composition-id="main" data-start="0" data-duration="18.4" data-width="1920" data-height="1080">
+
+      <div id="s1" class="scene clip" data-start="0" data-duration="4" data-track-index="1">
+        <div class="breaking" id="s1b">Breaking</div>
+        <div class="headline" style="margin-top:34px">The West's biggest deals<br/><span class="red">break here first.</span></div>
+      </div>
+
+      <div id="s2" class="scene clip" data-start="4" data-duration="3.2" data-track-index="1">
+        <div class="amt red">$124M</div>
+        <div class="buyer">Camden Property Trust</div>
+        <div class="loc">Gilbert, AZ</div>
+        <div class="cat">Multifamily</div>
+      </div>
+
+      <div id="s3" class="scene clip" data-start="7.2" data-duration="2.6" data-track-index="1">
+        <div class="amt">$30M</div>
+        <div class="buyer">CentrePoint Properties</div>
+        <div class="loc">Colorado</div>
+        <div class="cat">Retail</div>
+      </div>
+
+      <div id="s4" class="scene clip" data-start="9.8" data-duration="2.9" data-track-index="1">
+        <div class="amt red">$132M</div>
+        <div class="buyer">Eagle Partners &amp; Vistria</div>
+        <div class="loc">Garden Grove, CA</div>
+        <div class="cat">Mixed-Income</div>
+      </div>
+
+      <div id="s5" class="scene clip" data-start="12.7" data-duration="2.6" data-track-index="1">
+        <div class="sect" style="text-align:center">
+          <span>Financing</span><span>Leases</span><span>Development</span><span>Sales</span>
+        </div>
+      </div>
+
+      <div id="s6" class="scene clip" data-start="15.3" data-duration="3.1" data-track-index="1">
+        <div class="headline" style="font-size:66px">If it closed out West,<br/>it's on</div>
+        <div class="wordmark" style="font-size:120px; margin-top:20px">REN<span class="red">TV</span>.com</div>
+      </div>
+
+      <audio id="vo" src=".media/narration.wav" data-start="0" data-duration="18.4" data-track-index="10" data-volume="1"></audio>
+    </div>
+
+    <script>
+      window.__timelines = window.__timelines || {};
+      const tl = gsap.timeline({ paused: true });
+      const card = (id, t) => {
+        tl.fromTo("#"+id, {opacity:0}, {opacity:1, duration:0.45}, t)
+          .from("#"+id+" .amt", {scale:0.8, y:20, duration:0.7, ease:"power3.out"}, t+0.05)
+          .from("#"+id+" .buyer", {opacity:0, y:18, duration:0.5}, t+0.35)
+          .from("#"+id+" .loc", {opacity:0, y:12, duration:0.5}, t+0.5)
+          .from("#"+id+" .cat", {opacity:0, duration:0.5}, t+0.65);
+      };
+      // s1
+      tl.fromTo("#s1", {opacity:0}, {opacity:1, duration:0.5}, 0.1)
+        .from("#s1b", {scale:0.8, opacity:0, duration:0.5, ease:"back.out(2)"}, 0.2)
+        .from("#s1 .headline", {opacity:0, y:30, duration:0.8, ease:"power3.out"}, 0.6)
+        .to("#s1", {opacity:0, duration:0.4}, 3.7);
+      // deal cards
+      card("s2", 4.05); tl.to("#s2", {opacity:0, duration:0.35}, 6.95);
+      card("s3", 7.25); tl.to("#s3", {opacity:0, duration:0.35}, 9.55);
+      card("s4", 9.85); tl.to("#s4", {opacity:0, duration:0.35}, 12.45);
+      // s5 sections
+      tl.fromTo("#s5", {opacity:0}, {opacity:1, duration:0.4}, 12.75)
+        .to("#s5 .sect span", {opacity:1, stagger:0.18, duration:0.4}, 12.9)
+        .to("#s5", {opacity:0, duration:0.4}, 15.0);
+      // s6 signoff
+      tl.fromTo("#s6", {opacity:0}, {opacity:1, duration:0.5}, 15.4)
+        .from("#s6 .headline", {opacity:0, y:24, duration:0.7}, 15.5)
+        .from("#s6 .wordmark", {opacity:0, scale:0.9, duration:0.8, ease:"power3.out"}, 16.0);
+
+      window.__timelines["main"] = tl;
+    </script>
+  </body>
+</html>
diff --git a/videos/deals/meta.json b/videos/deals/meta.json
new file mode 100644
index 0000000..feab84f
--- /dev/null
+++ b/videos/deals/meta.json
@@ -0,0 +1,5 @@
+{
+  "id": "deals",
+  "name": "deals",
+  "createdAt": "2026-07-22T14:07:31.574Z"
+}
\ No newline at end of file
diff --git a/videos/deals/package.json b/videos/deals/package.json
new file mode 100644
index 0000000..9d02964
--- /dev/null
+++ b/videos/deals/package.json
@@ -0,0 +1,11 @@
+{
+  "name": "deals",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "npx --yes hyperframes@0.7.68 preview",
+    "check": "npx --yes hyperframes@0.7.68 check",
+    "render": "npx --yes hyperframes@0.7.68 render",
+    "publish": "npx --yes hyperframes@0.7.68 publish"
+  }
+}
diff --git a/videos/review/.media/narration.mp3 b/videos/review/.media/narration.mp3
new file mode 100644
index 0000000..dc94c35
Binary files /dev/null and b/videos/review/.media/narration.mp3 differ
diff --git a/videos/review/AGENTS.md b/videos/review/AGENTS.md
new file mode 100644
index 0000000..a63562c
--- /dev/null
+++ b/videos/review/AGENTS.md
@@ -0,0 +1,93 @@
+# HyperFrames Composition Project
+
+## Skills — USE THESE FIRST
+
+**Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
+
+**Doing anything with HyperFrames?** Start at `/hyperframes` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), confirms your brief up front (the intent layer), and routes every "make me a…" request (a video, a deck, a composition port) to the right workflow. Read it first, especially when there's no project context to orient you. The workflows it routes to:
+
+- `/product-launch-video` — any **website** URL or brief / script → a product launch / SaaS / promo video, or a site tour / showcase featuring the site's own captured visuals.
+- `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
+- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
+- `/talking-head-recut` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
+- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
+- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
+- `/music-to-video` — a **music track** (audio file, or video to pull audio from) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
+- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
+- `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition) and the home of **companion mode** — co-create with the full HyperFrames toolbox; the original hyperframes authoring flow, any length.
+
+**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
+
+The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-keyframes`, `/hyperframes-creative`, `/hyperframes-cli`, `/media-use`, `/hyperframes-registry`, `/figma`) and the full capability map live inside `/hyperframes` — it is the single source of truth for which skill handles which intent.
+
+> **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
+
+> **Skill missing or stale?** Run `npx hyperframes skills update <name>` to install/refresh
+> the specific skill you need (the `/hyperframes` router does this automatically before
+> entering a workflow), or bare `npx hyperframes skills update` to refresh the core set plus
+> everything already installed — neither pulls the full set. Restart the agent session so
+> newly installed skills load.
+
+## Commands
+
+```bash
+npm run dev          # start the preview server (long-running — keep it alive in background)
+npm run check        # lint + runtime + layout + motion + contrast (one command)
+npm run render       # render to MP4
+npm run publish      # publish and get a shareable link
+npx hyperframes lint --verbose  # include info-level findings
+npx hyperframes lint --json     # machine-readable output for CI
+npx hyperframes docs <topic> # reference docs in terminal
+```
+
+> **`npm run dev` is a long-running server, not a one-shot command.** It blocks until stopped.
+> In Claude Code, always run it with `run_in_background: true`. Never run it as a foreground
+> command — it will time out and the server will die, breaking the browser preview.
+
+> **Pinned CLI version.** These scripts pin an exact `hyperframes@X.Y.Z` so this project re-renders identically over time. Weeks later that pin lags fixes shipped since. To move up: `npx hyperframes@latest upgrade --project . --check` (shows the delta), then `npx hyperframes@latest upgrade --project .` to rewrite the pins. Always unpinned — the pinned script re-runs the old version against itself.
+
+## Documentation
+
+**For quick reference**, use the local CLI docs command (no network required):
+
+```bash
+npx hyperframes docs <topic>
+```
+
+Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
+
+**For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
+
+```
+https://hyperframes.heygen.com/llms.txt
+```
+
+## Project Structure
+
+- `index.html` — main composition (root timeline)
+- `compositions/` — sub-compositions referenced via `data-composition-src`
+- `meta.json` — project metadata (id, name)
+- `transcript.json` — whisper word-level transcript (if generated)
+
+## Linting — ALWAYS RUN AFTER CHANGES
+
+After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
+
+```bash
+npm run check
+```
+
+Fix all errors before presenting the result. Warnings should be reviewed before rendering.
+
+## Key Rules
+
+1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
+2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
+3. Timelines must be paused and registered on `window.__timelines`:
+   ```js
+   window.__timelines = window.__timelines || {};
+   window.__timelines["composition-id"] = gsap.timeline({ paused: true });
+   ```
+4. Videos use `muted` with a separate `<audio>` element for the audio track
+5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
+6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
diff --git a/videos/review/CLAUDE.md b/videos/review/CLAUDE.md
new file mode 100644
index 0000000..a63562c
--- /dev/null
+++ b/videos/review/CLAUDE.md
@@ -0,0 +1,93 @@
+# HyperFrames Composition Project
+
+## Skills — USE THESE FIRST
+
+**Always invoke the relevant skill before writing or modifying compositions.** Skills encode framework-specific patterns (e.g., `window.__timelines` registration, `data-*` attribute semantics, shader-compatible CSS rules) that are NOT in generic web docs. Skipping them produces broken compositions.
+
+**Doing anything with HyperFrames?** Start at `/hyperframes` — it tells you what HyperFrames can do and which skill or workflow handles your intent (make a video, TTS / BGM, prep footage, author / animate, render, install blocks), confirms your brief up front (the intent layer), and routes every "make me a…" request (a video, a deck, a composition port) to the right workflow. Read it first, especially when there's no project context to orient you. The workflows it routes to:
+
+- `/product-launch-video` — any **website** URL or brief / script → a product launch / SaaS / promo video, or a site tour / showcase featuring the site's own captured visuals.
+- `/faceless-explainer` — arbitrary text (topic / article / notes), **no URL, no website capture** → 60-90s faceless explainer.
+- `/embedded-captions` — an existing talking-head video (MP4) → the same footage with captions / subtitles added (rail + embed, or pure-cinematic embed); the footage itself is untouched.
+- `/talking-head-recut` — an existing talking-head / interview / podcast video (MP4) → the same footage **packaged with designed graphic overlays** (kinetic titles, lower-thirds, data callouts, pull-quotes, side panels, pip) synced to the transcript; the clip plays unchanged underneath. (Plain captions/subtitles → `/embedded-captions`.)
+- `/pr-to-video` — a GitHub PR (URL / `owner/repo#N` / "this PR") → 30-90s code-change explainer (changelog / feature reveal / fix / refactor).
+- `/motion-graphics` — a short (typically under 10s) design-led **motion graphic**, motion-is-the-message, no narration: kinetic type, a stat / number count-up, a chart, a logo sting, a lower-third / overlay, or an animated tweet / headline / captured-page highlight; rendered to MP4 or a transparent overlay. Longer / narrated / custom → `/general-video`.
+- `/music-to-video` — a **music track** (audio file, or video to pull audio from) → beat-synced video (lyric / slideshow / kinetic promo). Music drives pacing; user-supplied images / videos are cut onto the same beat grid.
+- `/slideshow` — a **presentation / pitch deck / interactive deck** — discrete slides, fragment reveals, branching, hotspot navigation, presenter mode. Output is a navigable deck, not a rendered video.
+- `/general-video` — fallback for any other video (title card, longer brand / sizzle reel, multi-scene montage, static loop, custom composition) and the home of **companion mode** — co-create with the full HyperFrames toolbox; the original hyperframes authoring flow, any length.
+
+**Porting an existing composition?** `/remotion-to-hyperframes` translates a Remotion (React) composition into HyperFrames HTML — a source migration, separate from the creation workflows above.
+
+The domain skills (`/hyperframes-core`, `/hyperframes-animation`, `/hyperframes-keyframes`, `/hyperframes-creative`, `/hyperframes-cli`, `/media-use`, `/hyperframes-registry`, `/figma`) and the full capability map live inside `/hyperframes` — it is the single source of truth for which skill handles which intent.
+
+> **Tailwind v4 projects** (`hyperframes init --tailwind`): see `/hyperframes-core` → `references/tailwind.md`.
+
+> **Skill missing or stale?** Run `npx hyperframes skills update <name>` to install/refresh
+> the specific skill you need (the `/hyperframes` router does this automatically before
+> entering a workflow), or bare `npx hyperframes skills update` to refresh the core set plus
+> everything already installed — neither pulls the full set. Restart the agent session so
+> newly installed skills load.
+
+## Commands
+
+```bash
+npm run dev          # start the preview server (long-running — keep it alive in background)
+npm run check        # lint + runtime + layout + motion + contrast (one command)
+npm run render       # render to MP4
+npm run publish      # publish and get a shareable link
+npx hyperframes lint --verbose  # include info-level findings
+npx hyperframes lint --json     # machine-readable output for CI
+npx hyperframes docs <topic> # reference docs in terminal
+```
+
+> **`npm run dev` is a long-running server, not a one-shot command.** It blocks until stopped.
+> In Claude Code, always run it with `run_in_background: true`. Never run it as a foreground
+> command — it will time out and the server will die, breaking the browser preview.
+
+> **Pinned CLI version.** These scripts pin an exact `hyperframes@X.Y.Z` so this project re-renders identically over time. Weeks later that pin lags fixes shipped since. To move up: `npx hyperframes@latest upgrade --project . --check` (shows the delta), then `npx hyperframes@latest upgrade --project .` to rewrite the pins. Always unpinned — the pinned script re-runs the old version against itself.
+
+## Documentation
+
+**For quick reference**, use the local CLI docs command (no network required):
+
+```bash
+npx hyperframes docs <topic>
+```
+
+Topics: `data-attributes`, `gsap`, `compositions`, `rendering`, `examples`, `troubleshooting`
+
+**For full documentation**, discover pages via the machine-readable index — do NOT guess URLs:
+
+```
+https://hyperframes.heygen.com/llms.txt
+```
+
+## Project Structure
+
+- `index.html` — main composition (root timeline)
+- `compositions/` — sub-compositions referenced via `data-composition-src`
+- `meta.json` — project metadata (id, name)
+- `transcript.json` — whisper word-level transcript (if generated)
+
+## Linting — ALWAYS RUN AFTER CHANGES
+
+After creating or editing any `.html` composition, **always** run the full check before considering the task complete:
+
+```bash
+npm run check
+```
+
+Fix all errors before presenting the result. Warnings should be reviewed before rendering.
+
+## Key Rules
+
+1. Every timed element needs `data-start`, `data-duration`, and `data-track-index`
+2. Elements with timing **MUST** have `class="clip"` — the framework uses this for visibility control
+3. Timelines must be paused and registered on `window.__timelines`:
+   ```js
+   window.__timelines = window.__timelines || {};
+   window.__timelines["composition-id"] = gsap.timeline({ paused: true });
+   ```
+4. Videos use `muted` with a separate `<audio>` element for the audio track
+5. Sub-compositions use `data-composition-src="compositions/file.html"` to reference other HTML files
+6. Only deterministic logic — no `Date.now()`, no `Math.random()`, no network fetches
diff --git a/videos/review/hyperframes.json b/videos/review/hyperframes.json
new file mode 100644
index 0000000..dc9ec2e
--- /dev/null
+++ b/videos/review/hyperframes.json
@@ -0,0 +1,12 @@
+{
+  "$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"
+  },
+  "media": {
+    "autoProxy": true
+  }
+}
diff --git a/videos/review/index.html b/videos/review/index.html
new file mode 100644
index 0000000..a624b87
--- /dev/null
+++ b/videos/review/index.html
@@ -0,0 +1,82 @@
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=1920, height=1080" />
+    <script src="https://cdn.jsdelivr.net/npm/gsap@3.14.2/dist/gsap.min.js"></script>
+    <style>
+      * { margin: 0; padding: 0; box-sizing: border-box; }
+      html, body { width: 1920px; height: 1080px; overflow: hidden; background: #0a0e14; }
+      body { font-family: "Georgia", "Times New Roman", serif; color: #f4f6f8; }
+      .sans { font-family: "Helvetica Neue", Arial, sans-serif; }
+      #root { position: relative; width: 1920px; height: 1080px; overflow: hidden;
+        background: radial-gradient(1400px 900px at 55% 40%, #16202e 0%, #0a0e14 72%); }
+      .scene { position: absolute; inset: 0; display: flex; flex-direction: column;
+        align-items: center; justify-content: center; opacity: 0; }
+      .red { color: #c8102e; }
+      .kicker { letter-spacing: 8px; text-transform: uppercase; font-size: 26px; color: #8fa3b8; }
+      .headline { font-size: 90px; line-height: 1.06; text-align: center; max-width: 1500px; font-weight: 700; }
+      .big { font-size: 220px; font-weight:700; letter-spacing:-4px; line-height:1; }
+      .play { width:150px; height:150px; border-radius:50%; background:#c8102e; display:flex;
+        align-items:center; justify-content:center; margin-bottom:34px; }
+      .play::after { content:""; border-left:52px solid #fff; border-top:32px solid transparent;
+        border-bottom:32px solid transparent; margin-left:14px; }
+      .three span { font-family:"Helvetica Neue",Arial,sans-serif; font-size:42px; letter-spacing:6px;
+        text-transform:uppercase; color:#b9c6d4; display:block; margin:14px 0; opacity:0; }
+      .wordmark { font-weight:700; letter-spacing:-2px; }
+    </style>
+  </head>
+  <body>
+    <div id="root" data-composition-id="main" data-start="0" data-duration="17.4" data-width="1920" data-height="1080">
+
+      <div id="s1" class="scene clip" data-start="0" data-duration="4.6" data-track-index="1">
+        <div class="headline">It isn't just headlines.<br/>It's the <span class="red">people</span> behind them.</div>
+      </div>
+
+      <div id="s2" class="scene clip" data-start="4.6" data-duration="4.4" data-track-index="1">
+        <div class="play" id="s2play"></div>
+        <div class="big">The <span class="red">RE</span>view</div>
+        <div class="kicker sans" style="margin-top:26px">Face to face with the dealmakers</div>
+      </div>
+
+      <div id="s3" class="scene clip" data-start="9" data-duration="4" data-track-index="1">
+        <div class="three" style="text-align:center">
+          <span>Interviews</span><span>Insight</span><span>The stories behind the numbers</span>
+        </div>
+      </div>
+
+      <div id="s4" class="scene clip" data-start="13" data-duration="4.4" data-track-index="1">
+        <div class="kicker sans" style="margin-bottom:26px">Watch The REview</div>
+        <div class="headline" style="font-size:70px">Only on</div>
+        <div class="wordmark" style="font-size:130px; margin-top:16px">REN<span class="red">TV</span>.com</div>
+      </div>
+
+      <audio id="vo" src=".media/narration.wav" data-start="0" data-duration="17.4" data-track-index="10" data-volume="1"></audio>
+    </div>
+
+    <script>
+      window.__timelines = window.__timelines || {};
+      const tl = gsap.timeline({ paused: true });
+
+      tl.fromTo("#s1", {opacity:0}, {opacity:1, duration:0.6}, 0.1)
+        .from("#s1 .headline", {opacity:0, y:34, duration:0.9, ease:"power3.out"}, 0.3)
+        .to("#s1", {opacity:0, duration:0.5}, 4.2);
+
+      tl.fromTo("#s2", {opacity:0}, {opacity:1, duration:0.5}, 4.7)
+        .from("#s2play", {scale:0.6, opacity:0, duration:0.6, ease:"back.out(2)"}, 4.8)
+        .from("#s2 .big", {opacity:0, y:26, duration:0.8, ease:"power3.out"}, 5.1)
+        .from("#s2 .kicker", {opacity:0, y:14, duration:0.6}, 5.6)
+        .to("#s2", {opacity:0, duration:0.5}, 8.6);
+
+      tl.fromTo("#s3", {opacity:0}, {opacity:1, duration:0.5}, 9.1)
+        .to("#s3 .three span", {opacity:1, stagger:0.4, duration:0.5}, 9.3)
+        .to("#s3", {opacity:0, duration:0.5}, 12.6);
+
+      tl.fromTo("#s4", {opacity:0}, {opacity:1, duration:0.5}, 13.1)
+        .from("#s4 .kicker", {opacity:0, y:14, duration:0.6}, 13.3)
+        .from("#s4 .wordmark", {opacity:0, scale:0.9, duration:0.9, ease:"power3.out"}, 13.7);
+
+      window.__timelines["main"] = tl;
+    </script>
+  </body>
+</html>
diff --git a/videos/review/meta.json b/videos/review/meta.json
new file mode 100644
index 0000000..565d64f
--- /dev/null
+++ b/videos/review/meta.json
@@ -0,0 +1,5 @@
+{
+  "id": "review",
+  "name": "review",
+  "createdAt": "2026-07-22T14:07:33.440Z"
+}
\ No newline at end of file
diff --git a/videos/review/package.json b/videos/review/package.json
new file mode 100644
index 0000000..b5f0b16
--- /dev/null
+++ b/videos/review/package.json
@@ -0,0 +1,11 @@
+{
+  "name": "review",
+  "private": true,
+  "type": "module",
+  "scripts": {
+    "dev": "npx --yes hyperframes@0.7.68 preview",
+    "check": "npx --yes hyperframes@0.7.68 check",
+    "render": "npx --yes hyperframes@0.7.68 render",
+    "publish": "npx --yes hyperframes@0.7.68 publish"
+  }
+}

(oldest)  ·  back to Rentv Promos  ·  auto-save: 2026-07-22T13:44:34 (1 files) — recap-v2/ 263c1a0 →