# Claude Paper Launch Documentation

> Reference for the HyperFrames MCP launch video: a 53.3s GSAP-orchestrated composition with ten scene plates, Claude Paper design tokens, synchronized audio/SFX, and self-hosted fonts.

## Context Links

- [Agent index](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/llms.txt)
- [Human interactive docs](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b)
- [GitHub repository](https://github.com/heygen-com/hyperframes-launches)

## Repository Metadata

- Repository: heygen-com/hyperframes-launches
- Branch: main
- Generated: 2026-06-10T06:35:42.853Z
- Updated: 2026-06-10T06:44:20.021Z
- Runtime: Grok CLI
- Format: Documentation
- Pages: 17

## Page Index

- 01. [Overview](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/01-overview.md) - What the Claude Paper launch video demonstrates, its 1920×1080 runtime envelope, primary entry points, and the shortest path to preview the full cut.
- 02. [Installation](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/02-installation.md) - Prerequisites for opening and rendering the project: Git LFS for binary assets, HyperFrames CLI, and the scoped folder layout under hyperframes-launches.
- 03. [Quickstart](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/03-quickstart.md) - First successful invocation: open index.html in HyperFrames preview, verify the 53.3s timeline plays, and render to MP4.
- 04. [HyperFrames composition model](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/04-hyperframes-composition-model.md) - How root and scene compositions register timelines via window.__timelines, data-composition-id attributes, template wrappers, and GSAP paused timelines.
- 05. [Claude Paper design system](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/05-claude-paper-design-system.md) - The four brand atoms (paper, ink, muted, clay), typography ramps, component tokens, and frame-scale authoring rules defined in FRAME-claude.md.
- 06. [Frame treatments](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/06-frame-treatments.md) - Seven normative frame plates—Paper Identity, Oversized Claim, Karaoke Stage, Focal Artifact, Quiet Ledger, Palette Catalog, Pull-Quote Closer—and their density, accent, and anchor constraints.
- 07. [Transition grammar](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/07-transition-grammar.md) - Cross-section seam types used in the master cut: hard cuts, opacity crossfades, inverse zoom-through, and leftward cut-the-curve with velocity-matched handoffs.
- 08. [Preview and render](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/08-preview-and-render.md) - Run hyperframes preview and hyperframes render against the claude-paper-launch folder, confirm 1920×1080 output, and validate scene loading from compositions/.
- 09. [Edit the master timeline](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/09-edit-the-master-timeline.md) - Modify the root GSAP timeline in index.html: adjust section data-start/duration, z-index stacking, seam cut times (CUT, CUT2–CUT6), and window.__timelines registration.
- 10. [Author a scene composition](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/10-author-a-scene-composition.md) - Create or edit a compositions/*.html plate: wrap in a template, set data-composition-id and data-duration, embed local fonts, build a paused GSAP timeline, and register on window.__timelines.
- 11. [Sync audio and SFX](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/11-sync-audio-and-sfx.md) - Wire voiceover, explainer VO, click/toggle/type SFX tracks using data-start, data-duration, data-track-index, and data-volume on audio elements in index.html.
- 12. [Master composition reference](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/12-master-composition-reference.md) - Root claude-paper composition: 1920×1080, 53.3s duration, ten stacked sections with z-index order, data-composition-src paths, and track-index assignments.
- 13. [Scene catalog](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/13-scene-catalog.md) - All scene compositions with ids, durations, narrative roles, and handoff constraints—from connector-morph through outro, plus the standalone tesla-rap explainer plate.
- 14. [Design tokens reference](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/14-design-tokens-reference.md) - Canonical color hexes, typography ramps (reading and hero), spacing, rounded radii, motion easings, shadow recipes, and component frontmatter keys from FRAME-claude.md.
- 15. [Audio track reference](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/15-audio-track-reference.md) - Voiceover tracks (Scotsman VO at 29.6s, explainer VO at 42.6s), generated SFX inventory (click, toggle, typenew), volumes, and word-level transcript.json timing.
- 16. [Fonts and assets](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/16-fonts-and-assets.md) - Self-hosted Hanken Grotesk, Spline Sans Mono, Newsreader, and Galaxie Copernicus woff2 files, fonts.css @font-face blocks, and Git LFS binary dependencies.
- 17. [Troubleshooting](https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/17-troubleshooting.md) - Recovery for missing LFS audio/SFX, font-display:block loading stalls, seam misalignment between consecutive scenes, and timeline registration failures.

## Source File Index

- `compositions/chat-response.html`
- `compositions/compose-tasklist.html`
- `compositions/compose-ui.html`
- `compositions/connector-morph.html`
- `compositions/followup-type.html`
- `compositions/outro.html`
- `compositions/response-scroll.html`
- `compositions/sure-response.html`
- `compositions/tesla-rap.html`
- `compositions/thinking-big-2.html`
- `compositions/thinking-big.html`
- `fonts/fonts.css`
- `fonts/GalaxieCopernicus-Book.woff2`
- `fonts/HankenGrotesk-normal-400-latin-fe1634.woff2`
- `fonts/Newsreader-normal-500-latin-f0c28d.woff2`
- `fonts/SplineSansMono-normal-500-latin-53329b.woff2`
- `FRAME-claude.md`
- `index.html`
- `transcript.json`
- `voiceover_explainer.mp3`
- `voiceover.mp3`

---

## 01. Overview

> What the Claude Paper launch video demonstrates, its 1920×1080 runtime envelope, primary entry points, and the shortest path to preview the full cut.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/01-overview.md
- Generated: 2026-06-10T06:30:52.973Z

### Source Files

- `index.html`
- `FRAME-claude.md`
- `compositions/outro.html`
- `compositions/compose-ui.html`
- `voiceover.mp3`

---
title: "Overview"
description: "What the Claude Paper launch video demonstrates, its 1920×1080 runtime envelope, primary entry points, and the shortest path to preview the full cut."
---

`claude-paper-launch/index.html` is the root HyperFrames composition `claude-paper`: a **53.3s**, **1920×1080** master cut that stacks ten scene plates, drives cross-section seams with a paused GSAP timeline on `window.__timelines`, and loads each scene from `compositions/` via `data-composition-src`.

## What the cut demonstrates

The video tells an end-to-end product story: a Claude user enables the HyperFrames MCP connector, receives a long-form Tesla analysis, asks Claude to turn it into a video, watches HyperFrames compose generate output, corrects an unwanted Scottish narrator style, and lands on a branded close announcing native HyperFrames MCP support on Claude.

| Beat | Scene id | Start | Duration | Narrative role |
| --- | --- | ---: | ---: | --- |
| 1 | `connector-morph` | 0s | 6.7s | Open `+` menu, enable Hyperframes connector, reveal prompt box |
| 2 | `chat-response` | 6.7s | 6.9s | Type and send the Tesla question; composer collapses to thinking |
| 3 | `response-scroll` | 13.0s | 6.7s | Scroll the long Tesla markdown answer into view |
| 4 | `followup-type` | 19.4s | 6.0s | Click composer; type “into a video with HyperFrames?” |
| 5 | `thinking-big` | 25.0s | 1.3s | Giant centered thinking: “Getting started…” |
| 6 | `compose-ui` | 25.8s | 13.3s | HyperFrames compose UI: init → 7-step pipeline → in-player Scottish VO → pause → style correction → send |
| 7 | `sure-response` | 38.8s | 0.4s | Giant serif reply: “Sure.” |
| 8 | `thinking-big-2` | 39.0s | 1.3s | Giant thinking: “Making your video…” |
| 9 | `compose-tasklist` | 40.3s | 9.8s | Task list resumes halfway; last three items cross off; download tap |
| 10 | `outro` | 49.9s | 3.4s | “HyperFrames MCP” → “Now natively supported on” → Claude logo Lottie |

The `compose-ui` plate is the narrative centerpiece: it runs the real seven-task HyperFrames pipeline (`narrative_planner` through `inline_index_html`), plays a generated “Hamish McTavish’s Tips” segment inside the compose player, interrupts the Scotsman voiceover at “numpties,” and shows the user typing a correction to drop the Scottish style.

`compositions/tesla-rap.html` (`tesla-rap`, 5.0s) is a standalone explainer plate referenced by the compose flow but **not** mounted in the master `index.html` stack.

## Runtime envelope

| Field | Value | Where set |
| --- | --- | --- |
| Composition id | `claude-paper` | `#claude-paper` in `index.html` |
| Frame size | 1920 × 1080 px | `data-width`, `data-height`; fixed `html, body` dimensions |
| Duration | 53.3 s | `data-duration="53.3"` |
| Background | `#F0EEE6` (paper) | Root and section CSS |
| Export target | 1920×1080 @ 30 fps | `FRAME-claude.md` motion export note |
| Scene plates | 1920 × 1080 each | Every `compositions/*.html` root `data-width` / `data-height` |

Sections are absolutely positioned full-bleed layers with `z-index` 1–10 so crossfades and cut-the-curve handoffs stack predictably. The master timeline in `index.html` owns **only** inter-section opacity, scale, blur, and `xPercent` seams (`CUT` through `CUT6`); each scene owns its internal GSAP timeline registered on `window.__timelines[<id>]`.

```text
index.html (#claude-paper, 53.3s)
├── sec-connector   z:1  → compositions/connector-morph.html
├── sec-chat        z:2  → compositions/chat-response.html
├── sec-response    z:3  → compositions/response-scroll.html
├── sec-followup    z:4  → compositions/followup-type.html
├── sec-thinking    z:5  → compositions/thinking-big.html
├── sec-compose     z:6  → compositions/compose-ui.html
├── sec-sure        z:7  → compositions/sure-response.html
├── sec-thinking2   z:8  → compositions/thinking-big-2.html
├── sec-tasklist    z:9  → compositions/compose-tasklist.html
├── sec-outro       z:10 → compositions/outro.html
├── voiceover.mp3           (Scotsman VO @ 29.6s, 2.17s)
├── voiceover_explainer.mp3 (explainer VO @ 42.6s, 6.41s)
└── click / toggle / typenew SFX tracks (data-start on <audio>)
```

## Primary entry points

| Path | Role |
| --- | --- |
| `index.html` | Master composition; open this for the full 53.3s cut |
| `compositions/*.html` | Scene templates (`<template id="…-template">`) with per-scene timelines |
| `FRAME-claude.md` | Claude Paper design system: colors, typography ramps, frame treatments, motion rules |
| `fonts/fonts.css` | Shared `@font-face` blocks (Hanken Grotesk, Spline Sans Mono, Newsreader, Galaxie Copernicus) |
| `transcript.json` | Word-level timing for the Scotsman VO segment |
| `voiceover.mp3` | Scotsman voiceover (plays during compose player segment) |
| `voiceover_explainer.mp3` | Neutral presenter VO over the final explainer beat |

<Note>
Binary audio and SFX files (`voiceover.mp3`, `click.mp3`, `toggle.mp3`, `typenew.mp3`, images referenced in scenes) are Git LFS assets. A checkout without `git lfs pull` may contain 131-byte pointer stubs instead of playable media.
</Note>

## Design system binding

Visual language follows **Claude Paper** from `FRAME-claude.md`: four brand atoms (paper `#F0EEE6`, ink `#262624`, muted `#6F6E66`, clay `#D97757`), Hanken Grotesk for display and body, Spline Sans Mono for chrome labels, and frame-relative sizing in `vw` / `cqw` against a `container-type: size` root. Scene plates embed local `woff2` fonts with `font-display: block` so preview and render match.

## Shortest path to preview the full cut

<Steps>
<Step title="Install prerequisites">

Install [Git LFS](https://git-lfs.com/) and the HyperFrames CLI. From the scoped folder root, pull LFS objects so audio, SFX, and referenced images resolve:

```bash
git lfs install
git lfs pull
```

</Step>

<Step title="Open the master composition">

From inside `claude-paper-launch/`, run HyperFrames preview against `index.html`:

```bash
cd claude-paper-launch
hyperframes preview
```

The preview loads `index.html`, hydrates each `data-composition-src` section, seeks the root `window.__timelines["claude-paper"]` timeline, and plays synchronized `<audio>` tracks by `data-start` / `data-duration`.

</Step>

<Step title="Verify the timeline">

Confirm the transport reads **53.3s** total duration and sections hand off at the scheduled `data-start` values (0 → 6.7 → 13.0 → … → 49.9). Audio cues to check:

- Scotsman VO begins near **29.6s** inside the compose player
- Explainer VO begins near **42.6s** during the task-list / explainer beat
- Click SFX fires on connector toggles, composer taps, and the download press near **49.3s**

</Step>
</Steps>

### Scene-only preview (without the master stack)

Any scene template supports local scrubbing via URL query params (pattern used across `compositions/`):

```bash
# auto-play the scene timeline in a browser
compositions/compose-ui.html?dev=1

# seek to a specific second
compositions/outro.html?t=1.4
```

These paths exercise a single `window.__timelines[<composition-id>]` registration; they do not load sibling sections or root audio tracks.

### Render to MP4

After preview validation:

```bash
hyperframes render
```

Output is **1920×1080** MP4 from the same `index.html` root. See [Preview and render](/preview-and-render) for CLI flags and validation checks.

## Master timeline seam grammar (summary)

The root timeline blends sections with four seam types:

| Seam | Sections | Type | Cut time |
| --- | --- | --- | ---: |
| 1 | connector → chat | Hard cut | 6.7s |
| 2 | chat → response | Opacity crossfade (0.6s) | 13.0s |
| 3 | follow-up → thinking | Inverse zoom-through | `CUT` 25.2s |
| 4 | thinking → compose | Inverse zoom-through | `CUT2` 26.0s |
| 5 | compose → sure | Leftward cut-the-curve | `CUT3` 38.8s |
| 6 | sure → thinking-2 | Inverse zoom-through | `CUT4` 39.2s |
| 7 | thinking-2 → tasklist | Leftward cut-the-curve | `CUT5` 40.3s |
| 8 | tasklist → outro | Leftward cut-the-curve | `CUT6` 49.9s |

Connector and chat share a pixel-matched composer layout, so seam 1 needs no blend. Paper background on exposed edges keeps leftward throws seamless.

## Related pages

<CardGroup>
<Card title="Installation" href="/installation">
Git LFS, HyperFrames CLI, and the scoped folder layout under hyperframes-launches.
</Card>
<Card title="Quickstart" href="/quickstart">
First successful preview of the 53.3s timeline and render to MP4.
</Card>
<Card title="Composition model" href="/composition-model">
How root and scene compositions register on `window.__timelines`.
</Card>
<Card title="Master composition reference" href="/master-composition-reference">
Full section table, z-index order, and track-index assignments.
</Card>
<Card title="Scene catalog" href="/scene-catalog">
All scene ids, durations, and handoff constraints.
</Card>
<Card title="Claude Paper design system" href="/claude-paper-design-system">
Brand atoms, typography ramps, and frame-scale authoring rules.
</Card>
</CardGroup>

---

## 02. Installation

> Prerequisites for opening and rendering the project: Git LFS for binary assets, HyperFrames CLI, and the scoped folder layout under hyperframes-launches.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/02-installation.md
- Generated: 2026-06-10T06:32:39.740Z

### Source Files

- `index.html`
- `fonts/fonts.css`
- `voiceover.mp3`
- `voiceover_explainer.mp3`
- `transcript.json`

---
title: "Installation"
description: "Prerequisites for opening and rendering the project: Git LFS for binary assets, HyperFrames CLI, and the scoped folder layout under hyperframes-launches."
---

`claude-paper-launch/` is a standalone HyperFrames composition inside the [heygen-com/hyperframes-launches](https://github.com/heygen-com/hyperframes-launches) monorepo. The master cut lives at `index.html`: composition id `claude-paper`, frame size 1920×1080, duration 53.3s. Ten scene plates load from `compositions/` via `data-composition-src`, and audio/SFX elements reference root-level MP3 paths. Opening or rendering requires Git LFS for binary assets, the HyperFrames CLI, and outbound network access for the GSAP 3.12.5 CDN script.

## Prerequisites

| Requirement | Role in this project |
| --- | --- |
| Git + Git LFS | Pulls voiceover, font, and source-audio binaries tracked by the repo-root `.gitattributes` |
| HyperFrames CLI | Previews `index.html` in Studio and renders the 53.3s master cut to MP4 |
| Network access | Loads `gsap@3.12.5` from `cdn.jsdelivr.net` in `index.html` and every scene plate |

<Warning>
If LFS assets are not smudged, MP3 and WOFF2 files remain 131-byte pointer stubs (`version https://git-lfs.github.com/spec/v1`). Preview and render will fail on missing audio, broken typography, and silent SFX.
</Warning>

## Clone the repository

<Steps>
<Step title="Install Git LFS">

```bash
brew install git-lfs   # macOS
git lfs install
```

</Step>

<Step title="Clone hyperframes-launches">

```bash
git clone https://github.com/heygen-com/hyperframes-launches.git
cd hyperframes-launches/claude-paper-launch
```

With Git LFS installed, LFS objects download during clone.

</Step>

<Step title="Recover LFS assets after a pointer-only clone">

If binaries are still pointers, pull them explicitly:

```bash
cd hyperframes-launches
git lfs pull --include="claude-paper-launch/**"
```

For a text-only clone followed by selective fetch:

```bash
GIT_LFS_SKIP_SMUDGE=1 git clone https://github.com/heygen-com/hyperframes-launches.git
cd hyperframes-launches
git lfs pull --include="claude-paper-launch/**"
```

</Step>
</Steps>

### LFS file types

The repo-root `.gitattributes` routes these extensions through Git LFS:

| Extension | Relevant assets in `claude-paper-launch/` |
| --- | --- |
| `*.mp3` | `voiceover.mp3`, `voiceover_explainer.mp3`, `ElevenLabs_2026-06-05T10_14_44_Scotsman_gen_sp100_s50_sb75_v3 (1).mp3` |
| `*.woff2` | 21 self-hosted font files under `fonts/` |

Plain-text sources—`index.html`, `compositions/*.html`, `fonts/fonts.css`, `transcript.json`, `FRAME-claude.md`—are stored as regular Git objects.

## Install HyperFrames CLI

The `hyperframes-launches` README documents the standard workflow: run CLI commands from the project directory.

```bash
cd claude-paper-launch
hyperframes preview     # open HyperFrames Studio
hyperframes render      # render to MP4
```

If `hyperframes` is not on `PATH`, invoke it through `npx`:

```bash
npx --yes hyperframes preview
npx --yes hyperframes render
```

See the [HyperFrames CLI repository](https://github.com/heygen-com/hyperframes) for install options, lint/validate commands, and render flags.

<Note>
Unlike sibling launches such as `vfx-heygen-combined/`, `claude-paper-launch/` has no local `package.json` or `hyperframes.json`. The CLI operates directly against `index.html` as the composition root.
</Note>

## Folder layout

`claude-paper-launch/` follows the HyperFrames project shape with assets co-located at the project root rather than under an `assets/` subdirectory.

:::files
claude-paper-launch/
├── index.html                 # master composition (claude-paper, 53.3s)
├── compositions/              # scene plates loaded by data-composition-src
│   ├── connector-morph.html
│   ├── chat-response.html
│   ├── response-scroll.html
│   ├── followup-type.html
│   ├── thinking-big.html
│   ├── compose-ui.html
│   ├── sure-response.html
│   ├── thinking-big-2.html
│   ├── compose-tasklist.html
│   ├── outro.html
│   └── tesla-rap.html         # standalone explainer plate (not in master stack)
├── fonts/
│   ├── fonts.css              # shared @font-face definitions
│   └── *.woff2                # Hanken Grotesk, Newsreader, Spline Sans Mono, Galaxie Copernicus
├── voiceover.mp3              # Scotsman VO (data-start 29.6s)
├── voiceover_explainer.mp3    # neutral presenter VO (data-start 42.6s)
├── transcript.json            # word-level timing for tesla-rap captions
├── FRAME-claude.md            # Claude Paper design tokens
└── ElevenLabs_*.mp3           # source Scotsman generation (LFS)
:::

### Master composition entry point

`index.html` declares the runtime envelope on `#claude-paper`:

| Attribute | Value |
| --- | --- |
| `data-composition-id` | `claude-paper` |
| `data-width` / `data-height` | `1920` / `1080` |
| `data-duration` | `53.3` |
| `data-start` | `0` |

Ten `<div>` sections under `#claude-paper` each set `data-composition-id`, `data-composition-src`, `data-start`, `data-duration`, and `data-track-index`. Scene sources resolve relative to the project root, for example `compositions/connector-morph.html`.

### Scene composition pattern

Each file under `compositions/` wraps content in a `<template id="…-template">` and registers a paused GSAP timeline on `window.__timelines`. Scene roots declare their own `data-composition-id`, `data-width="1920"`, `data-height="1080"`, and `data-duration`. Fonts are embedded inline via `@font-face` blocks with `font-display: block` and `url(fonts/…woff2)` paths resolved from the project root.

`fonts/fonts.css` provides the canonical `@font-face` catalog for Hanken Grotesk, Newsreader, and Spline Sans Mono. Scene plates duplicate the subsets they need rather than linking `fonts.css` directly.

### Audio and transcript files

| File | Master timeline role | LFS |
| --- | --- | --- |
| `voiceover.mp3` | Scotsman VO at `data-start="29.6"`, duration 2.17s, track 8 | Yes |
| `voiceover_explainer.mp3` | Explainer VO at `data-start="42.6"`, duration 6.41s, track 184 | Yes |
| `transcript.json` | Word-level `{text, start, end}` array for `tesla-rap` karaoke timing | No (plain JSON) |

`transcript.json` holds 18 word entries spanning 0.11s–7.28s for the TSLA explainer rap sequence.

### Generated SFX (not in Git)

`index.html` references three root-level SFX files that are **not** tracked in the repository:

| File | Usage |
| --- | --- |
| `click.mp3` | UI click SFX (10 instances, `data-volume="0.85"`) |
| `toggle.mp3` | HyperFrames toggle at 4.30s (`data-duration="2.67"`) |
| `typenew.mp3` | Keystroke SFX (74 instances, `data-volume="0.2"`) |

The master timeline comment labels these as `SFX:generated`. Place the three MP3 files at the project root before preview or render, or regenerate them through your local SFX pipeline.

## Runtime dependencies

HyperFrames loads scene HTML into the master frame. Each composition pulls GSAP independently:

```html
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
```

`followup-type.html` additionally loads `CustomEase.min.js` from the same CDN. No package manager or local `node_modules` install is required for the composition itself—only the HyperFrames CLI for preview/render.

## Verify installation

<Steps>
<Step title="Confirm LFS smudge">

```bash
file voiceover.mp3 voiceover_explainer.mp3 fonts/HankenGrotesk-normal-400-latin-fe1634.woff2
```

Expected: `MPEG ADTS` or `Audio file` for MP3; `Web Open Font Format` for WOFF2. A 131-byte ASCII text file means LFS pull is incomplete.

</Step>

<Step title="Check SFX presence">

```bash
ls click.mp3 toggle.mp3 typenew.mp3
```

All three must exist at the project root. Missing files produce silent UI interactions during preview and render.

</Step>

<Step title="Open in HyperFrames Studio">

```bash
cd claude-paper-launch
hyperframes preview
```

Confirm the Studio loads `index.html`, resolves all ten `data-composition-src` paths under `compositions/`, and reports a 53.3s timeline at 1920×1080.

</Step>
</Steps>

### Expected LFS object sizes

When smudged correctly, pointer metadata resolves to these sizes:

| File | LFS size |
| --- | --- |
| `voiceover.mp3` | 153,744 bytes |
| `voiceover_explainer.mp3` | 103,697 bytes |
| `fonts/HankenGrotesk-normal-400-latin-fe1634.woff2` | 34,664 bytes |
| `fonts/GalaxieCopernicus-Book.woff2` | 76,580 bytes |

The repository tracks **26** LFS objects under `claude-paper-launch/` (4 MP3 + 21 WOFF2 + 1 additional font file).

## Position in hyperframes-launches

```text
hyperframes-launches/          # monorepo root
├── .gitattributes             # LFS rules for all launch folders
├── README.md                  # clone + per-project CLI workflow
├── hyperframes-launch/
├── timeline-launch/
├── variables-launch/
└── claude-paper-launch/       # ← this project
    └── index.html             # composition entry point
```

Each subdirectory is an independent HyperFrames composition. Work always starts inside `claude-paper-launch/` so relative paths (`compositions/…`, `fonts/…`, `voiceover.mp3`) resolve correctly.

## Related pages

<CardGroup>
<Card title="Quickstart" href="/quickstart">
Open `index.html` in HyperFrames preview, verify the 53.3s timeline plays, and render to MP4.
</Card>
<Card title="Preview and render" href="/preview-and-render">
Run `hyperframes preview` and `hyperframes render` against this folder and validate 1920×1080 output.
</Card>
<Card title="Fonts and assets" href="/fonts-and-assets">
Self-hosted font inventory, `fonts.css` blocks, and Git LFS binary dependencies.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
Recovery for missing LFS audio/SFX, `font-display:block` stalls, and timeline registration failures.
</Card>
</CardGroup>

---

## 03. Quickstart

> First successful invocation: open index.html in HyperFrames preview, verify the 53.3s timeline plays, and render to MP4.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/03-quickstart.md
- Generated: 2026-06-10T06:31:53.132Z

### Source Files

- `index.html`
- `compositions/connector-morph.html`
- `compositions/chat-response.html`
- `compositions/outro.html`

---
title: "Quickstart"
description: "First successful invocation: open index.html in HyperFrames preview, verify the 53.3s timeline plays, and render to MP4."
---

`claude-paper-launch/index.html` is the root HyperFrames composition `claude-paper`: a 1920×1080 master cut with `data-duration="53.3"`, ten scene slots under `compositions/`, a GSAP seam timeline registered on `window.__timelines["claude-paper"]`, and synced voiceover/SFX audio tracks. Run `npx hyperframes preview` from this folder to open HyperFrames Studio against that entry point, scrub the full timeline, then `npx hyperframes render` to produce an MP4.

## Prerequisites

| Dependency | Required | Notes |
| --- | --- | --- |
| Node.js 22+ | Yes | HyperFrames CLI runtime |
| FFmpeg | Yes | Local MP4 encoding |
| Git LFS | Yes | `voiceover.mp3`, `voiceover_explainer.mp3`, and `fonts/*.woff2` are LFS objects |
| HyperFrames CLI | Via `npx` | No global install required |

<Note>
Pull LFS assets before preview or render. Pointer files (~131 bytes) mean audio and fonts have not downloaded yet. From the repo root: `git lfs pull --include="claude-paper-launch/**"`.
</Note>

See [Installation](/installation) for full setup. `index.html` references `click.mp3`, `toggle.mp3`, and `typenew.mp3` (commented as generated SFX); those files are not tracked in git—visual preview still works, but SFX will be silent until those assets exist locally.

## Project layout

```text
claude-paper-launch/
├── index.html              # Root composition claude-paper (53.3s master cut)
├── compositions/           # Scene plates loaded via data-composition-src
│   ├── connector-morph.html
│   ├── chat-response.html
│   ├── response-scroll.html
│   ├── followup-type.html
│   ├── thinking-big.html
│   ├── compose-ui.html
│   ├── sure-response.html
│   ├── thinking-big-2.html
│   ├── compose-tasklist.html
│   ├── outro.html
│   └── tesla-rap.html      # Standalone plate; not wired into the master cut
├── fonts/                  # Self-hosted woff2 + fonts.css
├── voiceover.mp3           # Scotsman VO (plays at 29.6s)
├── voiceover_explainer.mp3 # Explainer VO (plays at 42.6s)
├── transcript.json         # Word-level timing for the Scotsman clip
└── FRAME-claude.md         # Design-system spec for scene authoring
```

Unlike sibling launch folders, `claude-paper-launch` has no `meta.json` or `hyperframes.json`. The CLI discovers the project from `index.html` alone.

## Runtime model

```mermaid
flowchart TB
  subgraph cli [HyperFrames CLI]
    preview["npx hyperframes preview"]
    render["npx hyperframes render"]
  end

  subgraph root [index.html — claude-paper]
    master["#claude-paper<br/>data-duration=53.3"]
    seamTl["window.__timelines['claude-paper']<br/>GSAP seam crossfades"]
    audio["audio tracks<br/>VO + SFX"]
  end

  subgraph scenes [compositions/*.html]
    cm["connector-morph"]
    cr["chat-response"]
    rs["response-scroll"]
    more["…7 more scenes"]
    ot["outro"]
  end

  preview --> master
  render --> master
  master --> seamTl
  master --> audio
  master -->|"data-composition-src"| cm
  master --> cr
  master --> rs
  master --> more
  master --> ot
  cm -->|"window.__timelines[id]"| seamTl
  cr --> seamTl
  ot --> seamTl
```

Each scene plate wraps content in a `<template>`, declares `data-composition-id`, `data-width="1920"`, `data-height="1080"`, and `data-duration`, builds a **paused** GSAP timeline, and registers it on `window.__timelines`. The root timeline in `index.html` only animates cross-section seams (opacity crossfades, inverse zoom-throughs, leftward cut-the-curve handoffs at `CUT`–`CUT6`); per-scene motion lives in the scene files.

## Preview the full cut

<Steps>
  <Step title="Enter the project folder">
    ```bash
    cd claude-paper-launch
    ```

    Confirm LFS assets are real binaries, not pointer stubs:

    ```bash
    file voiceover.mp3
    # expect: Audio file with MPEG ADTS … not ASCII text
    ```
  </Step>

  <Step title="Start HyperFrames Studio">
    ```bash
    npx hyperframes preview
    ```

    The CLI opens HyperFrames Studio in your browser with hot reload. The default composition is `index.html` at the project root.
  </Step>

  <Step title="Confirm composition metadata">
    In Studio (or browser devtools on the loaded page), verify the root element:

    | Attribute | Expected value |
    | --- | --- |
    | `data-composition-id` | `claude-paper` |
    | `data-width` / `data-height` | `1920` / `1080` |
    | `data-duration` | `53.3` |
    | `data-start` | `0` |

    Run `npx hyperframes compositions` to list registered compositions and durations.
  </Step>

  <Step title="Scrub and play through 53.3s">
    Use Studio transport controls to play from `0:00` through `0:53.3`. The timeline must not end early or show a black tail after the outro hold.

    Spot-check these seam times:

    | Time (s) | Section | `data-composition-id` | Expected beat |
    | --- | --- | --- | --- |
    | 0.0 | `#sec-connector` | `connector-morph` | Plus button → connectors menu → Hyperframes toggle |
    | 6.7 | `#sec-chat` | `chat-response` | Hard cut; typing in composer → send → thinking |
    | 13.0 | `#sec-response` | `response-scroll` | 0.6s opacity crossfade; answer scrolls up |
    | 19.4 | `#sec-followup` | `followup-type` | Follow-up typing: "into a video with HyperFrames?" |
    | 25.0 | `#sec-thinking` | `thinking-big` | Inverse zoom-through into giant thinking |
    | 25.8 | `#sec-compose` | `compose-ui` | HyperFrames compose tool UI (Initializing → steps) |
    | 29.6 | audio `#vo` | — | Scotsman voiceover starts inside compose player |
    | 38.8 | `#sec-sure` | `sure-response` | Leftward cut-the-curve → giant "Sure." |
    | 40.3 | `#sec-tasklist` | `compose-tasklist` | Task list; last three todos cross off |
    | 42.6 | audio `#vo-explainer` | — | Neutral explainer VO over TSLA clip |
    | 49.9 | `#sec-outro` | `outro` | "HyperFrames MCP" → "Now natively supported on" → Claude logo |
    | 53.3 | end | — | Logo held; composition completes |
  </Step>
</Steps>

<Tip>
Scene plates support local dev query params ignored by the HyperFrames runtime: `?t=6.7` seeks to a timestamp, `?dev=1` autoplays the scene timeline. Append to a loaded scene URL when debugging a single plate (for example `compositions/connector-morph.html?t=4.3&dev=1`).
</Tip>

### Lint before render

```bash
npx hyperframes lint
```

Resolve structural errors before rendering. Warnings about overlapping clips or GSAP tween overlap may be pre-existing; the cut still renders if lint reports zero errors.

## Render to MP4

<Steps>
  <Step title="Render the master composition">
    ```bash
    npx hyperframes render --output renders/claude-paper.mp4
    ```

    The CLI captures `index.html`, loads all ten `data-composition-src` scenes, muxes audio tracks, and encodes via FFmpeg.
  </Step>

  <Step title="Verify output">
    Expected render signature:

    ```text
    ✔ Capturing frames... N/N
    ✔ Encoding MP4...
    ✔ renders/claude-paper.mp4 (1920x1080, 53.3s, 30fps)
    ```

    Confirm duration is **53.3 seconds** and resolution is **1920×1080**.
  </Step>
</Steps>

<CodeGroup>
  ```bash Draft iteration
  npx hyperframes render --quality draft --output renders/draft.mp4
  ```

  ```bash Deterministic render
  npx hyperframes render --docker --output renders/claude-paper.mp4
  ```

  ```bash Single scene plate
  npx hyperframes render -c compositions/outro.html -o renders/outro.mp4
  ```
</CodeGroup>

<ParamField body="--output, -o" type="string">
  Output MP4 path. Create `renders/` first if it does not exist.
</ParamField>

<ParamField body="--quality" type="string" default="standard">
  `draft` for fast iteration; `standard` for final output.
</ParamField>

<ParamField body="--docker" type="boolean" default={false}>
  Run capture in Docker for reproducible frame output across machines.
</ParamField>

<ParamField body="-c, --composition" type="string">
  Render a scene file instead of the root `index.html`.
</ParamField>

## Section schedule reference

The master cut stacks ten sections by z-index (`#sec-connector` z-index 1 through `#sec-outro` z-index 10). Section windows are declared on each slot:

| # | Element ID | Composition | `data-start` | `data-duration` | End (s) |
| --- | --- | --- | --- | --- | --- |
| 1 | `#sec-connector` | `connector-morph` | 0 | 6.7 | 6.7 |
| 2 | `#sec-chat` | `chat-response` | 6.7 | 6.9 | 13.6 |
| 3 | `#sec-response` | `response-scroll` | 13.0 | 6.7 | 19.7 |
| 4 | `#sec-followup` | `followup-type` | 19.4 | 6.0 | 25.4 |
| 5 | `#sec-thinking` | `thinking-big` | 25.0 | 1.3 | 26.3 |
| 6 | `#sec-compose` | `compose-ui` | 25.8 | 13.3 | 39.1 |
| 7 | `#sec-sure` | `sure-response` | 38.8 | 0.4 | 39.2 |
| 8 | `#sec-thinking2` | `thinking-big-2` | 39.0 | 1.3 | 40.3 |
| 9 | `#sec-tasklist` | `compose-tasklist` | 40.3 | 9.8 | 50.1 |
| 10 | `#sec-outro` | `outro` | 49.9 | 3.4 | **53.3** |

Overlapping `data-start` values (for example `thinking-big` at 25.0s inside `compose-ui` starting at 25.8s) are intentional—seam tweens in the root timeline hand off visibility at `CUT`–`CUT6`.

## First-run failure modes

<Warning>
**LFS pointer audio** — If `voiceover.mp3` is ASCII text (~131 bytes), run `git lfs pull` before preview. Silent or missing VO at 29.6s is the most common first-run symptom.
</Warning>

<Warning>
**Missing generated SFX** — `index.html` wires 74 typenew keystroke clips and 11 click/toggle clips. Without `click.mp3`, `toggle.mp3`, and `typenew.mp3` on disk, interactions render visually but without sound.
</Warning>

<Warning>
**Timeline registration** — Each composition must register a paused GSAP timeline on `window.__timelines["<data-composition-id>"]`. A missing registration leaves that scene static for the entire section window.
</Warning>

<Warning>
**Font loading** — Scene plates use `font-display: block` and `await document.fonts.ready` before measuring text widths. Incomplete font LFS pulls cause layout drift in typing animations.
</Warning>

See [Troubleshooting](/troubleshooting) for recovery steps.

## Success criteria

A first successful invocation meets all of the following:

<Check>
`npx hyperframes preview` opens Studio and loads `index.html` without console errors on timeline registration.
</Check>

<Check>
Transport plays from 0s through 53.3s with all ten scenes visible at their scheduled windows.
</Check>

<Check>
Seam transitions fire at 6.7s (hard cut), 13.0s (crossfade), 25.2s / 26.0s (inverse zoom), 38.8s / 40.3s / 49.9s (leftward cut-the-curve).
</Check>

<Check>
`npx hyperframes render --output renders/claude-paper.mp4` produces a 1920×1080 MP4 with 53.3s duration.
</Check>

## Related pages

<CardGroup cols={2}>
  <Card title="Installation" href="/installation">
    Git LFS setup, Node.js/FFmpeg prerequisites, and folder layout under hyperframes-launches.
  </Card>
  <Card title="Overview" href="/overview">
    What the Claude Paper launch video demonstrates and its 1920×1080 runtime envelope.
  </Card>
  <Card title="Preview and render" href="/preview-and-render">
    Full CLI flag reference, quality presets, Docker mode, and scene-loading validation.
  </Card>
  <Card title="Master composition reference" href="/master-composition-reference">
    Root `claude-paper` composition: section stacking, track-index assignments, and audio wiring.
  </Card>
  <Card title="Composition model" href="/composition-model">
    `window.__timelines`, `data-composition-id`, template wrappers, and paused GSAP timelines.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Recovery for missing LFS assets, font stalls, seam misalignment, and registration failures.
  </Card>
</CardGroup>

---

## 04. HyperFrames composition model

> How root and scene compositions register timelines via window.__timelines, data-composition-id attributes, template wrappers, and GSAP paused timelines.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/04-hyperframes-composition-model.md
- Generated: 2026-06-10T06:31:10.616Z

### Source Files

- `index.html`
- `compositions/connector-morph.html`
- `compositions/chat-response.html`
- `compositions/sure-response.html`
- `compositions/outro.html`

---
title: "HyperFrames composition model"
description: "How root and scene compositions register timelines via window.__timelines, data-composition-id attributes, template wrappers, and GSAP paused timelines."
---

The `claude-paper-launch` cut is a two-tier HyperFrames project: `index.html` declares the root composition `claude-paper` (1920×1080, 53.3s) and mounts ten scene slots by `data-composition-src`, while each `compositions/*.html` plate is a `<template>`-wrapped scene that builds a paused GSAP timeline and registers it on `window.__timelines` under its `data-composition-id`. The HyperFrames runtime loads scene templates into section slots, seeks each scene timeline on its local clock, and drives the root timeline for cross-section seams only.

## Composition tiers

| Tier | File | `data-composition-id` | Timeline scope | Registration key |
|------|------|----------------------|----------------|------------------|
| Root (master) | `index.html` | `claude-paper` | Cross-section opacity, zoom-through, and cut-the-curve seams | `window.__timelines["claude-paper"]` |
| Scene | `compositions/*.html` | Per-plate id (e.g. `connector-morph`) | Intra-scene motion, typing, UI morphs, Lottie frames | `window.__timelines["<id>"]` |

Scene timelines run in **local time** starting at 0. The root timeline uses **absolute master times** (e.g. seam cuts at `CUT` 25.2s, `CUT3` 38.8s). Section visibility windows are owned by the framework via `data-start` and `data-duration` on each section div; the root GSAP timeline only blends seams between stacked sections.

```mermaid
flowchart TB
  subgraph root ["index.html — claude-paper"]
    RP["#claude-paper<br/>data-duration=53.3"]
    RT["rootTimeline<br/>gsap.timeline paused:true"]
    REG_R["window.__timelines claude-paper"]
    RP --> RT --> REG_R
  end

  subgraph slots ["Section slots — empty mount points"]
    S1["#sec-connector<br/>data-composition-src"]
    S2["#sec-chat<br/>data-composition-src"]
    SN["… #sec-outro"]
  end

  subgraph scenes ["compositions/*.html — template plates"]
    T1["template connector-morph-template"]
    T2["template chat-response-template"]
    TN["template outro-template"]
    TL1["scene tl paused:true"]
    TL2["scene tl paused:true"]
    REG1["__timelines connector-morph"]
    REG2["__timelines chat-response"]
  end

  RP --> slots
  S1 -.->|HF loads template| T1
  S2 -.->|HF loads template| T2
  T1 --> TL1 --> REG1
  T2 --> TL2 --> REG2
  REG_R -->|seeks at master clock| RT
  REG1 -->|seeks at section offset| TL1
  REG2 -->|seeks at section offset| TL2
```

## Root composition (`index.html`)

The root frame is `#claude-paper` with these attributes:

| Attribute | Value | Role |
|-----------|-------|------|
| `data-composition-id` | `claude-paper` | Registry key for the master timeline |
| `data-start` | `0` | Master timeline origin |
| `data-width` / `data-height` | `1920` / `1080` | Output envelope |
| `data-duration` | `53.3` | Total cut length in seconds |

Ten child `<div>` elements are absolutely positioned section slots (`#sec-connector` through `#sec-outro`). Each slot carries:

<ParamField body="data-composition-id" type="string" required>
Scene id that must match the loaded plate and its `window.__timelines` key.
</ParamField>

<ParamField body="data-composition-src" type="string" required>
Relative path to the scene template file, e.g. `compositions/connector-morph.html`.
</ParamField>

<ParamField body="data-start" type="number" required>
Master-clock start time in seconds when this section becomes active.
</ParamField>

<ParamField body="data-duration" type="number" required>
Section length in seconds; should match the scene plate's `data-duration`.
</ParamField>

<ParamField body="data-track-index" type="number" required>
Track ordering for the framework scheduler (sections 1–11; audio uses separate indices).
</ParamField>

Sections stack with ascending `z-index` (1–10) so later scenes paint on top during crossfades. The root timeline is created paused and registered at the end of the inline script:

```javascript
window.__timelines = window.__timelines || {};
const rootTimeline = gsap.timeline({ paused: true });
// … seam tweens at CUT, CUT2, CUT3, CUT4, CUT5, CUT6 …
window.__timelines["claude-paper"] = rootTimeline;
```

<Note>
The root timeline comment states it drives **only** cross-section opacity crossfades and transition seams—not intra-scene animation. Scene motion lives entirely in scene timelines.
</Note>

## Scene compositions (`compositions/*.html`)

Every scene file in the master cut follows the same plate structure:

1. **Template wrapper** — outer `<template id="<id>-template">` so HyperFrames can clone the plate without rendering it as a standalone document.
2. **Root div** — inner element with `data-composition-id`, `data-width="1920"`, `data-height="1080"`, and `data-duration` matching the section slot in `index.html`.
3. **Self-contained assets** — scoped `<style>` (including local `@font-face` blocks), markup, GSAP (and optionally Lottie) scripts.
4. **Paused timeline** — `gsap.timeline({ paused: true })` built in local 0-based seconds.
5. **Registry write** — `window.__timelines["<id>"] = tl` where `<id>` equals `data-composition-id`.

Example registration pattern (all scenes use this contract):

```javascript
window.__timelines = window.__timelines || {};
const tl = gsap.timeline({ paused: true });
// … scene tweens …
window.__timelines["connector-morph"] = tl;
```

Scripts resolve the scene root with `document.querySelector('[data-composition-id="<id>"]')` and scope all selectors under that element.

### Scene catalog in the master cut

| `data-composition-id` | `data-duration` | `data-start` | Template id |
|----------------------|-----------------|--------------|-------------|
| `connector-morph` | 6.7 | 0 | `connector-morph-template` |
| `chat-response` | 6.9 | 6.7 | `chat-response-template` |
| `response-scroll` | 6.7 | 13.0 | `response-scroll-template` |
| `followup-type` | 6.0 | 19.4 | `followup-type-template` |
| `thinking-big` | 1.3 | 25.0 | `thinking-big-template` |
| `compose-ui` | 13.3 | 25.8 | `compose-ui-template` |
| `sure-response` | 0.4 | 38.8 | `sure-response-template` |
| `thinking-big-2` | 1.3 | 39.0 | `thinking-big-2-template` |
| `compose-tasklist` | 9.8 | 40.3 | `compose-tasklist-template` |
| `outro` | 3.4 | 49.9 | `outro-template` |

`compositions/tesla-rap.html` (`tesla-rap`, 5.0s) uses the same template and registration pattern but is **not** mounted in `index.html`; its explainer content is authored inline inside `compose-tasklist` for the in-player beat.

## `window.__timelines` registry

`window.__timelines` is a plain object keyed by composition id. Each value is a **paused** GSAP `Timeline` instance.

| Key | Owner | Driven by |
|-----|-------|-----------|
| `claude-paper` | `index.html` | Master clock; seam cuts only |
| `connector-morph` … `outro` | Matching scene plate | Section-local clock (`0` … `data-duration`) |
| `tesla-rap` | Standalone plate | Independent preview only |

<Info>
Registration is idempotent: every script starts with `window.__timelines = window.__timelines || {}` before assigning its key. The HyperFrames runtime (outside this repo) seeks timelines by id; this project does not call `.play()` in production paths.
</Info>

### Timeline duration contract

Scene authors align GSAP timeline length with `data-duration` on the root div. Comments in scene files note that a trailing hold tween keeps the last frame visible for the framework's full section window—for example `connector-morph` holds at 6.3s so the 6.7s slot does not show a black tail before the next section.

Short beats like `sure-response` (0.4s) pack the entire motion into a sub-second timeline; the root composition's inverse zoom-through at `CUT4` (39.2s) takes over exit motion.

## Paused GSAP timelines

All compositions—root and scene—use `paused: true`. Playback is **seek-driven**, not autoplay:

- The framework advances the master clock and calls `.seek(t)` on the active timelines.
- Scene timelines never auto-run on load in the render path.
- Deterministic output requires baking animation state into GSAP tweens (including Lottie frame stepping via `onUpdate`, as in `chat-response` and `outro`).

Scene timelines commonly set initial state with `gsap.set()` at time 0, then add sequenced tweens. The root timeline pre-hides sections that participate in crossfades (`gsap.set("#sec-response", { opacity: 0 }, 0)`) and applies seam choreography at absolute times.

### Lottie integration pattern

When a scene embeds Lottie, the established pattern is:

1. Load with `autoplay: false`.
2. Neutralize `anim.goToAndStop` so only the GSAP timeline can advance frames.
3. Drive frames from a GSAP tween's `onUpdate` callback.

This keeps Lottie in sync with the paused timeline during preview and render.

## Template wrappers

Scene files are **not** full HTML documents. They are fragment templates:

```html
<template id="chat-response-template">
  <div id="cr-root" data-composition-id="chat-response" …>
    <!-- styles, markup, scripts -->
  </div>
</template>
```

HyperFrames reads `data-composition-src` on a section slot, fetches the file, and instantiates the matching `<template>` content into the slot. The template id convention is `{composition-id}-template`.

Benefits in this project:

- Scenes are hot-swappable units under `compositions/`.
- Each plate carries its own fonts and scoped CSS without polluting the root document.
- The root `index.html` stays a scheduling manifest plus seam timeline.

## Handoff constraints between scenes

Adjacent scenes are authored for seamless cuts. The composition model relies on **matching end states** at section boundaries:

| Seam | Type | Authoring requirement |
|------|------|----------------------|
| `connector-morph` → `chat-response` | Hard cut + velocity handoff | End composer in `connector-morph` mirrors `chat-response` composer layout; cursor position and easing continue across the cut |
| `chat-response` → `response-scroll` | Opacity crossfade | Shared composer position; thinking dissolves as response fades in |
| `followup-type` → `thinking-big` | Inverse zoom-through | Outbound scale/blur at `CUT`; inbound giant thinking enters at scale 1.25 |
| `compose-ui` → `sure-response` | Leftward cut-the-curve | Outgoing `xPercent` throw matches incoming left slide (`x:210 → 0`) |
| `compose-tasklist` → `outro` | Leftward cut-the-curve | Same throw/fade recipe as prior cut-the-curve seams |

Root seam constants (`CUT` 25.2, `CUT2` 26.0, `CUT3` 38.8, `CUT4` 39.2, `CUT5` 40.3, `CUT6` 49.9) must stay aligned with `data-start` boundaries and scene end states.

## Local development helpers

Scene scripts (and `connector-morph` explicitly document this) support query params **ignored by the HyperFrames runtime**:

| Param | Behavior |
|-------|----------|
| `?t=<seconds>` | `tl.seek(parseFloat(t))` — inspect a single frame |
| `?dev=1` | `tl.play()` — autoplay in a browser for local iteration |

Use these when authoring a plate in isolation before wiring it into `index.html`.

## Verification checklist

<Steps>
<Step title="Confirm id alignment">
`data-composition-id` on the scene root div, the `index.html` section slot, and the `window.__timelines` key must be identical strings.
</Step>
<Step title="Match durations">
Section `data-duration` in `index.html` must equal the scene root `data-duration` and the GSAP timeline's effective length (including trailing holds).
</Step>
<Step title="Register before render">
Every composition that should animate must assign `window.__timelines["<id>"]` after building a paused timeline. A missing key produces a static section.
</Step>
<Step title="Preview the master cut">
Open `index.html` with HyperFrames preview and confirm the 53.3s timeline advances all ten sections. See [Preview and render](/preview-and-render).
</Step>
</Steps>

## Failure modes

<Warning>
**Timeline not found** — `data-composition-id` typo or missing `window.__timelines` assignment. The section slot renders but does not animate.
</Warning>

<Warning>
**Seam pop or jump** — `data-start` drift between sections, or end-state mismatch between consecutive scene timelines. Fix by aligning the outgoing scene's final tween with the incoming scene's `gsap.set` at time 0.
</Warning>

<Warning>
**Black tail before handoff** — scene GSAP timeline shorter than `data-duration`. Add a hold tween through the section end, as `connector-morph` does at 6.3s.
</Warning>

## Related pages

<CardGroup>
<Card title="Author a scene composition" href="/author-scene-composition">
Step-by-step workflow for creating a new `compositions/*.html` plate with template wrapper, attributes, and timeline registration.
</Card>
<Card title="Edit the master timeline" href="/edit-master-timeline">
Modify section timing, z-index stacking, and root seam constants in `index.html`.
</Card>
<Card title="Master composition reference" href="/master-composition-reference">
Full root manifest: all ten sections, track indices, and audio slot assignments.
</Card>
<Card title="Scene catalog" href="/scene-catalog">
Per-scene ids, durations, narrative roles, and handoff constraints.
</Card>
<Card title="Transition grammar" href="/transition-grammar">
Seam types the root timeline implements: hard cuts, crossfades, inverse zoom-through, leftward cut-the-curve.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
Recovery for timeline registration failures, seam misalignment, and font-loading stalls.
</Card>
</CardGroup>

---

## 05. Claude Paper design system

> The four brand atoms (paper, ink, muted, clay), typography ramps, component tokens, and frame-scale authoring rules defined in FRAME-claude.md.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/05-claude-paper-design-system.md
- Generated: 2026-06-10T06:31:29.415Z

### Source Files

- `FRAME-claude.md`
- `compositions/outro.html`
- `compositions/compose-tasklist.html`
- `compositions/thinking-big.html`
- `fonts/fonts.css`

---
title: "Claude Paper design system"
description: "The four brand atoms (paper, ink, muted, clay), typography ramps, component tokens, and frame-scale authoring rules defined in FRAME-claude.md."
---

`FRAME-claude.md` is the normative design contract for the Claude Paper launch cut: YAML frontmatter holds canonical colors, typography, spacing, motion, shadows, and component tokens; the markdown body defines frame-scale authoring rules, seven plate treatments, and pre-render audits. Scene compositions in `compositions/*.html` implement the system as CSS custom properties on 1920×1080 roots with `container-type: size`, mapping spec `vw` values to `cqw` at render time.

> **Atoms are sacred · composition is free · numbers come from the script.**

## Design principles

Claude Paper is a warm editorial system tuned for video. Cream paper grounds, warm charcoal ink, muted grey chrome, and a single rationed clay accent stage each 1920×1080 frame as a printed page given motion. Hanken Grotesk carries every word; Spline Sans Mono carries every label. Weight—not italics—carries hierarchy.

Three craft tests govern every frame:

| Test | Rule |
|------|------|
| Squint | One element dominates at 3–6× the next (wordmark, claim, stat numeral, or caption pill—never two at once). |
| Silence | Sparse plates read 55–75% empty; cream paper is the brand. Quiet Ledger is the sole density exception. |
| Restraint | Clay fires once per frame at full strength. A second clay element demotes to `clay-text` or is removed. |

<Warning>
Pure `#FFFFFF` and `#000000` are banned. Decoratives (`kraft`, `manila`, `sky`, `sage`) appear only on the palette catalog plate and never compete with clay at fill strength.
</Warning>

## Brand atoms

Four canonical colors anchor the brand. All other hues are semantic aliases or palette-plate decoratives.

| Atom | Token | Hex | Role |
|------|-------|-----|------|
| Paper | `paper`, `canvas`, `primary` | `#F0EEE6` | Default full-bleed ground—warm cream, never white |
| Ink | `ink`, `secondary` | `#262624` | Load-bearing text on paper; warm charcoal, never pure black |
| Muted | `muted`, `tertiary` | `#6F6E66` | Hairlines, quiet bands, chrome labels—never carries a beat's meaning alone |
| Clay | `clay`, `accent` | `#D97757` | Single rationed accent per frame—CTA, active caption pill, stat underline, quote mark |

### Semantic extensions

| Token | Hex | Use |
|-------|-----|-----|
| `surface` | `#FAF9F5` | Lifted card ground on cream |
| `surface-2` | `#F4F1E6` | Sunken tint band; catalog plate ground |
| `accent-2` | `#CC785C` | Deeper clay (book-cloth) |
| `clay-text` | `#A8472A` | In-line word emphasis on light grounds (~AA contrast) |
| `hairline` | `#DCD8CC` | Warm hairline—replaces hard borders |
| `hairline-soft` | `#E7E3D6` | Card borders in the paper-lift recipe |
| `on-accent` | `#FBF7F0` | Text on clay fills |
| `on-ink` | `#EFEADD` | Warm cream text on ink grounds |

### Accent allocation

- **Grounds:** `paper` is the default full-bleed ground. `ink` is reserved for one or two frames per sequence (karaoke stage, closer). `surface` and `surface-2` lift cards on cream—never the reverse.
- **Clay rule:** One element per frame at full `#D97757` fill strength. Inline emphasis uses `clay-text` only—never as a fill.
- **Ink pairing:** Words land in `ink` on paper, `on-ink` on ink grounds.

```text
paper (#F0EEE6) ──default ground──► ink (#262624) text
     │                                    │
     └── surface / surface-2 cards ──────┘
ink ground (#262624) ──► on-ink (#EFEADD) text
clay (#D97757) ──once per frame──► on-accent (#FBF7F0) text
```

## Typography

Two ramps share Hanken Grotesk for display and body; Spline Sans Mono handles chrome only.

### Font families

| Role | Family | Fallbacks |
|------|--------|-----------|
| Display / body | Hanken Grotesk | Inter, system-ui, sans-serif |
| Mono / chrome | Spline Sans Mono | IBM Plex Mono, monospace |

Compositions embed subset `@font-face` blocks with `font-display: block` and map tokens to CSS variables (`--f-body`, `--f-mono`). Some scenes add Galaxie Copernicus or Newsreader for serif display beats outside the core spec.

### Reading ramp (product/UI scale, px)

Fixed-pixel hierarchy for UI-scale elements. At 1920px wide, `body` sits exactly on the legibility floor.

| Token | Size | Weight | Tracking | Line height | Notes |
|-------|------|--------|----------|-------------|-------|
| `display` | 124px (~6.45vw) | 800 | −0.03em | 0.92 | |
| `h1` | 84px (~4.4vw) | 800 | −0.025em | 0.96 | |
| `h2` | 52px (~2.7vw) | 700 | −0.02em | 1.05 | |
| `lead` | 26px (~1.35vw) | 500 | −0.01em | 1.45 | |
| `body` | 27px (1.4vw) | 400 | −0.01em | 1.65 | Load-bearing floor |
| `label` | 13px | 500 | 0.14em | 1.0 | UPPERCASE chrome only |

### Hero / display ramp (frame-native, vw)

Frame-scale type uses `vw` against the 1920 long edge. In compositions, equivalent sizes appear as `cqw` on `container-type: size` roots.

| Token | Size | Weight | Use |
|-------|------|--------|-----|
| `wordmark-mega` | 30vw | 800 | Paper Identity cover |
| `display-hero` | 14vw | 800 | |
| `claim-l` | 9vw | 800 | ≤3-word claims |
| `claim-m` | 6.2vw | 700 | 4–6-word claims |
| `section-head` | 4.2vw | 700 | 7+ word claims |
| `stat-numeral` | 18vw | 800 | Hero numerals |
| `stat-ledger` | 4.8vw | 700 | Ledger column |
| `lead-frame` | 1.9vw (~36px) | 500 | Above floor |
| `body-frame` | 1.5vw (~29px) | 400 | Above floor |
| `eyebrow` | 0.85vw | 500 | UPPERCASE chrome—below floor by design |
| `caption-pill` | 3.6vw | 700 | Karaoke pills |
| `quote-mark` | 22vw | 800 | Pull-quote closer |

### Legibility floor and fit-to-measure

Any load-bearing line—anything carrying a beat's meaning—must be **≥ 1.4vw** (~27px at 1920). Sizes under the floor (`eyebrow`, `label`) are chrome: kicker tags, indices, colophon.

Claims cap at **≤ 78vw** wide and step by word count:

| Word count | Token | Size |
|------------|-------|------|
| ≤ 3 | `claim-l` | 9vw |
| 4–6 | `claim-m` | 6.2vw |
| 7+ | `section-head` | 4.2vw |

Emphasis uses weight (700/800) or `clay-text` color—never italic.

## Layout and the vw law

| Constraint | Value |
|------------|-------|
| Primary aspect | 1920×1080 (16:9) |
| Secondary aspects | 1080×1920 (9:16), 1080×1080 (1:1) |
| Safe area (long edge) | `frame-pad` = 5vw |
| Safe area (short edge) | `frame-pad-y` = 5.5vw |
| Gutter | 2vw |
| Gap tight / loose | 1.2vw / 3.4vw |

**The vw law:** Author frame-relative sizes in `vw` against the 1920 long edge (`px ÷ 1920 × 100`). Atomic chrome—button radius, hairline, label px, shadow specs—stays in `px`. The frame, not the viewport, is the reference.

<Info>
In scene compositions, each root sets `container-type: size` and uses `cqw` 1:1 for spec `vw`, so review plates at any size preserve true frame proportions. Portrait reflow measures `vw` against the **short** edge per the aspect-ratio table in `FRAME-claude.md`.
</Info>

### Anchor defaults

Frames lean **centered** for identity, claim, focal-artifact, and closer. Editorial, ledger, and catalog plates may run **left**. No more than ~2 consecutive frames share one anchor.

## Spacing, shape, elevation, motion

### Spacing tokens

| Token | Value | Context |
|-------|-------|---------|
| `pad-x` | `clamp(28px, 5vw, 88px)` | Web context |
| `pad-y` | `clamp(64px, 9vh, 116px)` | Web context |
| `content-max` | 1280px | Web context |
| `frame-pad` | 5vw | Frame safe area (long edge) |
| `frame-pad-y` | 5.5vw | Frame safe area (short edge) |

### Rounded radii

| Token | Value | Use |
|-------|-------|-----|
| `sm` | 8px | Chips, small elements |
| `md` | 14px | Buttons, inputs, cards |
| `lg` | 22px | Large cards, panels |
| `pill` | 9999px | Pills, rails, tags, karaoke captions |

No square corners on load-bearing chrome. CTA geometry is always pill or 14px-radius button.

### Elevation

Depth ceiling is **paper lift**. At most one lifted plane per frame. The paper-lift recipe pairs `shadow-card` with a `1px solid hairline-soft` border—the shadow alone is insufficient. Hard-offset shadows, neumorphism, and inner shadows are banned.

| Token | Value |
|-------|-------|
| `shadow-soft` | `0 1px 2px rgba(38,38,36,.04), 0 12px 32px -18px rgba(38,38,36,.16)` |
| `shadow-card` | `0 1px 3px rgba(38,38,36,.05), 0 22px 50px -26px rgba(38,38,36,.20)` |

### Motion tokens

| Token | Value |
|-------|-------|
| `ease-out` | `cubic-bezier(.16, 1, .3, 1)` |
| `ease-in` | `cubic-bezier(.5, 0, .75, 0)` |
| `ease-in-out` | `cubic-bezier(.65, 0, .35, 1)` |
| `dur-slide` | 0.8s |
| `dur-enter` | 0.5s |

Entrances settle (fade + 0.4vw rise)—no slide-from-edge, scale-from-zero, or kinetic typography. Caption words, stat count-ups, and optional clay underlines may animate; paper grounds, hairlines, and clay fills must not pulse.

## Component tokens

The `components:` frontmatter block is the normative source. Resolved values reference color, typography, spacing, rounded, and shadow tokens via `{token}` interpolation.

```text
grounds          buttons & chips        cards & data           editorial
─────────        ───────────────        ─────────────          ─────────
ground-paper     button-primary         card-paper             quote-mark-clay
ground-ink       button-primary-giant   card-sunken            colophon
ground-surface   button-secondary       ledger-row
ground-sunken    chip-mono              ledger-numeral
                 chip-mono-ink          hairline-rule
                 eyebrow-rail           swatch-tile
                 caption-pill
                 caption-pill-active
```

### Grounds

| Component | Background | Text | Padding |
|-----------|------------|------|---------|
| `ground-paper` | `paper` | `ink` | `frame-pad` |
| `ground-ink` | `ink` | `on-ink` | `frame-pad` |
| `ground-surface` | `surface` | `ink` | `frame-pad` |
| `ground-sunken` | `surface-2` | `ink` | `frame-pad` |

### Buttons

| Component | Background | Typography | Rounded | Notes |
|-----------|------------|------------|---------|-------|
| `button-primary` | `clay` | `label` | `md` | Chrome-scale CTA; `on-accent` text |
| `button-primary-giant` | `clay` | `section-head` | `lg` | Frame-scale CTA; padding `1.6vw 3.2vw` |
| `button-secondary` | `paper` | `label` | `md` | `1px solid hairline`; never carries clay |

### Chips, eyebrows, captions

| Component | Role |
|-----------|------|
| `chip-mono` | Uppercase mono tag on surface ground with `hairline-soft` border |
| `chip-mono-ink` | Inverted variant for ink grounds |
| `eyebrow-rail` | Top-edge label strip in `eyebrow` typography—use on a minority of frames |
| `caption-pill` | Karaoke past/upcoming word; surface ground, reduced opacity (0.82 / 0.5) |
| `caption-pill-active` | Active karaoke word; clay fill—the brand signature |

The **caption band** is a reserved horizontal strip at the bottom **9–12vw** of the frame; the pill centers vertically within it.

### Cards and ledger

| Component | Role |
|-----------|------|
| `card-paper` | Lifted editorial card: `surface` + `shadow-card` + `hairline-soft` border |
| `card-sunken` | Un-lifted variant on `surface-2` for ledger and aside content |
| `ledger-row` | Hairline-separated row with `body-frame` typography |
| `ledger-numeral` | Right-column figures in `stat-ledger` |
| `hairline-rule` | 1px `hairline` separator |
| `swatch-tile` | Palette plate atom with color band and mono label/hex |

### Editorial chrome

| Component | Role |
|-----------|------|
| `quote-mark-clay` | Giant clay opening quote at `quote-mark` size—hero clay allowed only here |
| `colophon` | Bottom-edge metadata in `eyebrow`: index, run-date, frame number |

## Implementation in compositions

Scene plates wire the design system through CSS custom properties on composition roots:

```css
#root {
  --paper: #F0EEE6;
  --ink: #262624;
  --muted: #6F6E66;
  --clay: #D97757;
  --on-accent: #FBF7F0;
  --f-body: "Hanken Grotesk", "Inter", system-ui, sans-serif;
  --f-mono: "Spline Sans Mono", "IBM Plex Mono", monospace;
  position: relative;
  width: 1920px;
  height: 1080px;
  background: var(--paper);
  container-type: size;
  font-family: var(--f-body);
  color: var(--ink);
}
```

Common patterns across `compositions/*.html`:

- **Paper texture:** Radial-dot overlay at ~50% opacity on cream grounds (`outro`, `thinking-big`, `compose-tasklist` explainer beats).
- **Frame-scale claims:** `outro` uses `9.5cqw` weight-800 type for "HyperFrames MCP"; `compose-tasklist` nests a 6s explainer with `7cqw` h1, `13.5cqw` stat numerals, and clay chips at `1.45cqw` mono.
- **Clay rationing:** `followup-type` and `response-scroll` place clay on the send button and caret only; `compose-tasklist` limits clay to the ticker chip and caption emphasis span.
- **Local fonts:** Each composition embeds captured woff2 subsets rather than linking `fonts/fonts.css` globally.

<Steps>
<Step title="Declare atoms on the root">
Set `--paper`, `--ink`, `--muted`, `--clay`, and derived tokens as CSS variables matching `FRAME-claude.md` hex values.
</Step>
<Step title="Set container context">
Apply `width: 1920px; height: 1080px; container-type: size` on the `data-composition-id` root.
</Step>
<Step title="Map typography to cqw">
Translate hero-ramp `vw` tokens to `cqw` (1:1 swap). Keep px values for `rounded`, hairlines, and `label` chrome.
</Step>
<Step title="Apply component recipes">
Use paper-lift (`shadow-card` + `hairline-soft`), caption-band placement, and single-clay restraint per frame.
</Step>
<Step title="Run the pre-render audit">
Verify squint, silence, restraint, floor, anchor variation, and numerals-from-script before finalizing.
</Step>
</Steps>

## Frame treatments overview

Seven normative plates compose the frontmatter components. Each carries a structural move, density target, and Fixed/Free split. Plates place components—they do not restate construction.

| # | Plate | Ground | Density | Accent |
|---|-------|--------|---------|--------|
| 1 | Paper Identity | `ground-paper` | ~70% empty | None (withholds clay) |
| 2 | Oversized Claim | `ground-paper` | ~60% empty | Optional `clay-text` word |
| 3 | Karaoke Stage | `ground-ink` | ~70% empty | `caption-pill-active` |
| 4 | Focal Artifact | `ground-paper` | ~58% empty | `button-primary` |
| 5 | Quiet Ledger | `ground-paper` | Tight (exception) | Optional `clay-text` numeral |
| 6 | Palette Catalog | `ground-sunken` | ~40% empty | Clay swatch tile |
| 7 | Pull-Quote Closer | `ground-paper` | ~65% empty | `quote-mark-clay` at hero size |

## Pre-render self-audit

Run every check before finalizing a frame:

- **Squint** — one element at 3–6× dominance; demote ties.
- **Silence** — sparse plates 55–75% empty; ledger is the exception.
- **Restraint** — count clay at full strength; maximum one.
- **Floor** — load-bearing lines ≥ 1.4vw (~27px@1920).
- **Depth** — at most one lifted plane with full paper-lift recipe.
- **Geometry** — load-bearing corners use `sm`/`md`/`lg`/`pill`.
- **Anchor** — vary across consecutive frames (≤ 2 share one).
- **Element count** — ≤ 2–3 distinct elements on sparse frames.
- **Caption fidelity** — only the active word wears clay pill.
- **Numerals** — every figure comes from the script; no invented data.

<Check>
A frame that passes all audits reads as a finished still at 30fps export—every plate must stand alone without motion.
</Check>

## Related pages

<CardGroup>
<Card title="Design tokens reference" href="/design-tokens-reference">
Canonical hex values, full typography ramps, spacing, radii, motion easings, and shadow recipes from the `FRAME-claude.md` frontmatter.
</Card>
<Card title="Frame treatments" href="/frame-treatments">
Seven normative plates—Paper Identity through Pull-Quote Closer—with density, accent, and anchor constraints.
</Card>
<Card title="Fonts and assets" href="/fonts-and-assets">
Self-hosted Hanken Grotesk, Spline Sans Mono, Newsreader, and Galaxie Copernicus woff2 files plus `fonts.css` loading behavior.
</Card>
<Card title="Author a scene composition" href="/author-scene-composition">
Wrap plates in templates, set `data-composition-id`, embed local fonts, and register paused GSAP timelines on `window.__timelines`.
</Card>
</CardGroup>

---

## 06. Frame treatments

> Seven normative frame plates—Paper Identity, Oversized Claim, Karaoke Stage, Focal Artifact, Quiet Ledger, Palette Catalog, Pull-Quote Closer—and their density, accent, and anchor constraints.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/06-frame-treatments.md
- Generated: 2026-06-10T06:31:58.092Z

### Source Files

- `FRAME-claude.md`
- `compositions/thinking-big.html`
- `compositions/sure-response.html`
- `compositions/compose-tasklist.html`
- `compositions/tesla-rap.html`

---
title: "Frame treatments"
description: "Seven normative frame plates—Paper Identity, Oversized Claim, Karaoke Stage, Focal Artifact, Quiet Ledger, Palette Catalog, Pull-Quote Closer—and their density, accent, and anchor constraints."
---

`FRAME-claude.md` defines seven normative frame plates for the Claude Paper launch. Each plate is a 1920×1080 composition pattern with fixed structural moves, a target silence percentage, a single rationed clay accent, and anchor rules. The frontmatter `components:` block supplies the atoms; the **Frame Treatments** section places them. Scene compositions under `compositions/` borrow these patterns for narrative beats but the spec in `FRAME-claude.md` is the authoritative reference for density, accent, and anchor constraints.

## Global constraints

Every plate obeys three craft tests before any element is placed.

| Test | Rule | Failure signal |
|------|------|----------------|
| Squint | One element dominates at 3–6× the next | Two elements tie for attention |
| Silence | Sparse plates read 55–75% empty cream | Frame filled to look "complete" |
| Restraint | `{colors.clay}` at full strength once per frame | Two clay fills in the same plate |

Accent and anchor rules apply across all seven treatments.

<ParamField body="accent" type="enum" required>
One rationed element per frame at full `{colors.clay}` (`#D97757`). Inline word emphasis may use `{colors.clay-text}` (`#A8472A`) instead of a second fill. Decorative hues (`kraft`, `manila`, `sky`, `sage`) appear only in Palette Catalog and never compete with clay.
</ParamField>

<ParamField body="anchor" type="enum" required>
Centered for Paper Identity, Oversized Claim, Focal Artifact, and Pull-Quote Closer. Left for Quiet Ledger and Palette Catalog. Right or asymmetric is an occasional tension beat. No more than ~2 consecutive frames share the same anchor.
</ParamField>

<ParamField body="legibility floor" type="string" required>
Load-bearing copy is ≥ 1.4vw (~27px at 1920). Sizes below the floor (`eyebrow`, `label`) are chrome only.
</ParamField>

Safe area uses `{spacing.frame-pad}` (5vw long edge) and `{spacing.frame-pad-y}` (5.5vw short edge). Authoring sizes are frame-relative `vw`; composition roots set `container-type: size` so `cqw` maps 1:1 to `vw` at review scale.

```text
FRAME-claude.md
├── colors / typography / spacing / motion   ← brand atoms
├── components:                                ← reusable plate atoms
│   ground-paper, ground-ink, card-paper,
│   caption-pill, ledger-row, swatch-tile, …
└── Frame Treatments (§7 plates)              ← placement + constraints
         │
         ▼
compositions/*.html                           ← narrative scenes (borrow patterns)
```

## Treatment inventory

| # | Plate | Archetype | Silence | Anchor | Accent | Pace |
|---|-------|-----------|---------|--------|--------|------|
| 1 | Paper Identity | identity/cover | ~70% | center | none (withholds clay) | low |
| 2 | Oversized Claim | editorial/oversized-claim | ~60% | center | optional `clay-text` word | moderate |
| 3 | Karaoke Stage | brand-signature | ~70% | top + caption band | active caption pill | moderate |
| 4 | Focal Artifact | focal-artifact | ~58% | center | clay button | moderate |
| 5 | Quiet Ledger | data/ledger | tight (density exception) | left | optional `clay-text` numeral | low |
| 6 | Palette Catalog | chrome/catalog | ~40% | left | clay swatch tile | moderate |
| 7 | Pull-Quote Closer | closer | ~65% | center | clay quote mark at hero size | low |

## 1 · Paper Identity

**Move:** wordmark centered, breathing.

**Ground:** `{components.ground-paper}` with `{spacing.frame-pad}`.

**Container:** single centered column; `flex-direction: column`, `align: center`, `justify: center`.

**Composes:** `ground-paper`, `chip-mono`, `colophon`.

| Role | Element | Token |
|------|---------|-------|
| Focal | Wordmark | `{typography.wordmark-mega}` (30vw), ink on cream |
| Chrome | Kicker tag | `{components.chip-mono}` 4vw above wordmark |
| Chrome | Metadata | `{components.colophon}` pinned to bottom safe area |

**Accent:** none — the cover earns calm by withholding clay (brand-signature exception).

**Fixed:** wordmark size, font, weight; cream ground; ink color; no shadow.

**Free:** kicker copy, colophon index, sequence number.

## 2 · Oversized Claim

**Move:** fit-to-measure centered claim.

**Ground:** `{components.ground-paper}`.

**Container:** centered single column, max width 78vw.

**Composes:** `ground-paper`, `eyebrow-rail`.

| Role | Element | Token |
|------|---------|-------|
| Focal | Claim line | Size by word count (see fit-to-measure table) |
| Chrome | Top label | `{components.eyebrow-rail}` 6vw above claim |

**Fit-to-measure headline sizing:**

| Word count | Typography token | Size |
|------------|------------------|------|
| ≤ 3 | `claim-l` | 9vw |
| 4–6 | `claim-m` | 6.2vw |
| 7+ | `section-head` | 4.2vw |

One word may take `color: {colors.clay-text}` as the single in-line emphasis allowance. Otherwise the frame runs clay-free.

<Note>
Launch scenes `thinking-big`, `thinking-big-2`, `sure-response`, and `outro` adapt Oversized Claim grammar: centered paper ground, hero-scale type, and fit-to-measure sizing — but they use narrative copy (serif response lines, Lottie bursts) rather than the canonical `wordmark-mega` + `chip-mono` + `colophon` stack.
</Note>

## 3 · Karaoke Stage

**Move:** ink stage with rationed clay caption.

**Ground:** `{components.ground-ink}` — warm charcoal negative voice.

**Container:** flex column; content top-anchored 16vw from top; caption band reserved bottom 12vw.

**Composes:** `ground-ink`, `chip-mono-ink`, `caption-pill`, `caption-pill-active`.

| Role | Element | Constraint |
|------|---------|------------|
| Focal | Active word | `{components.caption-pill-active}`, centered in caption band |
| Chrome | Beat label | `{components.chip-mono-ink}` top-left of safe area |
| Chrome | Flanking words | `{components.caption-pill}` at 0.82 (past) / 0.5 (upcoming) opacity |

**Accent:** the clay active pill — the rationed element and squint winner.

**Caption band:** reserved horizontal strip at bottom 9–12vw; pill vertically centered within it.

<Info>
The Karaoke Stage is the brand signature treatment. Caption pill swap is one of the few permitted animations alongside stat count-ups and optional clay underlines.
</Info>

## 4 · Focal Artifact

**Move:** lifted paper card on cream.

**Ground:** `{components.ground-paper}`.

**Container:** centered; single artifact ~62vw × 50vw.

**Composes:** `ground-paper`, `card-paper`, `eyebrow-rail`, `button-primary`.

| Role | Element | Constraint |
|------|---------|------------|
| Focal | Lifted card | `{components.card-paper}` — squint winner via lift, not size |
| Inside card | Label, heading, CTA | `label`, `section-head`, `button-primary` bottom-right |
| Chrome | Top label | `{components.eyebrow-rail}` top-left safe corner |

**Paper-lift recipe:** `{shadows.shadow-card}` + `1px solid {colors.hairline-soft}` together — never one without the other. At most one lifted plane per frame.

<Note>
`compose-ui` and `compose-tasklist` implement Focal Artifact grammar: a centered window card on cream paper with hairline border and diffuse shadow. `compose-tasklist` nests a generated explainer inside the player viewport.
</Note>

## 5 · Quiet Ledger

**Move:** hairline-ruled rows, one numeral per row.

**Ground:** `{components.ground-paper}`.

**Container:** two-column grid (label / numeral), 4 rows, gap `{spacing.gap-tight}`. Section headline `{typography.section-head}` top-left with `margin-bottom: 2.4vw`.

**Composes:** `ground-paper`, `eyebrow-rail`, `ledger-row`, `ledger-numeral`, `hairline-rule`.

| Role | Element | Constraint |
|------|---------|------------|
| Focal | Numeral column | `{components.ledger-numeral}` on right edge — vertical run |
| Chrome | Row separators | `{components.hairline-rule}` via `ledger-row` border-bottom |
| Accent | One numeral | optional `color: {colors.clay-text}` on the figure that matters |

**Silence:** tight by design — the sole density exception. Numerals come from the script; the spec never invents figures.

<Note>
The embedded TSLA explainer inside `compose-tasklist` borrows ledger patterns: `x-stat` count-up numerals, `x-ledger` labels, and a clay `x-delta` emphasis on the base-case figure.
</Note>

## 6 · Palette Catalog

**Move:** ruled swatch grid.

**Ground:** `{components.ground-sunken}` on `{colors.surface-2}`.

**Container:** 4-column grid of `{components.swatch-tile}`, gap `{spacing.gutter}`.

**Composes:** `ground-sunken`, `swatch-tile`, `eyebrow-rail`, `colophon`.

| Role | Element | Constraint |
|------|---------|------------|
| Focal | Grid field | no single tile dominates |
| Chrome | Per-tile label | `{typography.label}` with hex inside each tile |
| Chrome | Bottom metadata | `{components.colophon}` at bottom safe edge |
| Accent | Clay tile | `{colors.clay}` swatch is the rationed accent |

Decorative hues (`kraft`, `manila`, `sky`, `sage`) may appear here and nowhere else at fill strength alongside clay.

## 7 · Pull-Quote Closer

**Move:** giant clay quote mark, ink line below.

**Ground:** `{components.ground-paper}`.

**Container:** centered single column, vertical stack.

**Composes:** `ground-paper`, `quote-mark-clay`, `colophon`.

| Role | Element | Token |
|------|---------|-------|
| Focal | Opening quote | `{components.quote-mark-clay}` at 22vw — hero-size clay allowed only here |
| Body | Quoted line | `{typography.claim-m}`, ink, max width 64vw |
| Chrome | Attribution | `{typography.eyebrow}` below line |
| Chrome | Metadata | `{components.colophon}` at bottom safe edge |

**Accent:** the clay quote mark is both the rationed accent and the squint winner. The quoted line itself stays ink.

## Launch-cut mapping

The master cut in `index.html` stacks ten narrative scenes. None are pure showcase plates; they adapt treatment grammar for product storytelling.

| Scene | Primary treatment grammar | Notes |
|-------|---------------------------|-------|
| `connector-morph` | Custom morph | Connector transition, not a canonical plate |
| `chat-response` / `response-scroll` / `followup-type` | UI narrative | Chat surface, not a spec plate |
| `thinking-big` / `thinking-big-2` | Oversized Claim | Centered hero type + Lottie on paper |
| `compose-ui` / `compose-tasklist` | Focal Artifact | Lifted compose window; tasklist embeds ledger beats |
| `sure-response` | Oversized Claim | Centered serif "Sure." at 15cqw |
| `outro` | Oversized Claim | Sequential centered claims + logo reveal |
| `tesla-rap` | Standalone explainer | Not a Claude Paper plate — red kinetic rap style, separate from the seven treatments |

<Warning>
`tesla-rap.html` uses a high-contrast red editorial aesthetic (`#E31937`, kinetic uppercase captions). Do not treat it as a Palette Catalog or Karaoke Stage reference when authoring Claude Paper plates.
</Warning>

## Aspect-ratio reflow

Treatments reflow across 16:9, 9:16, and 1:1 while holding the legibility floor against the new short edge.

| Treatment | 16:9 (1920×1080) | 9:16 (1080×1920) | 1:1 (1080×1080) |
|-----------|------------------|------------------|-----------------|
| Paper Identity | Wordmark 30vw centered | Wordmark ~22vw of short edge | Wordmark ~20vw; colophon single bottom line |
| Oversized Claim | Fit-to-measure, max 78vw | Wrap 2–3 lines; step one ramp down | Step one ramp down; max 80vw |
| Karaoke Stage | Caption band bottom 12vw | Band bottom 14vw; pills may stack | Flanking pills may drop; active only |
| Focal Artifact | Card 62×50vw centered | Card 80vw × 56vw | Card 78vw square; CTA own row |
| Quiet Ledger | 2-column, 4 rows | Single column per row | 2-column, 3 rows |
| Palette Catalog | 4-column grid | 2-column, 8 tiles | 3-column, 9 tiles |
| Pull-Quote Closer | Quote 22vw; line `claim-m` | Quote ~26vw; line wraps | Quote ~22vw; line max 78vw |

Aspect re-scales are guidance, not strict numerics — a 9:16 plate may need a half-step adjustment per script word count.

## Pre-render self-audit

Run every check before finalizing a frame plate.

<Steps>
<Step title="Squint and silence">
Confirm one element dominates at 3–6× the next. Sparse plates read 55–75% empty; Quiet Ledger is the only density exception.
</Step>
<Step title="Restraint and voltage">
Count `{colors.clay}` at full strength — exactly once. No second accent hue; decoratives stay in Palette Catalog.
</Step>
<Step title="Depth and geometry">
At most one lifted plane with the full paper-lift recipe. Every load-bearing corner uses `sm` / `md` / `lg` / `pill` radius.
</Step>
<Step title="Anchor and floor">
Centered by default for identity, claim, artifact, closer. Vary anchor across consecutive frames (≤ 2 share one). Every load-bearing line ≥ 1.4vw.
</Step>
<Step title="Caption and numerals">
Karaoke: only the active word wears the clay pill; flanking pills at 0.82 / 0.5 opacity. Ledger numerals come from the script — no invented figures.
</Step>
</Steps>

## Authoring a new plate

When creating or editing a scene composition, select the treatment that matches the beat's structural move, then wire the HyperFrames composition shell.

<Steps>
<Step title="Select treatment">
Match the beat to one of the seven plates by move (cover, claim, caption stage, lifted card, ledger, swatch grid, closer).
</Step>
<Step title="Resolve tokens">
Pull ground, typography, and component values from `FRAME-claude.md` frontmatter. Use `vw` / `cqw` for frame-scale type; keep atomic chrome in `px`.
</Step>
<Step title="Implement composition">
Wrap in a `<template>`, set `data-composition-id`, `data-width="1920"`, `data-height="1080"`, `data-duration`, embed local fonts, build a paused GSAP timeline, register on `window.__timelines`.
</Step>
<Step title="Verify constraints">
Run the self-audit checklist. Confirm clay count, anchor variation, and legibility floor before preview or render.
</Step>
</Steps>

## Related pages

<CardGroup>
<Card title="Claude Paper design system" href="/claude-paper-design-system">
Brand atoms, typography ramps, component tokens, and frame-scale authoring rules from FRAME-claude.md.
</Card>
<Card title="Design tokens reference" href="/design-tokens-reference">
Canonical color hexes, typography ramps, spacing, motion easings, and component frontmatter keys.
</Card>
<Card title="Author a scene composition" href="/author-scene-composition">
Create or edit compositions/*.html plates with template wrappers and GSAP timeline registration.
</Card>
<Card title="Scene catalog" href="/scene-catalog">
All scene compositions with ids, durations, narrative roles, and handoff constraints.
</Card>
</CardGroup>

---

## 07. Transition grammar

> Cross-section seam types used in the master cut: hard cuts, opacity crossfades, inverse zoom-through, and leftward cut-the-curve with velocity-matched handoffs.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/07-transition-grammar.md
- Generated: 2026-06-10T06:32:14.215Z

### Source Files

- `index.html`
- `compositions/followup-type.html`
- `compositions/thinking-big.html`
- `compositions/compose-ui.html`
- `compositions/sure-response.html`
- `compositions/outro.html`

---
title: "Transition grammar"
description: "Cross-section seam types used in the master cut: hard cuts, opacity crossfades, inverse zoom-through, and leftward cut-the-curve with velocity-matched handoffs."
---

Cross-section seams in the 53.3s master cut are authored exclusively in the root GSAP timeline registered as `window.__timelines["claude-paper"]` inside `index.html`. The timeline drives opacity, scale, blur, and horizontal throw on ten absolutely positioned section wrappers (`#sec-connector` through `#sec-outro`); scene compositions own their internal motion. HyperFrames controls section visibility windows from each section's `data-start` and `data-duration`; the root timeline only blends the boundaries between those windows.

## Architecture

All ten sections fill the 1920×1080 frame and stack by `z-index` (later sections paint on top). Sections that participate in scale, blur, or throw transitions declare `will-change: transform, filter, opacity` in the root stylesheet. The page and composition backgrounds use paper `#F0EEE6` so exposed edges during crossfades and mid-throw hard cuts remain visually continuous.

```text
index.html (#claude-paper, 53.3s)
├── HyperFrames runtime     → section visibility from data-start / data-duration
├── window.__timelines["claude-paper"]  → seam blends only (opacity, scale, blur, xPercent)
└── compositions/*.html     → per-scene GSAP timelines on window.__timelines[id]
```

<Info>
The master timeline comment states it drives **only** cross-section opacity crossfades and seam blends—no padding or section timing. Changing when a section appears requires editing `data-start` on the section div, not adding tweens to the root timeline.
</Info>

## Seam type catalog

The master cut uses four seam families across eight active boundaries (seam 1 is implicit; seams 2–8 are scripted).

| Seam | Boundary | Type | Cut time | Outgoing | Incoming |
|------|----------|------|----------|----------|----------|
| 1 | `connector-morph` → `chat-response` | Hard cut | 6.7s | — | — |
| 2 | `chat-response` → `response-scroll` | Opacity crossfade | 13.0s | `#sec-chat` → 0 | `#sec-response` → 1 |
| 3 | `followup-type` → `thinking-big` | Inverse zoom-through | `CUT` = 25.2s | `#sec-followup` | `#sec-thinking` |
| 4 | `thinking-big` → `compose-ui` | Inverse zoom-through | `CUT2` = 26.0s | `#sec-thinking` | `#sec-compose` |
| 5 | `compose-ui` → `sure-response` | Leftward cut-the-curve | `CUT3` = 38.8s | `#sec-compose` | `#sec-sure` |
| 6 | `sure-response` → `thinking-big-2` | Inverse zoom-through | `CUT4` = 39.2s | `#sec-sure` | `#sec-thinking2` |
| 7 | `thinking-big-2` → `compose-tasklist` | Leftward cut-the-curve | `CUT5` = 40.3s | `#sec-thinking2` | `#sec-tasklist` |
| 8 | `compose-tasklist` → `outro` | Leftward cut-the-curve | `CUT6` = 49.9s | `#sec-tasklist` | `#sec-outro` |

Seams 3–4 and 6 overlap their section `data-start` values by design: for example, `sec-thinking` starts at 25.0s but the zoom-through cut fires at 25.2s, and `sec-compose` starts at 25.8s with `CUT2` at 26.0s. The outgoing scene's exit motion is authored in the root timeline, not at the section boundary alone.

## Hard cut

A hard cut switches visibility with no root-level blend tween. Seam 1 (`connector-morph` → `chat-response` at 6.7s) relies on pixel-matched layout between scenes: `connector-morph` ends with a composer box that mirrors `chat-response`'s `.composer` in position, dimensions, shadow, and border treatment. No `rootTimeline.to()` runs at 6.7s.

A second hard-cut pattern appears inside leftward and inverse-zoom seams: at the `CUT` instant the outgoing section's opacity is `set` to `0` and the incoming section is `set` to visible (or pre-blurred/zoomed). There are no intermediate crossfade frames at the cut point.

<Note>
`connector-morph` also uses a scene-level **cut-the-curve** cursor handoff into `chat-response`: the cursor covers the first third of its approach with `power2.in` over 0.3s ending at 6.4s local time; `chat-response` resumes from the same position with matched velocity (`power2.out`). That handoff is authored in the scene timelines, not in the root `CUT` constants.
</Note>

## Opacity crossfade

Seam 2 dissolves `chat-response` into `response-scroll` over 0.6s starting at 13.0s (global). Both sections tween opacity in parallel with `ease: "power1.inOut"`:

```javascript
rootTimeline.set("#sec-response", { opacity: 0 }, 0);
rootTimeline.to("#sec-response", { opacity: 1, duration: 0.6, ease: "power1.inOut" }, 13.0);
rootTimeline.to("#sec-chat",      { opacity: 0, duration: 0.6, ease: "power1.inOut" }, 13.0);
```

The crossfade works because message and thin composer sit at identical positions in both plates—the UI stays rock-steady while thinking content dissolves into the scrolling answer. Only `#sec-response` needs an initial `opacity: 0` at time 0; earlier sections remain fully opaque until their seam.

## Inverse zoom-through

Used at seams 3, 4, and 6. The effect reverses a conventional zoom-through: the outgoing scene **shrinks** (recedes), blurs, and dims; at peak blur a hard cut fires; the incoming scene enters **overscaled** at 1.25 and settles to 1.0. Both sides move in the shrinking direction so velocity carries across the cut.

### Outbound phase (0.2s, starts `CUT − 0.2`)

| Property | From | To | Ease |
|----------|------|-----|------|
| `scale` | 1 | 0.8 | `power3.in` |
| `filter` | none | `blur(20px)` | `power3.in` |
| `opacity` | 1 | 0.15 | `none` |

At `CUT`: outgoing `opacity` → `0`.

### Inbound phase (hard cut + 0.5s settle)

At `CUT`: incoming set to `{ opacity: 0.15, scale: 1.25, filter: "blur(20px)" }`.

| Property | To | Duration | Ease |
|----------|-----|----------|------|
| `scale` | 1 | 0.5s | `expo.out` |
| `filter` | `blur(0px)` | 0.5s | `expo.out` |
| `opacity` | 1 | 0.5s | `expo.out` |

**Scene responsibilities:** `followup-type` holds the sent composer state after send so the root zoom can pull it back. `thinking-big` and `thinking-big-2` enter with giant centered thinking UI and hold through the settle. `compose-ui` receives the inbound zoom at 75% window scale after `thinking-big` exits post-"Rendering."

The `outro` composition reuses the same inverse zoom-through pattern internally between its three beats (`CB` = 0.7s, `CC` = 1.4s), independent of the root timeline's seam 8 hard cut into the outro section.

## Leftward cut-the-curve

Used at seams 5, 7, and 8. The outgoing section **throws left** with accelerating ease while fading; a hard cut fires mid-throw; the incoming section is already sliding left from the right so horizontal velocity continues across the cut.

### Outbound phase (0.26s, starts `CUTn − 0.26`)

```javascript
rootTimeline.to("#sec-compose", { xPercent: -13, duration: 0.26, ease: "power2.in" }, CUT3 - 0.26);
rootTimeline.to("#sec-compose", { opacity: 0.55, duration: 0.26, ease: "power2.in" }, CUT3 - 0.26);
rootTimeline.set("#sec-compose", { opacity: 0 }, CUT3);
rootTimeline.set("#sec-sure",    { opacity: 1 }, CUT3);
```

The opacity fade **1 → 0.55** on exit mirrors the incoming **0.55 → 1** on entry.

### Inbound entry state (scene-local)

Incoming plates initialize with a fixed right offset and partial opacity so the first local tween completes the handoff:

| Composition | Initial state | Local settle |
|-------------|---------------|--------------|
| `sure-response` | `x: 210`, `opacity: 0.55`, `scale: 1.045` | `x: 0`, `opacity: 1`, `scale: 1` in 0.18s |
| `compose-tasklist` | `win` at `x: 210`, `opacity: 0.55` | `x: 0`, `opacity: 1` in 0.45s |
| `outro` beat A | `.mcp` at `x: 210`, `opacity: 0.55`, `scale: 1.02` | `x: 0`, `opacity: 1`, `scale: 1` in 0.4s |

**Scene responsibilities:** `compose-ui` ends with the cursor sweeping left off-frame (`left: '-12%'`, `ease: 'power2.in'`) after the send tap at local time 12.0s—the root timeline cuts mid-sweep into `sure-response`. `compose-tasklist` arrives **mid-checklist** (first four tasks already done) because the cut lands partway through the pipeline beat.

## Velocity-matched handoffs

Velocity matching appears at two levels:

1. **Root ↔ scene opacity symmetry** — leftward exits fade to 0.55 as entries rise from 0.55, preserving luminance continuity at the cut.
2. **Scene ↔ scene motion carry** — incoming elements start displaced (`x: 210`) and partially visible so their first tween continues the outgoing throw direction. `sure-response` explicitly documents that its leftward slide carries the cursor sweep from `compose-ui` across the hard cut.
3. **Inverse zoom direction** — outbound shrink and inbound overscale both move toward the viewer's "into the screen" axis; the hard cut lands at peak blur when apparent velocity is highest.

<Warning>
Do not add root-level `xPercent` tweens to sections that use inverse zoom-through (`#sec-followup`, `#sec-thinking`, `#sec-sure`, `#sec-thinking2`). Those sections use scale/blur only at the root; horizontal throw is reserved for leftward cut-the-curve pairs.
</Warning>

## CUT constant reference

All seam cut times are local constants in the `index.html` script block:

<ParamField body="CUT" type="number" default="25.2">
Seam 3 — `followup-type` → `thinking-big`
</ParamField>

<ParamField body="CUT2" type="number" default="26.0">
Seam 4 — `thinking-big` → `compose-ui`
</ParamField>

<ParamField body="CUT3" type="number" default="38.8">
Seam 5 — `compose-ui` → `sure-response`. Aligns with `sec-sure` `data-start`.
</ParamField>

<ParamField body="CUT4" type="number" default="39.2">
Seam 6 — `sure-response` → `thinking-big-2`. Fires ~0.2s into the 0.4s `sure-response` plate.
</ParamField>

<ParamField body="CUT5" type="number" default="40.3">
Seam 7 — `thinking-big-2` → `compose-tasklist`. Aligns with `sec-tasklist` `data-start`.
</ParamField>

<ParamField body="CUT6" type="number" default="49.9">
Seam 8 — `compose-tasklist` → `outro`. Aligns with `sec-outro` `data-start`.
</ParamField>

## Editing seams

<Steps>
<Step title="Pick the seam family">

Use opacity crossfade only when UI anchors align between consecutive chat plates. Use inverse zoom-through for chat-to-tool or tool-to-thinking scale changes. Use leftward cut-the-curve when horizontal motion should carry across a reply or card transition.

</Step>
<Step title="Align section timing and CUT constants">

Set the incoming section's `data-start` to the hard-cut instant (or slightly before for zoom-through overlap). Update the matching `CUT` / `CUT2`–`CUT6` constant and the outbound tween offset (`CUT − 0.2` or `CUT − 0.26`).

</Step>
<Step title="Author the incoming scene entry state">

For leftward cuts, set the incoming root child to `x: 210`, `opacity: 0.55` in the scene timeline's initial `gsap.set`. For inverse zoom-through, hide the incoming section at the root with `rootTimeline.set("#sec-*", { opacity: 0 }, 0)` and let the root inbound set handle overscale and blur.

</Step>
<Step title="Verify in preview">

Seek the root timeline to `CUT − 0.5` through `CUT + 0.5` in HyperFrames preview. Confirm paper shows through any exposed edge, blur peaks before the hard cut, and no double-exposure flash occurs on the incoming section.

</Step>
</Steps>

## Failure modes

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| Flash of wrong section at seam | Incoming section not hidden at `t=0` | Add `rootTimeline.set("#sec-*", { opacity: 0 }, 0)` |
| Jump in composer position at 6.7s | `connector-morph` end state drifted from `chat-response` | Re-match `.composer` / `.lcomposer` dimensions and shadow |
| Zoom feels like a dissolve | Outbound/inbound scales not paired | Keep outbound `0.8` and inbound start `1.25`; cut at peak blur |
| Leftward cut stutters | Incoming scene starts at `x: 0` | Set incoming element to `x: 210`, `opacity: 0.55` before first tween |
| Seam early/late vs audio | `CUT` constant out of sync with `data-start` | Reconcile `CUTn` with section `data-start` and scene exit beats |

## Related pages

<CardGroup>
<Card title="Edit the master timeline" href="/edit-master-timeline">
Modify `data-start`, `data-duration`, z-index stacking, and `CUT`–`CUT6` constants in `index.html`.
</Card>
<Card title="Master composition reference" href="/master-composition-reference">
Full section stack: ids, durations, track indices, and `data-composition-src` paths.
</Card>
<Card title="Scene catalog" href="/scene-catalog">
Per-plate narrative roles and handoff constraints for each composition.
</Card>
<Card title="Composition model" href="/composition-model">
How `window.__timelines` registration and `data-composition-id` interact with the HyperFrames runtime.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
Recovery for seam misalignment, timeline registration failures, and preview glitches.
</Card>
</CardGroup>

---

## 08. Preview and render

> Run hyperframes preview and hyperframes render against the claude-paper-launch folder, confirm 1920×1080 output, and validate scene loading from compositions/.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/08-preview-and-render.md
- Generated: 2026-06-10T06:33:51.523Z

### Source Files

- `index.html`
- `compositions/connector-morph.html`
- `compositions/compose-ui.html`
- `compositions/compose-tasklist.html`
- `compositions/outro.html`

---
title: "Preview and render"
description: "Run hyperframes preview and hyperframes render against the claude-paper-launch folder, confirm 1920×1080 output, and validate scene loading from compositions/."
---

The `claude-paper-launch` project is a HyperFrames composition rooted at `index.html`: the master `#claude-paper` node declares `data-width="1920"`, `data-height="1080"`, and `data-duration="53.3"`, and mounts ten scene plates from `compositions/` via `data-composition-src`. Preview and render both target this folder as the project directory.

## Prerequisites

Before preview or render, confirm:

- HyperFrames CLI is installed (`npx hyperframes` or a global `hyperframes` binary).
- Git LFS assets are pulled — voiceover MP3s and SFX files (`click.mp3`, `toggle.mp3`, `typenew.mp3`) are LFS-tracked; pointer stubs produce silent audio at render time.
- Chrome/ffmpeg dependencies pass `hyperframes doctor` (see [Installation](/installation)).

<Note>
The scoped folder has no `package.json` or local README. Run all commands from inside `claude-paper-launch/` (or pass the folder path as the `DIR` argument).
</Note>

## Project layout

```text
claude-paper-launch/
├── index.html              # Master composition (claude-paper)
├── compositions/           # Scene plates loaded by data-composition-src
│   ├── connector-morph.html
│   ├── chat-response.html
│   ├── response-scroll.html
│   ├── followup-type.html
│   ├── thinking-big.html
│   ├── compose-ui.html
│   ├── sure-response.html
│   ├── thinking-big-2.html
│   ├── compose-tasklist.html
│   ├── outro.html
│   └── tesla-rap.html      # Standalone plate (not mounted in index.html)
├── fonts/                  # Self-hosted woff2 for scene @font-face blocks
├── voiceover.mp3
├── voiceover_explainer.mp3
├── transcript.json
└── FRAME-claude.md         # Design spec: 1920×1080 @ 30fps primary export
```

## Preview the master cut

<Steps>
<Step title="Start the studio">

From `claude-paper-launch/`:

```bash
npx hyperframes preview .
```

<ParamField body="DIR" type="string">
Project directory. Defaults to the current working directory when omitted.
</ParamField>

<ParamField body="--port" type="number" default="3002">
Preview server port.
</ParamField>

<ParamField body="--no-open" type="boolean" default="false">
Skip automatic browser launch.
</ParamField>

</Step>

<Step title="Open the master composition">

The studio loads `index.html` and resolves the `claude-paper` composition. Scrub the 53.3s timeline and confirm all ten stacked sections animate in z-index order (`#sec-connector` through `#sec-outro`).

</Step>

<Step title="Spot-check scene handoffs">

Pause at seam times defined in the root GSAP timeline:

| Seam | Time (s) | Transition type |
|------|----------|-----------------|
| connector → chat | 6.7 | Hard cut |
| chat → response | 13.0 | Opacity crossfade (0.6s) |
| follow-up → thinking | 25.2 | Inverse zoom-through |
| thinking → compose UI | 26.0 | Inverse zoom-through |
| compose → "Sure." | 38.8 | Leftward cut-the-curve |
| "Sure." → thinking 2 | 39.2 | Inverse zoom-through |
| thinking 2 → task list | 40.3 | Leftward cut-the-curve |
| task list → outro | 49.9 | Leftward cut-the-curve |

</Step>
</Steps>

### Preview a single scene plate

Scene files under `compositions/` use `<template>` wrappers and register paused GSAP timelines on `window.__timelines`. For isolated iteration, open a plate directly in the browser and use local dev query params:

```bash
# Seek to 3.1s into connector-morph
open "compositions/connector-morph.html?t=3.1"

# Autoplay the plate timeline
open "compositions/connector-morph.html?dev=1"
```

<Tip>
`?t=` and `?dev=1` are local dev helpers inside scene `<script>` blocks. The HyperFrames runtime ignores them during preview and render.
</Tip>

## Render to MP4

<Steps>
<Step title="Run a draft render (fast iteration)">

```bash
npx hyperframes render . \
  --quality draft \
  --workers 1 \
  --output renders/claude-paper-draft.mp4
```

</Step>

<Step title="Run a production render">

```bash
npx hyperframes render . \
  --quality standard \
  --fps 30 \
  --output renders/claude-paper.mp4
```

Default render settings when flags are omitted:

| Flag | Default | Project value |
|------|---------|---------------|
| `--fps` | 30 | Matches `FRAME-claude.md` export spec |
| `--quality` | `standard` | — |
| `--format` | `mp4` | — |
| `--output` | `renders/<name>.mp4` | Override with `-o` |
| `--resolution` | Composition native | 1920×1080 (landscape) |

</Step>

<Step title="Verify output dimensions">

Confirm the rendered file is 1920×1080:

```bash
ffprobe -v error -select_streams v:0 \
  -show_entries stream=width,height,duration \
  -of csv=p=0 renders/claude-paper.mp4
```

Expected: `1920,1080,<duration>`.

</Step>
</Steps>

### Render flags reference

<ParamField body="-o, --output" type="string">
Output path. Example: `renders/claude-paper.mp4`.
</ParamField>

<ParamField body="-f, --fps" type="number | rational" default="30">
Frame rate. Accepts integers (24, 25, 30, 60) or ffmpeg-style rationals.
</ParamField>

<ParamField body="-q, --quality" type="draft | standard | high" default="standard">
Encoder quality preset. Use `draft` for iteration.
</ParamField>

<ParamField body="-w, --workers" type="number | auto" default="auto">
Parallel Chrome capture workers. Use `--workers 1` when Lottie-heavy scenes (outro logo, thinking bursts) cause instability.
</ParamField>

<ParamField body="--resolution" type="preset">
Output resolution preset. `landscape` maps to 1920×1080. Aspect ratio must match the composition; scale must be an integer multiple.
</ParamField>

<ParamField body="--strict" type="boolean" default="false">
Fail render on lint errors. Useful after fixing missing audio assets.
</ParamField>

<Warning>
`hyperframes render -c compositions/outro.html` renders a single plate only. Sub-compositions must be referenced from `index.html` via `data-composition-src` to appear in the master cut.
</Warning>

## 1920×1080 runtime envelope

The frame size is declared at three layers:

| Layer | Declaration |
|-------|-------------|
| Viewport | `<meta name="viewport" content="width=1920, height=1080" />` |
| Master root | `data-width="1920"` `data-height="1080"` on `#claude-paper` |
| Scene plates | `data-width="1920"` `data-height="1080"` on each `*-root` div inside `<template>` |
| CSS | `width: 1920px; height: 1080px` on `html`, `body`, and `#claude-paper` |

Scene plates use `container-type: size` and `cqw` units so frame-relative sizing holds at review scale and at full 1920×1080 capture.

## Scene loading from compositions/

HyperFrames loads scene HTML from `data-composition-src` paths on empty section `<div>` elements in `index.html`. Each referenced file follows the composition model:

1. Wrap content in `<template id="{id}-template">`.
2. Set `data-composition-id`, `data-width`, `data-height`, `data-duration` on the root element.
3. Embed local `@font-face` blocks pointing at `fonts/*.woff2`.
4. Build a paused GSAP timeline and register it: `window.__timelines["{id}"] = tl`.

```mermaid
sequenceDiagram
    participant CLI as hyperframes CLI
    participant Studio as Preview / Render runtime
    participant Index as index.html
    participant Scene as compositions/*.html
    participant TL as window.__timelines

    CLI->>Studio: preview . / render .
    Studio->>Index: Load claude-paper (1920×1080, 53.3s)
    loop Each data-composition-src section
        Index->>Scene: Fetch template plate
        Scene->>TL: Register scene timeline (paused)
        Studio->>TL: Seek scene at section data-start
    end
    Index->>TL: Register claude-paper rootTimeline (seam crossfades)
    Studio->>Studio: Composite + capture frames @ 30fps
```

### Mounted scenes in the master cut

| Section ID | Composition ID | Source | Start (s) | Duration (s) |
|------------|----------------|--------|-----------|--------------|
| `#sec-connector` | `connector-morph` | `compositions/connector-morph.html` | 0 | 6.7 |
| `#sec-chat` | `chat-response` | `compositions/chat-response.html` | 6.7 | 6.9 |
| `#sec-response` | `response-scroll` | `compositions/response-scroll.html` | 13.0 | 6.7 |
| `#sec-followup` | `followup-type` | `compositions/followup-type.html` | 19.4 | 6.0 |
| `#sec-thinking` | `thinking-big` | `compositions/thinking-big.html` | 25.0 | 1.3 |
| `#sec-compose` | `compose-ui` | `compositions/compose-ui.html` | 25.8 | 13.3 |
| `#sec-sure` | `sure-response` | `compositions/sure-response.html` | 38.8 | 0.4 |
| `#sec-thinking2` | `thinking-big-2` | `compositions/thinking-big-2.html` | 39.0 | 1.3 |
| `#sec-tasklist` | `compose-tasklist` | `compositions/compose-tasklist.html` | 40.3 | 9.8 |
| `#sec-outro` | `outro` | `compositions/outro.html` | 49.9 | 3.4 |

`compositions/tesla-rap.html` is authored as a standalone plate (`tesla-rap`, 5.0s) and is embedded inside the compose player within `compose-tasklist`; it is not mounted directly from `index.html`.

## Validation commands

Run these before a production render to confirm composition discovery and dimensions.

### List compositions

```bash
npx hyperframes compositions .
```

Expected output (11 compositions, all 1920×1080):

```text
claude-paper       53.3s   1920×1080
connector-morph     6.7s   1920×1080   ← compositions/connector-morph.html
chat-response       6.9s   1920×1080   ← compositions/chat-response.html
…
outro               3.4s   1920×1080   ← compositions/outro.html
```

JSON output for scripting:

```bash
npx hyperframes compositions . --json
```

### Print project metadata

```bash
npx hyperframes info .
```

Reports resolution `1920x1080`, element counts, and total project size. Duration may read slightly above 53.3s when audio tracks extend past the visual timeline end.

### Lint before render

```bash
npx hyperframes lint .
```

<Check>
A clean lint run (or only warnings you accept) is the signal that scene files resolve, timelines register, and asset paths are valid.
</Check>

Known lint failure in a fresh checkout without LFS pull:

```text
✗ [index.html] audio_src_not_found: click.mp3, toggle.mp3, typenew.mp3
```

Pull LFS objects or add the missing SFX files before expecting click/type audio in preview or render.

## Render-time constraints

Scene scripts in this project are authored for the HyperFrames render batching proxy:

- Use `tl.add(() => { … }, pos)` instead of `tl.call()` for timeline callbacks.
- Drive Lottie frames from timeline `onUpdate` handlers rather than `goToAndStop`.
- Avoid `tl.recent()`, `tl.invalidate()`, and `tl.eventCallback()` — these throw under the render proxy and leave a scene static.

`compose-ui` and `followup-type` include inline comments documenting these constraints.

## Troubleshooting preview and render

| Symptom | Likely cause | Recovery |
|---------|--------------|----------|
| Silent SFX (clicks, typing) | `click.mp3`, `toggle.mp3`, `typenew.mp3` missing | `git lfs pull` in repo root; see [Fonts and assets](/fonts-and-assets) |
| Silent voiceover | `voiceover.mp3` / `voiceover_explainer.mp3` are LFS pointers | Pull LFS; verify file size is not ~131 bytes |
| Scene stays static | Timeline registration failed or render-unsafe GSAP API used | Check browser console; confirm `window.__timelines["{id}"]` exists |
| Seam pop or flash | Root `rootTimeline` cut time drifted from `data-start` | Realign `CUT`–`CUT6` constants with section boundaries; see [Edit the master timeline](/edit-master-timeline) |
| Font fallback in render | Lint `font_family_without_font_face` warnings | Scene files declare `@font-face` via CSS variables; ensure woff2 paths resolve relative to each plate |
| Page navigation timeout | Heavy font/audio load | Increase `--browser-timeout` or `--player-ready-timeout` on render |

## Related pages

<CardGroup>
<Card title="Quickstart" href="/quickstart">
First successful preview of the 53.3s master cut and a draft MP4 render.
</Card>
<Card title="HyperFrames composition model" href="/composition-model">
How `data-composition-src`, template wrappers, and `window.__timelines` registration work.
</Card>
<Card title="Master composition reference" href="/master-composition-reference">
Full `index.html` section table, z-index stacking, and audio track indices.
</Card>
<Card title="Scene catalog" href="/scene-catalog">
Per-plate durations, narrative roles, and handoff constraints.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
LFS recovery, font stalls, seam misalignment, and timeline registration failures.
</Card>
</CardGroup>

---

## 09. Edit the master timeline

> Modify the root GSAP timeline in index.html: adjust section data-start/duration, z-index stacking, seam cut times (CUT, CUT2–CUT6), and window.__timelines registration.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/09-edit-the-master-timeline.md
- Generated: 2026-06-10T06:32:44.290Z

### Source Files

- `index.html`
- `compositions/chat-response.html`
- `compositions/response-scroll.html`
- `compositions/compose-tasklist.html`
- `compositions/outro.html`

---
title: "Edit the master timeline"
description: "Modify the root GSAP timeline in index.html: adjust section data-start/duration, z-index stacking, seam cut times (CUT, CUT2–CUT6), and window.__timelines registration."
---

The `claude-paper` master cut in `index.html` splits timing across two layers: HyperFrames reads each section’s `data-start` and `data-duration` to decide when a scene composition is active, while a paused root GSAP timeline registered as `window.__timelines["claude-paper"]` drives only the cross-section seams—opacity crossfades, inverse zoom-throughs, and leftward cut-the-curve throws. The root composition runs 53.3 seconds at 1920×1080 and stacks ten absolutely positioned section divs under `#claude-paper`.

## Responsibility split

| Layer | Owner | What it controls |
| --- | --- | --- |
| Section attributes | `#claude-paper` child divs | When each `compositions/*.html` plate loads and plays its own `window.__timelines[id]` |
| Root GSAP timeline | Bottom `<script>` in `index.html` | Seam blending between stacked sections (opacity, `scale`, `filter`, `xPercent`) |
| z-index CSS | `<style>` block in `index.html` | Paint order during overlapping visibility windows |

<Note>
The root timeline comment states it drives **only** cross-section opacity crossfades. Section visibility windows belong to the HyperFrames framework. Do not move intra-scene animation into the root timeline.
</Note>

## Section schedule

Each section div carries `data-composition-id`, `data-composition-src`, `data-start`, `data-duration`, and `data-track-index`. Overlapping `data-start` values are intentional—they reserve time for seams without black frames.

| # | Element ID | Composition ID | `data-start` | `data-duration` | End (start + duration) |
| --- | --- | --- | --- | --- | --- |
| 1 | `sec-connector` | `connector-morph` | 0 | 6.7 | 6.7 |
| 2 | `sec-chat` | `chat-response` | 6.7 | 6.9 | 13.6 |
| 3 | `sec-response` | `response-scroll` | 13.0 | 6.7 | 19.7 |
| 4 | `sec-followup` | `followup-type` | 19.4 | 6.0 | 25.4 |
| 5 | `sec-thinking` | `thinking-big` | 25.0 | 1.3 | 26.3 |
| 6 | `sec-compose` | `compose-ui` | 25.8 | 13.3 | 39.1 |
| 7 | `sec-sure` | `sure-response` | 38.8 | 0.4 | 39.2 |
| 8 | `sec-thinking2` | `thinking-big-2` | 39.0 | 1.3 | 40.3 |
| 9 | `sec-tasklist` | `compose-tasklist` | 40.3 | 9.8 | 50.1 |
| 10 | `sec-outro` | `outro` | 49.9 | 3.4 | 53.3 |

The root `#claude-paper` element sets `data-duration="53.3"`, which must equal the latest section end time (currently `49.9 + 3.4`).

```text
index.html
├── #claude-paper  (data-composition-id="claude-paper", data-duration="53.3")
│   ├── #sec-connector … #sec-outro   ← data-start / data-duration / data-composition-src
│   └── <audio> elements              ← global SFX/VO (separate schedule)
└── <script>
      rootTimeline = gsap.timeline({ paused: true })
      window.__timelines["claude-paper"] = rootTimeline
```

## z-index stacking

Sections are `position: absolute; inset: 0`. Later narrative beats sit above earlier ones so crossfades and hard cuts reveal the incoming plate on top.

| z-index | Section ID | `will-change` |
| --- | --- | --- |
| 1 | `sec-connector` | — |
| 2 | `sec-chat` | — |
| 3 | `sec-response` | — |
| 4–10 | `sec-followup` … `sec-outro` | `transform, filter, opacity` |

<Warning>
Reordering z-index without matching seam logic inverts crossfade direction. If section 3 must fade in over section 2, section 3 needs the higher z-index.
</Warning>

## Seam cut constants

Six named cut times in the root script anchor outgoing throws and incoming reveals. Each maps to a transition grammar type used across the cut.

| Constant | Time (s) | Outgoing → incoming | Seam type | Root GSAP pattern |
| --- | --- | --- | --- | --- |
| *(none)* | 6.7 | `connector-morph` → `chat-response` | Hard cut | No root tween; scenes are pixel-matched at the composer |
| *(none)* | 13.0 | `chat-response` → `response-scroll` | Opacity crossfade | 0.6s mutual fade (`power1.inOut`) |
| `CUT` | 25.2 | `followup-type` → `thinking-big` | Inverse zoom-through | Outbound `scale: 0.8`, `blur(20px)`; inbound from `scale: 1.25` |
| `CUT2` | 26.0 | `thinking-big` → `compose-ui` | Inverse zoom-through | Same pattern as `CUT` |
| `CUT3` | 38.8 | `compose-ui` → `sure-response` | Leftward cut-the-curve | Outbound `xPercent: -13`, opacity `1 → 0.55`; hard cut to inbound at opacity 1 |
| `CUT4` | 39.2 | `sure-response` → `thinking-big-2` | Inverse zoom-through | Same pattern as `CUT` |
| `CUT5` | 40.3 | `thinking-big-2` → `compose-tasklist` | Leftward cut-the-curve | Same throw pattern as `CUT3` |
| `CUT6` | 49.9 | `compose-tasklist` → `outro` | Leftward cut-the-curve | Same throw pattern as `CUT3`; aligns with download click at ~49.3s in `compose-tasklist` |

Inverse zoom-through seams use a 0.2s outbound recess (`CUT - 0.2`), a hard `set` at the cut second, then a 0.5s inbound settle with `expo.out`. Leftward cut-the-curve seams use a 0.26s outbound throw (`CUTn - 0.26`) before the hard opacity swap.

```mermaid
sequenceDiagram
  participant HF as HyperFrames runtime
  participant Root as rootTimeline (claude-paper)
  participant Out as Outgoing section
  participant In as Incoming section

  HF->>Out: activate at data-start
  HF->>In: activate at overlapping data-start
  Root->>Out: throw / recess / fade (CUT window)
  Root->>In: reveal at CUT instant
  Note over Root,In: Scene timelines run independently via window.__timelines[id]
```

Scene plates pre-position elements for these handoffs—for example `sure-response` enters at `x: 210, opacity: 0.55` to match the compose-ui throw, and `compose-tasklist` opens with `win` at `x: 210, opacity: 0.55` to carry `CUT5`.

## `window.__timelines` registration

Every composition—root and scenes—registers a paused GSAP timeline on the shared global:

```javascript
window.__timelines = window.__timelines || {};
const rootTimeline = gsap.timeline({ paused: true });
// … seam tweens …
window.__timelines["claude-paper"] = rootTimeline;
```

<ParamField body="key" type="string" required>
Must match `data-composition-id` on the registering element. Root key is `claude-paper`; scene keys include `chat-response`, `response-scroll`, `compose-tasklist`, `outro`, and the other section IDs.
</ParamField>

<ParamField body="timeline" type="gsap.core.Timeline" required>
Always `{ paused: true }`. HyperFrames seeks the timeline against the master clock; scene scripts may use `?t=` or `?dev=1` query params for local scrubbing only.
</ParamField>

If the root registration key drifts from `data-composition-id="claude-paper"`, the framework cannot drive seam blending and sections may pop without transitions.

## Edit workflow

<Steps>
<Step title="Plan the time shift">

Decide whether you are moving a section boundary, changing a section’s length, or retiming a seam. List every dependent surface: adjacent `data-start`/`data-duration`, the matching `CUT` constant, scene handoff keyframes, and `<audio>` `data-start` values.

</Step>

<Step title="Update section attributes">

Edit the target `#sec-*` div and, if total runtime changes, `#claude-paper` `data-duration`. Keep intentional overlaps—for example `response-scroll` starting at 13.0 while `chat-response` ends at 13.6 leaves 0.6s for the opacity crossfade.

</Step>

<Step title="Retarget seam tweens">

Move every GSAP position argument tied to the boundary. For inverse zoom-throughs, update both the constant (`CUT`, `CUT2`, `CUT4`) and the derived offsets (`CUT - 0.2`). For leftward cuts, update `CUT3`, `CUT5`, `CUT6` and their `CUTn - 0.26` throw start.

Example—shifting the chat→response crossfade from 13.0s to 14.0s:

```javascript
rootTimeline.to("#sec-response", { opacity: 1, duration: 0.6, ease: "power1.inOut" }, 14.0);
rootTimeline.to("#sec-chat", { opacity: 0, duration: 0.6, ease: "power1.inOut" }, 14.0);
```

</Step>

<Step title="Align scene compositions">

When a cut time moves, verify the outgoing scene still finishes its throw and the incoming scene still opens at the matched pose. Scene `data-duration` on the template root must cover the visible window declared in `index.html`. Mismatches produce black tails or one-frame flashes at hard cuts.

</Step>

<Step title="Resync audio and SFX">

Voiceover (`data-start="29.6"`), explainer VO (`42.6`), click SFX (`49.30` for the download tap), and the generated type/click tracks are scheduled in absolute master time. Shift them whenever the underlying visual event moves.

</Step>

<Step title="Verify">

Preview the full cut with HyperFrames and scrub across every seam—especially hard cuts at 6.7s, 25.2s, 38.8s, 40.3s, and 49.9s. Confirm paper background `#F0EEE6` stays visible through throws so exposed edges stay seamless.

</Step>
</Steps>

## Constraints and invariants

| Invariant | Why it matters |
| --- | --- |
| `data-duration` on `#claude-paper` equals last section end | Defines render length and export envelope |
| `CUTn` aligns with incoming `data-start` (or the visual event it marks) | Prevents velocity breaks across hard cuts |
| Higher z-index on the incoming section during crossfades | Incoming plate must paint above the outgoing one |
| Paper `#F0EEE6` on `html`, `body`, and `#claude-paper` | Opaque overlaps and throws expose paper, not black |
| Scene `data-duration` ≥ scene GSAP timeline length | Avoids frozen or blank frames before the next section |
| Root key `claude-paper` on `window.__timelines` | Framework seam driver registration |

<Tip>
When lengthening a middle section, shift all downstream `data-start`, `CUT` constants, and audio timestamps together. A spreadsheet column for absolute time prevents cumulative drift.
</Tip>

## Adding or removing a section

1. Add a `#sec-*` div with `data-composition-src`, timing attributes, and a unique `data-track-index`.
2. Assign the next z-index in the `<style>` block; add `will-change` if the seam uses transform, filter, or opacity throws.
3. Author or reuse a `compositions/*.html` plate that registers `window.__timelines["your-id"]`.
4. Insert root seam tweens at the new boundary (or document a hard cut if plates are pixel-matched).
5. Recompute `#claude-paper` `data-duration` and validate the full 1920×1080 render.

Removing a section reverses the sequence; collapse overlaps so no seam references a removed element selector.

## Failure modes

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| Pop or flash at a seam | `CUT` time drifted from `data-start` | Retarget constant and `CUT ± offset` tweens together |
| Both sections visible, wrong stacking | z-index inverted | Raise z-index on the plate that should be on top |
| Black frame between scenes | Gap between section windows | Overlap `data-start`/`data-duration` or extend scene hold tweens |
| Outgoing throw with no inbound motion | Incoming scene initial state not matched | Align entry transforms with outgoing throw (see `sure-response`, `compose-tasklist`, `outro`) |
| Audio off-sync | Visual moved, `<audio>` `data-start` did not | Shift affected audio elements in absolute time |
| Seam tweens never run | Missing `window.__timelines["claude-paper"]` | Confirm registration key matches `data-composition-id` |
| Crossfade shows wrong content | Only one section faded | Ensure both `#sec-*` selectors are tweened (see seam 2 pattern) |

## Quick reference: root timeline skeleton

```javascript
window.__timelines = window.__timelines || {};
const rootTimeline = gsap.timeline({ paused: true });

// Initial hidden states for incoming plates
rootTimeline.set("#sec-response", { opacity: 0 }, 0);
// … set other inbound sections to opacity: 0 …

// Seam 2 — opacity crossfade at 13.0
rootTimeline.to("#sec-response", { opacity: 1, duration: 0.6, ease: "power1.inOut" }, 13.0);
rootTimeline.to("#sec-chat",     { opacity: 0, duration: 0.6, ease: "power1.inOut" }, 13.0);

// Seam 3 — inverse zoom-through
const CUT = 25.2;
rootTimeline.to("#sec-followup", { scale: 0.8, filter: "blur(20px)", duration: 0.2, ease: "power3.in" }, CUT - 0.2);
// … CUT2, CUT3, CUT4, CUT5, CUT6 blocks follow the same templates …

window.__timelines["claude-paper"] = rootTimeline;
```

## Related pages

<CardGroup>
<Card title="Master composition reference" href="/master-composition-reference">
Full section inventory with track-index assignments and composition source paths.
</Card>
<Card title="Transition grammar" href="/transition-grammar">
Normative definitions for hard cuts, opacity crossfades, inverse zoom-through, and leftward cut-the-curve.
</Card>
<Card title="HyperFrames composition model" href="/composition-model">
How `data-composition-id`, template wrappers, and `window.__timelines` fit together.
</Card>
<Card title="Sync audio and SFX" href="/sync-audio-and-sfx">
Retarget voiceover, explainer VO, and generated click/type tracks after timeline edits.
</Card>
<Card title="Author a scene composition" href="/author-scene-composition">
Build or adjust scene plates whose handoff poses must match root seam times.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
Recovery steps for seam misalignment and timeline registration failures.
</Card>
</CardGroup>

---

## 10. Author a scene composition

> Create or edit a compositions/*.html plate: wrap in a template, set data-composition-id and data-duration, embed local fonts, build a paused GSAP timeline, and register on window.__timelines.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/10-author-a-scene-composition.md
- Generated: 2026-06-10T06:33:05.873Z

### Source Files

- `compositions/connector-morph.html`
- `compositions/chat-response.html`
- `compositions/followup-type.html`
- `compositions/compose-ui.html`
- `compositions/outro.html`
- `FRAME-claude.md`

---
title: "Author a scene composition"
description: "Create or edit a compositions/*.html plate: wrap in a template, set data-composition-id and data-duration, embed local fonts, build a paused GSAP timeline, and register on window.__timelines."
---

Each scene in the Claude Paper launch cut is a self-contained HTML plate under `compositions/*.html`: a `<template>` wrapper, a 1920×1080 root with `data-composition-id` and `data-duration`, embedded `@font-face` blocks, a paused GSAP timeline, and registration on `window.__timelines`. HyperFrames loads the plate when `index.html` references it via `data-composition-src`; the root master timeline in `index.html` only blends section seams—scene motion lives inside each plate.

## Plate anatomy

Every scene file in `compositions/` follows the same skeleton. The outer `<template>` id matches the composition id (`{id}-template`). Inside, a single root `div` carries the runtime metadata HyperFrames reads at load time.

```text
compositions/my-scene.html
└── <template id="my-scene-template">
    └── <div data-composition-id="my-scene"
              data-width="1920"
              data-height="1080"
              data-duration="6.0">
        ├── <style>          @font-face + scoped CSS
        ├── markup           scene DOM
        └── <script>         GSAP timeline + window.__timelines registration
```

| Attribute | Required | Purpose |
| --- | --- | --- |
| `data-composition-id` | yes | Stable id; must match `window.__timelines["…"]` key and `index.html` section reference |
| `data-width` / `data-height` | yes | Frame envelope; all plates use `1920` × `1080` |
| `data-duration` | yes | Scene length in seconds; timeline must cover this span (hold tweens at the end if needed) |

The root element also gets a unique DOM id (`#cm-root`, `#cr-root`, `#f4-root`, etc.) so all CSS is scoped under one selector and never leaks into sibling sections.

## Authoring workflow

<Steps>
<Step title="Copy a neighbor plate">

Start from the scene closest in narrative role. UI-interaction scenes (`connector-morph`, `chat-response`, `followup-type`) share composer chrome; editorial beats (`outro`, `sure-response`) are thinner; tool UI (`compose-ui`, `compose-tasklist`) adds window chrome.

</Step>
<Step title="Rename identifiers consistently">

Align four names to one slug (kebab-case):

- filename: `compositions/my-scene.html`
- template id: `my-scene-template`
- `data-composition-id`: `my-scene`
- `window.__timelines["my-scene"]`

The script's root query must use the same id: `document.querySelector('[data-composition-id="my-scene"]')`.

</Step>
<Step title="Set data-duration from the script beat">

`data-duration` is the contract with the master cut. Existing durations in this project:

| Composition id | Duration (s) |
| --- | --- |
| `connector-morph` | 6.7 |
| `chat-response` | 6.9 |
| `response-scroll` | 6.7 |
| `followup-type` | 6.0 |
| `thinking-big` | 1.3 |
| `compose-ui` | 13.3 |
| `sure-response` | 0.4 |
| `thinking-big-2` | 1.3 |
| `compose-tasklist` | 9.8 |
| `outro` | 3.4 |
| `tesla-rap` | 5.0 (standalone plate, not in master stack) |

If you change duration, update the matching `data-duration` and `data-start` on the section in `index.html`.

</Step>
<Step title="Embed fonts and design tokens">

Copy the `@font-face` block from a sibling plate (or subset for minimal scenes like `outro`). Paths are relative to the plate: `url(fonts/HankenGrotesk-normal-400-latin-fe1634.woff2)`. Every face uses `font-display: block` so render frames do not flash fallback glyphs.

Declare Claude Paper atoms as CSS variables on the root, matching `FRAME-claude.md`:

```css
#my-root {
  --paper:#F0EEE6; --ink:#262624; --muted:#6F6E66; --clay:#D97757;
  --surface:#FAF9F5; --hairline:#DCD8CC; --hairline-soft:#E7E3D6;
  --f-body:"Hanken Grotesk","Inter",system-ui,sans-serif;
  --f-serif:"Newsreader",Georgia,serif;
  --f-mono:"Spline Sans Mono","IBM Plex Mono",monospace;
  position:relative; width:1920px; height:1080px; overflow:hidden;
  background:var(--paper); container-type:size;
}
```

Use `cqw` for frame-relative sizing (`2.7cqw` body type ≈ 1.4vw floor at 1920). The dotted paper grain (`::before` radial-gradient at 34px pitch) is repeated across chat-family scenes for seam continuity.

</Step>
<Step title="Build a paused GSAP timeline">

Load GSAP from the CDN, create the timeline paused, set initial states with `gsap.set`, then add tweens. Pattern used throughout the repo:

```javascript
const tl = gsap.timeline({ paused: true, defaults: { ease: 'power3.out' } });
// gsap.set(...) initial states
// tl.to(...) motion beats
// tl.to({}, { duration: 0.4 }, lastMark);  // pad to data-duration

window.__timelines = window.__timelines || {};
window.__timelines["my-scene"] = tl;
```

<Note>
HyperFrames drives scene timelines by seek position; timelines must not autoplay. The master `claude-paper` timeline in `index.html` is also `{ paused: true }`.
</Note>

</Step>
<Step title="Register and wire into the master cut">

Registration is the last line before dev helpers:

```javascript
window.__timelines["my-scene"] = tl;
```

To include the scene in the full cut, add a section placeholder in `index.html`:

```html
<div
  id="sec-my-scene"
  data-composition-id="my-scene"
  data-composition-src="compositions/my-scene.html"
  data-start="25.0"
  data-duration="6.0"
  data-track-index="12"
></div>
```

HyperFrames fetches the plate, instantiates the template, and binds `window.__timelines["my-scene"]` to the section's local clock. Seam blending (crossfades, inverse zoom-through, cut-the-curve) stays in the root script—do not duplicate it inside scene plates.

</Step>
</Steps>

## Runtime registration model

```mermaid
sequenceDiagram
  participant Index as index.html
  participant HF as HyperFrames runtime
  participant Plate as compositions/*.html
  participant TL as window.__timelines

  Index->>HF: section data-composition-src
  HF->>Plate: fetch + clone template
  Plate->>Plate: script runs (IIFE)
  Plate->>TL: __timelines[id] = paused timeline
  HF->>TL: seek(localTime) each frame
  Index->>TL: __timelines["claude-paper"] seam blends only
```

Scene scripts own intra-scene motion. The root timeline owns opacity, scale, blur, and `xPercent` at section boundaries (`CUT`, `CUT2`–`CUT6` in `index.html`).

## Render-safe authoring rules

Plates in this project follow constraints discovered during HyperFrames render. Violations often produce static frames or seam pops.

### Await fonts before measuring text

Scenes that clip-reveal typed text await `document.fonts.ready` before measuring `offsetWidth`:

```javascript
(async function () {
  if (document.fonts && document.fonts.ready) {
    try { await document.fonts.ready; } catch (e) {}
  }
  // build timeline with baked widths
})();
```

`chat-response`, `followup-type`, and `compose-ui` bake per-character or per-line widths into `tl.set` / `tl.to` calls. Do not rely on `tl.invalidate()` or `tl.recent()`—the render-time GSAP proxy does not support them.

### Keep timelines seek-deterministic

- Prefer `tl.set` with precomputed values over runtime measurement inside tweens.
- Use deterministic jitter (indexed sine) for humanized typing, not `Math.random()`.
- Drive Lottie from the timeline via `onUpdate` + `goToAndStop` override (`chat-response`, `outro`), not `autoplay: true`.

### Pad timeline length to data-duration

If the last motion beat ends early, add a hold tween so local time matches `data-duration`:

```javascript
tl.to(box, { opacity: 1, duration: 0.4 }, 6.3);  // connector-morph pads 6.7s
tl.to({}, { duration: 0.2 }, 3.2);               // outro pads 3.4s
```

A shortfall leaves a black tail before the next section or crossfade.

### Match handoff state to the previous scene

Consecutive scenes often share DOM geometry so hard cuts stay invisible:

| Seam | Outgoing end state | Incoming start state |
| --- | --- | --- |
| `connector-morph` → `chat-response` | Composer at 84×18cqw; cursor at 40.7%, 63.7% with `power2.in` | Same cursor position; continues click path |
| `chat-response` → `response-scroll` | Thin composer at 87%; message bubble visible | Overlapping layout (root crossfade) |
| `followup-type` → `thinking-big` | Scroll frozen at response bottom | Inverse zoom-through handled by root |
| `compose-ui` → `sure-response` | Cursor sweeps left off-frame | `sure-response` word enters from `x:210` |

When editing one plate in a chain, inspect the previous plate's final `gsap.set` / last tweens and the next plate's opening state.

## Local development helpers

Every plate ends with query-string helpers ignored by the HyperFrames runtime:

```javascript
const q = new URLSearchParams(location.search);
if (q.has('t')) { tl.seek(parseFloat(q.get('t')) || 0); }
else if (q.get('dev') === '1') { tl.play(); }
```

Open a plate directly (or via preview) with `?t=4.2` to scrub, or `?dev=1` to autoplay while authoring.

## Verification

After editing a plate:

1. Preview the plate in isolation with `?t=` at seam-critical times (last 0.3s and first 0.3s).
2. Preview `index.html` and confirm the section appears at the correct `data-start`.
3. Confirm `window.__timelines["your-id"]` exists in the console after load.
4. Render at 1920×1080 and check the handoff against the previous and next scene.

<Warning>
A mismatch between `data-duration` on the plate root and the section in `index.html` causes sync drift against audio (`data-start` on `<audio>` elements) and root seam constants.
</Warning>

## Common failure modes

| Symptom | Likely cause | Fix |
| --- | --- | --- |
| Scene stays on frame 0 | Missing or mistyped `window.__timelines` key | Key must equal `data-composition-id` exactly |
| Text clips on final character | Width measured before fonts loaded | `await document.fonts.ready`; bake widths |
| 1–2 frame scroll pop at section cut | Live `offsetHeight` remeasure mid-render | Cache scroll max once (`followup-type` pattern) |
| Black gap before next section | Timeline shorter than `data-duration` | Add terminal hold tween |
| Font swap flash | Missing `font-display: block` or omitted `@font-face` | Embed full face list from sibling plate |
| Lottie drifts from GSAP | `autoplay: true` on Lottie | Timeline-driven `goToAndStop` only |

## Minimal reference plate

`sure-response.html` is the smallest complete example: two Newsreader weights, one centered word, 0.4s timeline, leftward entry matched to `compose-ui`'s exit sweep.

```html
<template id="sure-response-template">
  <div id="su-root" data-composition-id="sure-response"
       data-width="1920" data-height="1080" data-duration="0.4">
    <style>/* @font-face + scoped #su-root rules */</style>
    <div class="stage"><div class="word" id="suWord">Sure.</div></div>
    <script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>
    <script>
    window.__timelines = window.__timelines || {};
    (async function () {
      if (document.fonts?.ready) { try { await document.fonts.ready; } catch (e) {} }
      const root = document.querySelector('[data-composition-id="sure-response"]');
      const word = root.querySelector('#suWord');
      gsap.set(word, { x: 210, opacity: 0.55, scale: 1.045 });
      const tl = gsap.timeline({ paused: true });
      tl.to(word, { x: 0, opacity: 1, scale: 1, duration: 0.18, ease: 'power3.out' }, 0);
      tl.to({}, { duration: 0.22 }, 0.18);
      window.__timelines['sure-response'] = tl;
    })();
    </script>
  </div>
</template>
```

`connector-morph.html` is the opposite extreme: multi-phase UI morph, cursor choreography, and a cut-the-curve handoff into `chat-response`.

## Related pages

<CardGroup>
<Card title="HyperFrames composition model" href="/composition-model">
How root and scene compositions register timelines, template wrappers, and the `window.__timelines` contract.
</Card>
<Card title="Claude Paper design system" href="/claude-paper-design-system">
Brand atoms, typography ramps, and frame-scale rules from FRAME-claude.md.
</Card>
<Card title="Scene catalog" href="/scene-catalog">
All composition ids, durations, narrative roles, and handoff constraints.
</Card>
<Card title="Edit the master timeline" href="/edit-master-timeline">
Wire a new section into index.html: data-start, z-index, and seam cut times.
</Card>
<Card title="Transition grammar" href="/transition-grammar">
Hard cuts, crossfades, inverse zoom-through, and cut-the-curve patterns between scenes.
</Card>
<Card title="Preview and render" href="/preview-and-render">
Validate scene loading and 1920×1080 output with the HyperFrames CLI.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
Recovery for timeline registration failures, font stalls, and seam misalignment.
</Card>
</CardGroup>

---

## 11. Sync audio and SFX

> Wire voiceover, explainer VO, click/toggle/type SFX tracks using data-start, data-duration, data-track-index, and data-volume on audio elements in index.html.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/11-sync-audio-and-sfx.md
- Generated: 2026-06-10T06:33:50.089Z

### Source Files

- `index.html`
- `voiceover.mp3`
- `voiceover_explainer.mp3`
- `transcript.json`
- `compositions/compose-tasklist.html`

---
title: "Sync audio and SFX"
description: "Wire voiceover, explainer VO, click/toggle/type SFX tracks using data-start, data-duration, data-track-index, and data-volume on audio elements in index.html."
---

All audio for the 53.3s `claude-paper` master cut is declared as sibling `<audio>` elements inside `#claude-paper` in `index.html`. HyperFrames reads `data-start`, `data-duration`, `data-track-index`, and `data-volume` on each element and schedules playback against the master clock. Scene GSAP timelines in `compositions/*.html` drive visuals only; audio timing is authored separately and must be converted from scene-local seconds to master seconds.

## Architecture

```text
index.html (#claude-paper, data-duration="53.3")
├── <div data-composition-src="…">  ×10   ← visual sections (data-track-index 1–11)
└── <audio src="…">                   ×87   ← voiceover + SFX (data-track-index 8, 100–185)
         │
         ▼
HyperFrames runtime  →  muxes tracks at master time t ∈ [0, 53.3]
Scene GSAP timelines →  visuals only (window.__timelines, no audio API)
```

The root GSAP script in `index.html` handles cross-section opacity and seam transitions. It does not start, stop, or volume-mix audio. When a cursor click or keystroke needs sound, add or adjust an `<audio>` row in `index.html` whose `data-start` equals the section's `data-start` plus the scene timeline's local trigger time.

<Note>
Master time formula: `data-start (audio) = data-start (section) + local_scene_time`. Example: Scotsman VO plays when `compose-ui` (section `data-start="25.8"`) reaches local `R = 3.8` → `25.8 + 3.8 = 29.6`.
</Note>

## Audio element contract

Each track is a plain HTML `<audio>` element with four scheduling attributes and a `src` pointing at a file in the `claude-paper-launch/` root.

<ParamField body="data-start" type="number (seconds)" required>
Absolute offset on the master timeline where playback begins. Uses the same clock as section `data-start` on `#claude-paper` (0 at cut start).
</ParamField>

<ParamField body="data-duration" type="number (seconds)" required>
How long HyperFrames plays or holds this clip on the master timeline. For voiceover, match the audible segment (Scotsman VO is trimmed to 2.17s). For SFX, match the source file length (`click.mp3` → 0.07, `toggle.mp3` → 2.67, `typenew.mp3` → 0.57).
</ParamField>

<ParamField body="data-track-index" type="integer" required>
Mixer lane identifier. Must be unique across all `<audio>` elements and distinct from visual section indices unless intentionally shared. Current cut uses 8 for Scotsman VO, 184 for explainer VO, 100–185 for generated SFX.
</ParamField>

<ParamField body="data-volume" type="number (0–1)" required>
Per-track gain. Voiceover tracks use `1`. UI SFX use `0.85` for `click.mp3` and `toggle.mp3`, `0.2` for `typenew.mp3`.
</ParamField>

Minimal voiceover row:

```html
<audio
  id="vo"
  src="voiceover.mp3"
  data-start="29.6"
  data-duration="2.17"
  data-track-index="8"
  data-volume="1"
></audio>
```

SFX rows follow the same shape; the comment block in `index.html` documents the generation rule: one `click.mp3` per cursor tap, `toggle.mp3` on the Hyperframes toggle, and one `typenew.mp3` per keystroke with humanized swell timing.

## Track index layout

| Range | Role | Count | Notes |
|-------|------|-------|-------|
| 1–11 | Visual sections | 10 | On `<div>` section wrappers, not `<audio>` |
| 8 | Scotsman VO | 1 | `#vo` — angry Scotsman inside compose player |
| 100–108, 183–185 | Click SFX | 11 | `click.mp3`, 0.07s, volume 0.85 |
| 102 | Toggle SFX | 1 | `toggle.mp3`, 2.67s, volume 0.85 |
| 109–182 | Type SFX | 74 | `typenew.mp3`, 0.57s, volume 0.2 |
| 184 | Explainer VO | 1 | `#vo-explainer` — neutral presenter over TSLA explainer |

<Warning>
`data-track-index` values are not required to be sequential. The cut skips index 9 on sections (jumps from `thinking-big-2` at 9 to `compose-tasklist` at 10) and uses non-contiguous SFX indices (e.g. `sfx-click-9` at 183, `sfx-click-10` at 185). Assign a new unique integer for every added track.
</Warning>

## Voiceover tracks

### Scotsman VO (`#vo`)

| Field | Value |
|-------|-------|
| `src` | `voiceover.mp3` |
| `data-start` | `29.6` |
| `data-duration` | `2.17` |
| `data-track-index` | `8` |
| `data-volume` | `1` |

Plays while the generated video runs inside the compose player in `compositions/compose-ui.html`. The scene defines `R = VS + 0.3` (local 3.8s) as video + VO start and `PEND = R + 2.17` as the pause tap that cuts off "numpties". Those map to master 29.6s and 31.77s. On-screen captions in `compose-ui` use offsets from `R` (e.g. `R + 0.11` for "Right.", `R + 1.03` for "Listen up, you wee numpties.").

`transcript.json` holds word-level `{ text, start, end }` entries for the Scotsman clip (first word at 0.11s, last at 7.28s in file time). The master `<audio>` element plays only the first 2.17s; captions and scrubber UI in the scene are authored against the truncated segment, not the full file.

### Explainer VO (`#vo-explainer`)

| Field | Value |
|-------|-------|
| `src` | `voiceover_explainer.mp3` |
| `data-start` | `42.6` |
| `data-duration` | `6.41` |
| `data-track-index` | `184` |
| `data-volume` | `1` |

Plays over the 6s TSLA explainer inside `compositions/compose-tasklist.html`. Scene local `R = VS + 0.3` with `VS = 2.0` yields master `40.3 + 2.3 = 42.6`. Caption swaps at `R + 3.4` ("our base case puts fair value near $1,450") align with ElevenLabs phrase timing noted in the scene script.

## Generated SFX inventory

HyperFrames does not derive SFX from GSAP. Each audible UI moment has a pre-declared `<audio>` row.

### Click tracks (`click.mp3`)

| ID | Master `data-start` | Scene anchor |
|----|---------------------|--------------|
| `sfx-click-0` | 1.60 | `connector-morph` + tap at 1.6 |
| `sfx-click-1` | 3.10 | `connector-morph` Connectors row tap at 3.1 |
| `sfx-click-3` | 7.48 | `chat-response` composer tap at 0.78 (section 6.7) |
| `sfx-click-4` | 9.93 | `chat-response` send tap |
| `sfx-click-5` | 20.20 | `followup-type` composer tap at 0.8 (section 19.4) |
| `sfx-click-6` | 24.89 | `followup-type` send tap |
| `sfx-click-7` | 31.77 | `compose-ui` pause tap at `PEND` |
| `sfx-click-8` | 33.20 | `compose-ui` prompt-box tap during correction |
| `sfx-click-9` | 38.42 | `compose-ui` send tap at `SEND + 0.62` (section 25.8) |
| `sfx-click-10` | 49.30 | `compose-tasklist` download pill tap at `END` (section 40.3 + 9.0) |

### Toggle track (`toggle.mp3`)

| ID | Master `data-start` | `data-duration` | Scene anchor |
|----|---------------------|-----------------|--------------|
| `sfx-toggle` | 4.30 | 2.67 | `connector-morph` Hyperframes toggle tap at 4.3 |

### Type tracks (`typenew.mp3`)

74 elements (`sfx-type-0` … `sfx-type-73`) cover humanized keystroke rhythms in three typing bursts:

| Master window | Section | Local origin |
|---------------|---------|--------------|
| 7.80 – 9.51 | `chat-response` (6.7) | Prompt typing from ~1.1s |
| 20.80 – 23.70 | `followup-type` (19.4) | Follow-up message from ~1.4s |
| 33.57 – 37.30 | `compose-ui` (25.8) | Style-correction typing from ~7.77s |

Each row uses `data-duration="0.57"` and `data-volume="0.2"`. Stagger intervals mirror the scene's `charT` / `steps()` reveal timing — when adding characters, insert a new `<audio>` at `section_start + char_land_time` and bump `data-track-index`.

## Workflow: sync a new sound

<Steps>
<Step title="Find the scene trigger time">
Open the scene composition (e.g. `compositions/chat-response.html`) and read the GSAP position of the cursor tap or typing onset. Use `?t=` seek in preview to verify the local second.
</Step>

<Step title="Convert to master time">
Add the parent section's `data-start` from `index.html`. For `chat-response` at 6.7 with a tap at local 0.78, audio `data-start` is `7.48`.
</Step>

<Step title="Add the audio row">
Insert an `<audio>` sibling after the section divs, before the root `</div>`. Set `src`, `data-duration` from the asset length, `data-volume` from the SFX class table, and a fresh `data-track-index`.
</Step>

<Step title="Preview and render">
Run `hyperframes preview` on the `claude-paper-launch` folder, scrub to the trigger, and confirm the sound aligns with the cursor. Re-render if muxed output drifts.
</Step>
</Steps>

```text
Scene GSAP (local t)  +  section data-start  =  audio data-start
        0.78          +         6.7            =       7.48
```

<Info>
When you change a section's `data-start` or trim its `data-duration` while editing the master timeline, recompute every audio `data-start` that references that section. Visual seams and audio share the master clock but are edited in separate places.
</Info>

## Asset files

| File | Role | Git LFS |
|------|------|---------|
| `voiceover.mp3` | Scotsman VO source | Yes (`*.mp3` in `.gitattributes`) |
| `voiceover_explainer.mp3` | TSLA explainer VO | Yes |
| `click.mp3` | UI click SFX | Yes (referenced; required at render) |
| `toggle.mp3` | Toggle switch SFX | Yes (referenced; required at render) |
| `typenew.mp3` | Keystroke SFX | Yes (referenced; required at render) |
| `transcript.json` | Word timings for Scotsman captions | No — metadata only, not wired to `<audio>` |

Audio binaries must be pulled with Git LFS before preview or render. A 131-byte pointer file means LFS has not been fetched.

## Verification signals

| Check | Expected result |
|-------|-----------------|
| Scotsman VO at 29.6s | Audio starts as compose player video begins; stops by pause at ~31.77s |
| Explainer VO at 42.6s | Six-second VO over task-list explainer beats |
| Click at 49.30s | `sfx-click-10` coincides with download pill press before outro cut |
| No duplicate `data-track-index` | 87 unique audio lanes; no index collision with another `<audio>` |
| Rendered MP4 | Full 53.3s mux includes VO and SFX; silent UI means missing LFS assets or wrong `data-start` |

<Tip>
To debug a single scene in isolation, open `compositions/<scene>.html?dev=1` for visuals, but remember audio only fires from `index.html` in the master composition. Always verify SFX in the root cut.
</Tip>

## Common failure modes

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| Silent clicks or typing | `click.mp3` / `toggle.mp3` / `typenew.mp3` missing (LFS) | `git lfs pull` in repo root |
| Silent voiceover | `voiceover.mp3` or `voiceover_explainer.mp3` is an LFS pointer | Pull LFS; confirm files are >1 KB |
| SFX early/late vs cursor | `data-start` not converted from scene-local time | Recompute `section.data-start + local_t` |
| VO out of sync with captions | Scene `R` / `PEND` changed but `#vo` attributes stale | Update both scene GSAP and root `<audio>` |
| Missing mixer lane | Duplicate `data-track-index` | Assign unused integer in 100–185 band |

## Related pages

<CardGroup>
<Card title="Audio track reference" href="/audio-track-reference">
Full inventory of voiceover tracks, SFX files, volumes, and `transcript.json` word timings.
</Card>
<Card title="Master composition reference" href="/master-composition-reference">
Section `data-start` / `data-duration` table and visual `data-track-index` assignments for all ten scenes.
</Card>
<Card title="Edit the master timeline" href="/edit-master-timeline">
How section timing changes cascade to seam cuts and audio offsets.
</Card>
<Card title="Preview and render" href="/preview-and-render">
Validate muxed audio in HyperFrames preview and 1920×1080 render output.
</Card>
<Card title="Fonts and assets" href="/fonts-and-assets">
Git LFS setup for binary audio, fonts, and images.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
Recovery steps for missing LFS audio, seam misalignment, and silent renders.
</Card>
</CardGroup>

---

## 12. Master composition reference

> Root claude-paper composition: 1920×1080, 53.3s duration, ten stacked sections with z-index order, data-composition-src paths, and track-index assignments.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/12-master-composition-reference.md
- Generated: 2026-06-10T06:33:41.076Z

### Source Files

- `index.html`
- `compositions/connector-morph.html`
- `compositions/response-scroll.html`
- `compositions/thinking-big-2.html`
- `compositions/compose-tasklist.html`
- `compositions/outro.html`

---
title: "Master composition reference"
description: "Root claude-paper composition: 1920×1080, 53.3s duration, ten stacked sections with z-index order, data-composition-src paths, and track-index assignments."
---

`index.html` defines the root HyperFrames composition `claude-paper`: a 1920×1080, 53.3-second master cut that stacks ten absolutely positioned section shells, loads each scene from `compositions/*.html` via `data-composition-src`, and registers a paused GSAP seam timeline on `window.__timelines["claude-paper"]`. HyperFrames owns per-section visibility windows from `data-start` and `data-duration`; the root script only blends cross-section seams.

## Root envelope

The composition root is `#claude-paper` inside `index.html`.

| Attribute | Value | Role |
|-----------|-------|------|
| `data-composition-id` | `claude-paper` | Registry key for `window.__timelines` |
| `data-start` | `0` | Master timeline origin (seconds) |
| `data-width` / `data-height` | `1920` / `1080` | Render envelope |
| `data-duration` | `53.3` | Total cut length |
| Background | `#F0EEE6` | Paper canvas; keeps opaque crossfades seamless |

`html`, `body`, and `#claude-paper` are fixed at 1920×1080 with `overflow: hidden`. GSAP 3.12.5 loads from jsDelivr.

## Section stack

Ten child `<div>` elements fill the frame (`position: absolute; inset: 0`). Each declares a scene id, source path, schedule, and `data-track-index` for the HyperFrames mixer.

| # | DOM id | `data-composition-id` | `data-composition-src` | `data-start` | `data-duration` | End (s) | z-index | `data-track-index` |
|---|--------|-------------------------|------------------------|--------------|-----------------|---------|---------|-------------------|
| 1 | `sec-connector` | `connector-morph` | `compositions/connector-morph.html` | 0 | 6.7 | 6.7 | 1 | 1 |
| 2 | `sec-chat` | `chat-response` | `compositions/chat-response.html` | 6.7 | 6.9 | 13.6 | 2 | 2 |
| 3 | `sec-response` | `response-scroll` | `compositions/response-scroll.html` | 13.0 | 6.7 | 19.7 | 3 | 3 |
| 4 | `sec-followup` | `followup-type` | `compositions/followup-type.html` | 19.4 | 6.0 | 25.4 | 4 | 4 |
| 5 | `sec-thinking` | `thinking-big` | `compositions/thinking-big.html` | 25.0 | 1.3 | 26.3 | 5 | 5 |
| 6 | `sec-compose` | `compose-ui` | `compositions/compose-ui.html` | 25.8 | 13.3 | 39.1 | 6 | 6 |
| 7 | `sec-sure` | `sure-response` | `compositions/sure-response.html` | 38.8 | 0.4 | 39.2 | 7 | 7 |
| 8 | `sec-thinking2` | `thinking-big-2` | `compositions/thinking-big-2.html` | 39.0 | 1.3 | 40.3 | 8 | 9 |
| 9 | `sec-tasklist` | `compose-tasklist` | `compositions/compose-tasklist.html` | 40.3 | 9.8 | 50.1 | 9 | 10 |
| 10 | `sec-outro` | `outro` | `compositions/outro.html` | 49.9 | 3.4 | 53.3 | 10 | 11 |

<Note>
Section end times are `data-start + data-duration`. Several pairs overlap by design (for example `sec-response` starts at 13.0 while `sec-chat` runs until 13.6) so seam crossfades have both plates on screen.
</Note>

`compositions/tesla-rap.html` exists as a standalone 5.0s plate (`data-composition-id="tesla-rap"`) but is **not** mounted in the master stack. The TSLA explainer in `compose-tasklist` is authored inline inside the player card.

### Narrative beats (section comments)

| Section | Beat |
|---------|------|
| `connector-morph` | + button → tool menu → connectors → HyperFrames ON → prompt box |
| `chat-response` | Type → send → composer drops to thin bar → thinking |
| `response-scroll` | Response scrolls up; thinking dissolves into answer at seam |
| `followup-type` | Cursor returns, clicks composer, types HyperFrames request |
| `thinking-big` | Inverse zoom-through into giant centered Claude thinking |
| `compose-ui` | Inverse zoom-through into HyperFrames compose tool (Initializing → steps) |
| `sure-response` | Leftward cut-the-curve into giant reply: "Sure." |
| `thinking-big-2` | Inverse zoom-through into "Making your video…" |
| `compose-tasklist` | Leftward cut back to task list midway; last three todos cross off → player → TSLA explainer → download click |
| `outro` | Leftward cut → "HyperFrames MCP" → zoom-through → "Now natively supported on" → Claude logo |

## Z-index stacking

Later sections sit above earlier ones so opacity crossfades and zoom-through seams resolve predictably.

```text
z-index 10  sec-outro
z-index  9  sec-tasklist      ← will-change: transform, filter, opacity
z-index  8  sec-thinking2     ← will-change: transform, filter, opacity
z-index  7  sec-sure          ← will-change: transform, filter, opacity
z-index  6  sec-compose       ← will-change: transform, filter, opacity
z-index  5  sec-thinking      ← will-change: transform, filter, opacity
z-index  4  sec-followup     ← will-change: transform, filter, opacity
z-index  3  sec-response
z-index  2  sec-chat
z-index  1  sec-connector
```

Sections 4–10 carry `will-change: transform, filter, opacity` because the root timeline animates scale, blur, `xPercent`, and opacity at seams.

```mermaid
flowchart TB
  subgraph root ["index.html — claude-paper"]
    HF["HyperFrames runtime\n(data-start / data-duration visibility)"]
    RT["rootTimeline\nwindow.__timelines['claude-paper']"]
  end

  subgraph stack ["Absolute section shells — z-index 1 → 10"]
    S1["sec-connector → connector-morph.html"]
    S2["sec-chat → chat-response.html"]
    S3["sec-response → response-scroll.html"]
    S4["sec-followup → followup-type.html"]
    S5["sec-thinking → thinking-big.html"]
    S6["sec-compose → compose-ui.html"]
    S7["sec-sure → sure-response.html"]
    S8["sec-thinking2 → thinking-big-2.html"]
    S9["sec-tasklist → compose-tasklist.html"]
    S10["sec-outro → outro.html"]
  end

  HF -->|"loads via data-composition-src"| stack
  RT -->|"opacity / scale / blur / xPercent at seams"| stack
```

## Track-index assignments

`data-track-index` orders layers in the HyperFrames mixer. Visual sections use indices **1–7** and **9–11**. Index **8** is reserved for the Scotsman voiceover so it sits between `sure-response` (7) and `thinking-big-2` (9) in the audio stack.

### Visual tracks

| `data-track-index` | Element | Composition |
|--------------------|---------|-------------|
| 1 | `sec-connector` | `connector-morph` |
| 2 | `sec-chat` | `chat-response` |
| 3 | `sec-response` | `response-scroll` |
| 4 | `sec-followup` | `followup-type` |
| 5 | `sec-thinking` | `thinking-big` |
| 6 | `sec-compose` | `compose-ui` |
| 7 | `sec-sure` | `sure-response` |
| 9 | `sec-thinking2` | `thinking-big-2` |
| 10 | `sec-tasklist` | `compose-tasklist` |
| 11 | `sec-outro` | `outro` |

### Audio tracks (root `index.html`)

| `data-track-index` | Element | Source | `data-start` | `data-duration` | `data-volume` |
|--------------------|---------|--------|--------------|-----------------|---------------|
| 8 | `#vo` | `voiceover.mp3` | 29.6 | 2.17 | 1 |
| 184 | `#vo-explainer` | `voiceover_explainer.mp3` | 42.6 | 6.41 | 1 |
| 100–108 | `#sfx-click-0` … `#sfx-click-8` | `click.mp3` | various | 0.07 | 0.85 |
| 102 | `#sfx-toggle` | `toggle.mp3` | 4.30 | 2.67 | 0.85 |
| 109–182 | `#sfx-type-0` … `#sfx-type-73` | `typenew.mp3` | various | 0.57 | 0.2 |
| 183 | `#sfx-click-9` | `click.mp3` | 38.42 | 0.07 | 0.85 |
| 185 | `#sfx-click-10` | `click.mp3` | 49.30 | 0.07 | 0.85 |

<Info>
Click SFX align to UI interactions (connector taps, send, download). Type SFX clusters at 7.8–9.5s (`chat-response`), 20.8–23.7s (`followup-type`), and 33.6–37.3s (`compose-ui` prompt entry).
</Info>

## Seam cut constants

The root GSAP timeline defines eight inter-section seams. Constants `CUT` through `CUT6` are absolute times on the master clock.

| Seam | Transition | Cut time | Outgoing | Incoming | Root behavior |
|------|------------|----------|----------|----------|---------------|
| 1 | Hard cut | 6.7s | `sec-connector` | `sec-chat` | No blend; end-frame composer matches start-frame |
| 2 | Opacity crossfade | 13.0s (0.6s) | `sec-chat` | `sec-response` | `#sec-response` starts at `opacity: 0` |
| 3 | Inverse zoom-through | `CUT` = 25.2s | `sec-followup` | `sec-thinking` | Scale down + blur out → scale up from 1.25 |
| 4 | Inverse zoom-through | `CUT2` = 26.0s | `sec-thinking` | `sec-compose` | Same pattern as seam 3 |
| 5 | Leftward cut-the-curve | `CUT3` = 38.8s | `sec-compose` | `sec-sure` | `xPercent: -13`, opacity 1→0.55, hard cut |
| 6 | Inverse zoom-through | `CUT4` = 39.2s | `sec-sure` | `sec-thinking2` | Same pattern as seam 3 |
| 7 | Leftward cut-the-curve | `CUT5` = 40.3s | `sec-thinking2` | `sec-tasklist` | Hard cut; task list enters sliding left |
| 8 | Leftward cut-the-curve | `CUT6` = 49.9s | `sec-tasklist` | `sec-outro` | Hard cut after download-button click |

Inverse zoom-through pattern (seams 3, 4, 6): outgoing scales to 0.8, `blur(20px)`, opacity 0.15; hard cut at peak blur; incoming starts at scale 1.25, same blur, opacity 0.15; settles to scale 1 over 0.5s with `expo.out`.

Leftward cut-the-curve pattern (seams 5, 7, 8): outgoing `xPercent: -13` over 0.26s with `power2.in`, opacity fades to 0.55; hard cut while still moving; incoming appears at full opacity with matching leftward entry motion in the scene timeline.

## Root GSAP timeline

```javascript
window.__timelines = window.__timelines || {};
const rootTimeline = gsap.timeline({ paused: true });
// … seam tweens …
window.__timelines["claude-paper"] = rootTimeline;
```

<ParamField body="paused" type="boolean" default="true">
Root and scene timelines are paused; HyperFrames scrubs them against the master clock.
</ParamField>

Responsibility split:

- **HyperFrames** — loads each `data-composition-src`, runs the scene's own `window.__timelines[id]`, and shows/hides sections by `data-start` / `data-duration`.
- **Root timeline** — cross-section blending only; no padding or intra-scene animation.

Initial opacity sets at time `0`:

- `#sec-response`, `#sec-thinking`, `#sec-compose`, `#sec-sure`, `#sec-thinking2`, `#sec-tasklist`, `#sec-outro` → `opacity: 0` until their seam reveals them.

## Scene plate contract

Each `compositions/*.html` file wraps content in a `<template>` and declares matching metadata on the inner root:

```html
<div data-composition-id="connector-morph"
     data-width="1920" data-height="1080" data-duration="6.7">
```

Scene durations in plate files match the `data-duration` on the corresponding section shell in `index.html`. Each plate registers its own paused timeline, for example `window.__timelines["connector-morph"]`.

## Verification signals

| Check | Expected |
|-------|----------|
| Master duration | Last section ends at 49.9 + 3.4 = **53.3s** |
| Frame size | Viewport and `#claude-paper` both **1920×1080** |
| Timeline registry | `window.__timelines["claude-paper"]` exists after `index.html` parses |
| Seam 1 | No opacity tween at 6.7s; hard cut from connector to chat |
| Seam 2 | `#sec-response` visible by 13.6s; `#sec-chat` faded out |
| Track 8 gap | No visual section uses `data-track-index="8"`; `#vo` occupies it |
| Final frame | `sec-outro` holds through 53.3s at z-index 10 |

<Warning>
Changing `data-start` or `data-duration` on a section without updating the matching `CUT` constant and scene `data-duration` causes seam misalignment. Edit root and scene timelines together.
</Warning>

## Related pages

<CardGroup>
  <Card title="Edit the master timeline" href="/edit-master-timeline">
    Adjust section schedules, z-index, and CUT constants in index.html.
  </Card>
  <Card title="Scene catalog" href="/scene-catalog">
    Per-scene ids, durations, narrative roles, and handoff constraints.
  </Card>
  <Card title="Transition grammar" href="/transition-grammar">
    Hard cuts, opacity crossfades, inverse zoom-through, and leftward cut-the-curve patterns.
  </Card>
  <Card title="Audio track reference" href="/audio-track-reference">
    Voiceover timing, SFX inventory, and transcript.json word-level sync.
  </Card>
  <Card title="HyperFrames composition model" href="/composition-model">
    How root and scene compositions register on window.__timelines.
  </Card>
</CardGroup>

---

## 13. Scene catalog

> All scene compositions with ids, durations, narrative roles, and handoff constraints—from connector-morph through outro, plus the standalone tesla-rap explainer plate.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/13-scene-catalog.md
- Generated: 2026-06-10T06:34:45.548Z

### Source Files

- `compositions/connector-morph.html`
- `compositions/chat-response.html`
- `compositions/response-scroll.html`
- `compositions/followup-type.html`
- `compositions/thinking-big.html`
- `compositions/compose-ui.html`
- `compositions/sure-response.html`
- `compositions/compose-tasklist.html`

---
title: "Scene catalog"
description: "All scene compositions with ids, durations, narrative roles, and handoff constraints—from connector-morph through outro, plus the standalone tesla-rap explainer plate."
---

The `compositions/` folder holds eleven HyperFrames scene plates—ten stacked in the root `claude-paper` master cut (`index.html`, 53.3 s) and one standalone explainer (`tesla-rap`). Each plate is a `<template>` wrapping a `data-composition-id` root at 1920×1080, a paused GSAP timeline registered on `window.__timelines`, and local `@font-face` blocks. Master-cut scenes are loaded via `data-composition-src` on section divs; seam blending is owned by the root timeline (`window.__timelines["claude-paper"]`).

## Master-cut inventory

| Order | Composition ID | File | Plate duration | Master `data-start` | Master window end | `data-track-index` | z-index |
|------:|----------------|------|---------------:|--------------------:|------------------:|-------------------:|--------:|
| 1 | `connector-morph` | `compositions/connector-morph.html` | 6.7 s | 0.0 s | 6.7 s | 1 | 1 |
| 2 | `chat-response` | `compositions/chat-response.html` | 6.9 s | 6.7 s | 13.6 s | 2 | 2 |
| 3 | `response-scroll` | `compositions/response-scroll.html` | 6.7 s | 13.0 s | 19.7 s | 3 | 3 |
| 4 | `followup-type` | `compositions/followup-type.html` | 6.0 s | 19.4 s | 25.4 s | 4 | 4 |
| 5 | `thinking-big` | `compositions/thinking-big.html` | 1.3 s | 25.0 s | 26.3 s | 5 | 5 |
| 6 | `compose-ui` | `compositions/compose-ui.html` | 13.3 s | 25.8 s | 39.1 s | 6 | 6 |
| 7 | `sure-response` | `compositions/sure-response.html` | 0.4 s | 38.8 s | 39.2 s | 7 | 7 |
| 8 | `thinking-big-2` | `compositions/thinking-big-2.html` | 1.3 s | 39.0 s | 40.3 s | 9 | 8 |
| 9 | `compose-tasklist` | `compositions/compose-tasklist.html` | 9.8 s | 40.3 s | 50.1 s | 10 | 9 |
| 10 | `outro` | `compositions/outro.html` | 3.4 s | 49.9 s | 53.3 s | 11 | 10 |

<Note>
Section windows overlap by design (for example `response-scroll` starts at 13.0 s while `chat-response` still runs until 13.6 s). HyperFrames owns per-section visibility; the root timeline only animates cross-section seams.
</Note>

## Narrative arc and seam map

```text
connector-morph ──HARD CUT──► chat-response ──crossfade 0.6s──► response-scroll
      │                              │                              │
      │  +→menu→connectors→HF ON     │  type TSLA prompt→send       │  scroll TSLA answer
      │  →prompt box                 │  →thinking shimmer           │  (linger at bottom)
      │                              │                              │
      └─ cursor velocity handoff ────┘                              │
                                                                    HARD CUT (scroll lock)
                                                                    ▼
followup-type ──inverse zoom CUT@25.2s──► thinking-big ──inverse zoom CUT2@26.0s──► compose-ui
      │  re-type HyperFrames ask              "Getting started…"              Initializing→7 tasks
      │  →send                                1.3 s burst plate               →Scotsman VO in player
      │                                                                       →pause→re-prompt→send
      │                                                                             │
      │◄── leftward cut-the-curve CUT3@38.8s ──────────────────────────────────────┘
      ▼
sure-response (0.4s "Sure.") ──inverse zoom CUT4@39.2s──► thinking-big-2 ("Making your video")
      │                                                          │
      │◄── leftward cut-the-curve CUT5@40.3s ────────────────────┘
      ▼
compose-tasklist ──leftward cut-the-curve CUT6@49.9s──► outro
  mid-checklist→explainer in player→download click         HyperFrames MCP → logo
```

| Seam | Boundary | Type | Root cut constant | Outbound constraint | Inbound constraint |
|------|----------|------|-------------------|---------------------|-------------------|
| 1 | `connector-morph` → `chat-response` | Hard cut @ 6.7 s | — | End composer matches `chat-response` pixel-for-pixel; cursor exits on 1:2 velocity split (`power2.in` → `power2.out`) | Picks up cursor at matched position/velocity |
| 2 | `chat-response` → `response-scroll` | Opacity crossfade @ 13.0 s, 0.6 s | — | Message + thin composer held steady through fade | Starts hidden (`opacity: 0`); fades in while chat fades out |
| 3 | `response-scroll` → `followup-type` | Hard cut (framework) | — | Holds 0.7 s at scrolled bottom so 3→4 has no 1-frame gap | Scroll born at `response-scroll` end position; cached `maxFrozen` prevents top-flash |
| 4 | `followup-type` → `thinking-big` | Inverse zoom-through | `CUT` = 25.2 s | Outbound scales to 0.8, blurs, dims; hard cut at peak blur | Inbound enters at scale 1.25, blurs in, settles to 1 (`expo.out`, 0.5 s) |
| 5 | `thinking-big` → `compose-ui` | Inverse zoom-through | `CUT2` = 26.0 s | Same as seam 4 | Compose window enters scaled up, settles to 75% card size |
| 6 | `compose-ui` → `sure-response` | Leftward cut-the-curve | `CUT3` = 38.8 s | Whole scene throws `xPercent: -13`, fades 1→0.55 over 0.26 s (`power2.in`) | `"Sure."` slides left from `x:210`, opacity 0.55→1 |
| 7 | `sure-response` → `thinking-big-2` | Inverse zoom-through | `CUT4` = 39.2 s | Same pattern as seam 4 | `"Making your video"` burst plate |
| 8 | `thinking-big-2` → `compose-tasklist` | Leftward cut-the-curve | `CUT5` = 40.3 s | Throws left + fades 1→0.55 | Window enters `x:210→0`, opacity 0.55→1; arrives with 4/7 tasks already done |
| 9 | `compose-tasklist` → `outro` | Leftward cut-the-curve | `CUT6` = 49.9 s | Card throws left after download tap @ ~49.3 s | `"HyperFrames MCP"` title already sliding left from the right |

<Info>
Leftward cut-the-curve seams expose only the paper background (`#F0EEE6`) behind outgoing scenes, so partial off-frame motion stays seamless. Inverse zoom-through seams use symmetric scale/blur/opacity at the hard cut so velocity appears matched in the shrinking direction.
</Info>

## Scene reference

### `connector-morph` (6.7 s)

Opens on a bare `+` glyph that morphs through the tool menu, Connectors panel, Hyperframes toggle ON, and a full prompt box with rolling-bounce placeholder **"How can I help you today?"** End state mirrors `chat-response`'s `.composer` (layout, shadow, weight) for seam 1.

<ParamField body="outbound handoff" type="constraint">
Cursor begins a 0.3 s move toward the chat click point in the last 0.3 s of the plate (`left: 40.7%`, `top: 63.7%`, `power2.in`). `chat-response` continues the path at matched velocity.
</ParamField>

### `chat-response` (6.9 s)

Continues from the matched composer. Types **"Can you give your projections for TSLA in 2026?"**, cursor-taps send, morphs composer to a thin bar (`top: 87%`), flies the user bubble up, and cycles thinking words **Thinking → Researching → Analyzing** with a Lottie burst.

<ParamField body="seam 2 exit" type="constraint">
Holds the last thinking word through plate end so no black tail appears before the 0.6 s crossfade into `response-scroll`.
</ParamField>

### `response-scroll` (6.7 s)

Crossfades in over the identical message/composer layout. Scrolls the TSLA markdown answer upward over 5.2 s (`SCROLL_START` = 0.5 s) with custom scroll easing, then holds at the bottom.

<ParamField body="seam 3 exit" type="constraint">
0.7 s hold after scroll completes so the conversation remains visible behind `followup-type` until the hard cut—prevents a 1-frame gap at 19.4 s.
</ParamField>

### `followup-type` (6.0 s)

Cursor returns from below, clicks the thin composer, types a two-line follow-up (**"Ummm... thank you! Would you mind making this"** / **"into a video with HyperFrames?"**), grows the box upward on wrap, and sends. Scroll position is frozen to `response-scroll`'s end via cached `maxFrozen` and timeline-level `onUpdate`.

<ParamField body="seam 4 exit" type="constraint">
Holds sent state; root inverse zoom-through at `CUT` = 25.2 s recedes this scene while `thinking-big` enters.
</ParamField>

### `thinking-big` (1.3 s)

Giant centered thinking burst with shimmer on **"Getting started…"** (distinct from scene-2 thinking words). Lottie frame driven by GSAP `onUpdate`.

<ParamField body="seam 5 exit" type="constraint">
~1 s on screen; root `CUT2` = 26.0 s inverse zoom-through hands off to `compose-ui`.
</ParamField>

### `compose-ui` (13.3 s)

HyperFrames compose tool window: **Initializing** shimmer → seven-task checklist (0.25 s cadence) → in-card video player with Scotsman VO (`voiceover.mp3` @ master 29.6 s, 2.17 s). Cursor pauses the video mid-"numpties", lifts the card, types a style correction, and sends—triggering the leftward sweep into `sure-response`.

| Task index | Pipeline step |
|-----------:|---------------|
| 1 | Generate narrator scripts via `narrative_planner` |
| 2 | Synthesize audio and generate ASR metadata via `audio_synth` |
| 3 | Create visual section plan via `visual_planner` |
| 4 | Build worker group specification via `build_group_spec` |
| 5 | Execute scene compositions via `scene_executor` workers |
| 6 | Merge scenes into final `index.html` via `inline_index_html` |
| 7 | Finalize execution and deliver video |

<ParamField body="seam 6 exit" type="constraint">
After send tap, cursor sweeps left off-frame (`power2.in`). Root hard-cuts at `CUT3` = 38.8 s while scene is still mostly on-frame, velocity carrying into `sure-response`.
</ParamField>

### `sure-response` (0.4 s)

Oversized serif **"Sure."** on paper grain. Enters from the right (`x: 210`, opacity 0.55) in 0.18 s to carry the leftward cut-the-curve motion.

<ParamField body="seam 7 exit" type="constraint">
Brief hold; root inverse zoom at `CUT4` = 39.2 s (~0.2 s into plate) recedes into `thinking-big-2`.
</ParamField>

### `thinking-big-2` (1.3 s)

Same burst template as `thinking-big` but displays **"Making your video"** (video-making beat).

<ParamField body="seam 8 exit" type="constraint">
Root leftward throw at `CUT5` = 40.3 s; inbound `compose-tasklist` window already sliding left.
</ParamField>

### `compose-tasklist` (9.8 s)

Runs the full output beat: arrives mid-checklist (`DONE` = 4, first four tasks pre-complete), crosses off the last three, transitions `viewList` → `viewPlayer`, plays a 6 s TSLA explainer inside `.vid` (frame.md **default** editorial style—not the rap plate), syncs explainer VO (`voiceover_explainer.mp3` @ master 42.6 s, 6.41 s), then cursor-taps the download pill @ ~9.0 s local / 49.3 s master.

<ParamField body="seam 9 exit" type="constraint">
Holds 0.48 s on the download press; root `CUT6` = 49.9 s leftward throw into `outro`.
</ParamField>

### `outro` (3.4 s)

Three beats on paper: **"HyperFrames MCP"** (slides in from right, 0.7 s) → inverse zoom → **"Now natively supported on"** (0.7 s) → inverse zoom → Claude logo Lottie (frame-driven, held to 3.4 s).

## Standalone plate: `tesla-rap`

| Field | Value |
|-------|-------|
| Composition ID | `tesla-rap` |
| File | `compositions/tesla-rap.html` |
| Plate duration | 5.0 s |
| Master registration | **Not** referenced in `index.html` |
| `window.__timelines` key | `"tesla-rap"` |

Kinetic rap-style TSLA explainer: aerial gigafactory Ken Burns with **"YO YO YO"** stamps, hard cut to second background with **"WHAT UP" ×3** and **"ALL THE DETAILS ON"**, then freeze (~3.7 s). Designed for VO-synced preview as an independent plate.

<Warning>
`tesla-rap` is not loaded by the master cut. The in-cut TSLA explainer is authored inline inside `compose-tasklist` (and partially previewed in `compose-ui`'s player card) using the editorial **default** frame style. Do not assume `data-composition-src="compositions/tesla-rap.html"` on any master section.
</Warning>

Preview standalone:

```bash
hyperframes preview compositions/tesla-rap.html
```

Append `?t=<seconds>` or `?dev=1` to seek or autoplay locally (same dev helpers as other plates).

## Composition contract (all plates)

Every scene file follows the same registration pattern:

```html
<template id="{id}-template">
  <div data-composition-id="{id}" data-width="1920" data-height="1080" data-duration="{seconds}">
    <!-- styles, markup, paused GSAP timeline -->
    <script>
      window.__timelines = window.__timelines || {};
      const tl = gsap.timeline({ paused: true });
      // …
      window.__timelines["{id}"] = tl;
    </script>
  </div>
</template>
```

<ParamField body="data-composition-id" type="string" required>
Must match the `window.__timelines` registry key and, for master-cut scenes, the section `data-composition-id` in `index.html`.
</ParamField>

<ParamField body="data-duration" type="number" required>
Plate runtime in seconds. Local GSAP timelines should hold through this length so HyperFrames does not clip early or show a black tail.
</ParamField>

<ParamField body="data-composition-src" type="path">
Set only on master section divs in `index.html` (not on standalone plates). Path is relative to the `claude-paper-launch` folder root.
</ParamField>

<ParamField body="data-start / data-duration (master)" type="number">
Master window on the `claude-paper` timeline. Changing these requires reconciling seam constants (`CUT`–`CUT6`) and audio `data-start` values.
</ParamField>

## Editing checklist

When modifying a scene, verify handoff pairs still align:

<Steps>
<Step title="Match plate duration to master window">
If `data-duration` on the root div changes, update the matching section `data-duration` and `data-start` chain in `index.html` so windows still sum to 53.3 s.
</Step>
<Step title="Reconcile seam partners">
Scenes that hard-cut or crossfade must end/start at identical layout anchors (composer geometry, scroll offset, cursor position, opacity). Test seams 1–3 in the pair `connector-morph` / `chat-response` / `response-scroll` / `followup-type` together.
</Step>
<Step title="Update root CUT constants">
Inverse zoom and leftward throws use absolute master times (`CUT` = 25.2 s through `CUT6` = 49.9 s). Shift a section start → shift the corresponding `CUT` in `index.html`.
</Step>
<Step title="Register timeline before preview">
Confirm `window.__timelines["{id}"]` is assigned after `document.fonts.ready` when metrics affect layout (typing reveals, scroll freeze).
</Step>
</Steps>

## Related pages

<CardGroup>
<Card title="Master composition reference" href="/master-composition-reference">
Root `claude-paper` stacking order, track-index assignments, and full 53.3 s section map.
</Card>
<Card title="Transition grammar" href="/transition-grammar">
Hard cuts, opacity crossfades, inverse zoom-through, and leftward cut-the-curve patterns used at seams.
</Card>
<Card title="Author a scene composition" href="/author-scene-composition">
Create or edit a `compositions/*.html` plate: template wrapper, attributes, fonts, and timeline registration.
</Card>
<Card title="Edit the master timeline" href="/edit-master-timeline">
Adjust section windows, z-index, and `CUT`–`CUT6` seam times in `index.html`.
</Card>
<Card title="Sync audio and SFX" href="/sync-audio-and-sfx">
Wire Scotsman VO, explainer VO, and click/type SFX to scene boundaries.
</Card>
</CardGroup>

---

## 14. Design tokens reference

> Canonical color hexes, typography ramps (reading and hero), spacing, rounded radii, motion easings, shadow recipes, and component frontmatter keys from FRAME-claude.md.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/14-design-tokens-reference.md
- Generated: 2026-06-10T06:34:24.948Z

### Source Files

- `FRAME-claude.md`
- `compositions/outro.html`
- `compositions/compose-tasklist.html`
- `compositions/thinking-big.html`
- `compositions/tesla-rap.html`
- `fonts/fonts.css`

---
title: "Design tokens reference"
description: "Canonical color hexes, typography ramps (reading and hero), spacing, rounded radii, motion easings, shadow recipes, and component frontmatter keys from FRAME-claude.md."
---

`FRAME-claude.md` is the normative token source for the Claude Paper launch: YAML frontmatter between the opening and closing `---` fences declares every atom, and scene compositions in `compositions/*.html` resolve those values into CSS custom properties on each root element (`#ou-root`, `#ct-root`, and similar).

## Token file structure

`FRAME-claude.md` splits into two layers:

| Layer | Location | Purpose |
| --- | --- | --- |
| **Frontmatter tokens** | Lines 1–311 (YAML between `---` fences) | Machine-readable atoms: `colors`, `typography`, `rounded`, `spacing`, `motion`, `shadows`, `components` |
| **Authoring prose** | Markdown body after frontmatter | Frame-scale rules: accent rationing, legibility floor, fit-to-measure claims, plate treatments |

Reference syntax uses brace interpolation: `{colors.clay}`, `{typography.claim-l}`, `{components.card-paper}`. Component entries reference other tokens rather than repeating raw values.

```text
FRAME-claude.md (frontmatter)
├── colors          → hex atoms + semantic aliases
├── typography      → fontFamilies + reading ramp + hero ramp
├── rounded         → sm / md / lg / pill
├── spacing         → web clamps + frame-safe-area + gutters
├── motion          → easings + duration tokens
├── shadows         → shadow-soft / shadow-card
└── components      → resolved UI recipes (grounds, buttons, pills, cards, ledger, quote)
         │
         ▼
compositions/*.html  → CSS custom properties (--paper, --ink, …) + cqw sizing
```

<Note>
Generic token consumers can read only the frontmatter block. Motion grammar, frame treatments, aspect-ratio tables, and the pre-render self-audit in the markdown body are video-authoring extensions.
</Note>

## Colors

### Four brand atoms

These four hexes are the brand canon. Pure `#FFFFFF` and `#000000` are banned.

| Token | Hex | Role |
| --- | --- | --- |
| `primary` / `paper` / `canvas` | `#F0EEE6` | Warm cream ground — default full-bleed surface |
| `secondary` / `ink` | `#262624` | Warm charcoal — all load-bearing text on paper |
| `tertiary` / `muted` | `#6F6E66` | Warm grey — hairlines, quiet bands, chrome labels |
| `accent` / `clay` | `#D97757` | Signature accent — **one element per frame** at fill strength |

### Semantic aliases

| Token | Hex | Use |
| --- | --- | --- |
| `surface` | `#FAF9F5` | Lifted card background on cream |
| `surface-2` | `#F4F1E6` | Sunken / tint band (catalog ground, window chrome) |
| `accent-2` | `#CC785C` | Deeper clay — book-cloth tone |
| `clay-text` | `#A8472A` | In-line word emphasis on light grounds (~AA) |
| `hairline` | `#DCD8CC` | Warm hairline borders and ledger rules |
| `hairline-soft` | `#E7E3D6` | Softer card borders (paper-lift recipe) |
| `on-accent` | `#FBF7F0` | Text on clay fills |
| `on-ink` | `#EFEADD` | Warm cream text on ink grounds |

### Decorative palette (catalog plate only)

| Token | Hex |
| --- | --- |
| `kraft` | `#D4A27F` |
| `manila` | `#EBDBBC` |
| `sky` | `#6E94A8` |
| `sage` | `#879A6B` |

Decoratives may appear only in the palette catalog plate and must not compete with clay at fill strength.

### Accent rules

- Clay fires **once per frame** at full strength (caption active pill, CTA, stat underline, quote mark).
- A second clay need demotes one element to `clay-text` (inline color only) or removes it.
- Ink grounds use `on-ink` for text; paper grounds use `ink`.

<Warning>
`compositions/tesla-rap.html` is a deliberate stylistic departure: it uses `--red:#E31937`, dark `#0A0E14` backgrounds, and kinetic white/red type — not the Claude Paper atom set. The embedded explainer inside `compose-tasklist.html` follows frame.md default tokens.
</Warning>

## Typography

### Font families

Declared in `typography.fontFamilies` and mirrored in `fonts/fonts.css`:

| Token | Stack |
| --- | --- |
| `display` | `"Hanken Grotesk", "Inter", system-ui, sans-serif` |
| `body` | `"Hanken Grotesk", "Inter", system-ui, sans-serif` |
| `mono` | `"Spline Sans Mono", "IBM Plex Mono", monospace` |

Compositions also load **Galaxie Copernicus** and **Newsreader** for serif editorial beats (`thinking-big.html`, `response-scroll.html`). Those faces are not in the frontmatter `fontFamilies` block but ship as self-hosted woff2 under `fonts/`.

Weight carries hierarchy — italics are not used. Emphasis is **700/800** weight or `clay-text` color.

### Reading ramp (product/UI scale, px @ 1920)

For UI-scale hierarchy. `body` sits exactly on the **1.4vw legibility floor** (27px = 1.4vw at 1920).

| Token | Size | Weight | Letter-spacing | Line-height | Notes |
| --- | --- | --- | --- | --- | --- |
| `display` | 124px (~6.45vw) | 800 | -0.03em | 0.92 | |
| `h1` | 84px (~4.4vw) | 800 | -0.025em | 0.96 | |
| `h2` | 52px (~2.7vw) | 700 | -0.02em | 1.05 | |
| `lead` | 26px (~1.35vw) | 500 | -0.01em | 1.45 | |
| `body` | 27px (1.4vw) | 400 | -0.01em | 1.65 | Load-bearing floor |
| `label` | 13px | 500 | 0.14em | 1.0 | UPPERCASE chrome only |

### Hero / display ramp (frame-native, vw)

Frame-scale sizes authored in `vw` against the 1920 long edge (`px ÷ 1920 × 100`). In compositions, roots set `container-type: size` and map `vw` → `cqw` 1:1 for reviewable plates.

| Token | Size | Weight | Letter-spacing | Line-height | Typical use |
| --- | --- | --- | --- | --- | --- |
| `wordmark-mega` | 30vw | 800 | -0.04em | 0.84 | Paper Identity cover |
| `display-hero` | 14vw | 800 | -0.035em | 0.88 | |
| `claim-l` | 9vw | 800 | -0.03em | 0.94 | ≤3-word claims |
| `claim-m` | 6.2vw | 700 | -0.025em | 1.02 | 4–6-word claims |
| `section-head` | 4.2vw | 700 | -0.02em | 1.05 | 7+ word claims, card headings |
| `stat-numeral` | 18vw | 800 | -0.04em | 0.84 | Hero numerals |
| `stat-ledger` | 4.8vw | 700 | -0.02em | 1.0 | Ledger column |
| `lead-frame` | 1.9vw (~36px) | 500 | -0.01em | 1.45 | Above floor |
| `body-frame` | 1.5vw (~29px) | 400 | -0.01em | 1.55 | Running copy |
| `eyebrow` | 0.85vw | 500 | 0.18em | 1.0 | UPPERCASE chrome — below floor by design |
| `caption-pill` | 3.6vw | 700 | -0.02em | 1.0 | Karaoke caption words |
| `quote-mark` | 22vw | 800 | -0.04em | 0.7 | Pull-quote closer |

### Fit-to-measure claims

Cap text blocks at **≤ 78vw** wide. Select hero ramp by word count:

| Words | Token | Size |
| --- | --- | --- |
| ≤ 3 | `claim-l` | 9vw |
| 4–6 | `claim-m` | 6.2vw |
| 7+ | `section-head` | 4.2vw |

### Legibility floor

Any line carrying a beat's meaning must be **≥ 1.4vw** (~27px @ 1920). Sizes under the floor (`eyebrow`, `label`) are chrome only — kicker tags, indices, colophon.

## Spacing

| Token | Value | Context |
| --- | --- | --- |
| `pad-x` | `clamp(28px, 5vw, 88px)` | Web context horizontal padding |
| `pad-y` | `clamp(64px, 9vh, 116px)` | Web context vertical padding |
| `content-max` | `1280px` | Max content width |
| `frame-pad` | `5vw` | Safe area on long edge (1920×1080) |
| `frame-pad-y` | `5.5vw` | Safe area on short edge of 16:9 |
| `gutter` | `2vw` | Grid gap (catalog swatches) |
| `gap-tight` | `1.2vw` | Tight vertical rhythm (ledger rows) |
| `gap-loose` | `3.4vw` | Loose section spacing |

Load-bearing content must not cross the safe margin. Full-bleed grounds and edge crops may extend past it. The karaoke caption band reserves the bottom **9–12vw** of the frame.

## Rounded radii

| Token | Value | Use |
| --- | --- | --- |
| `sm` | `8px` | Chips, small elements |
| `md` | `14px` | Buttons, inputs, cards |
| `lg` | `22px` | Large cards, panels |
| `pill` | `9999px` | Pills, rails, tags, karaoke captions |

No square corners on load-bearing chrome. CTAs are always pill or 14px-radius buttons.

## Motion

Global motion tokens — per-element durations live here, not inside plate definitions.

| Token | Value |
| --- | --- |
| `ease-out` | `cubic-bezier(.16, 1, .3, 1)` |
| `ease-in` | `cubic-bezier(.5, 0, .75, 0)` |
| `ease-in-out` | `cubic-bezier(.65, 0, .35, 1)` |
| `dur-slide` | `0.8s` |
| `dur-enter` | `0.5s` |

Entrances settle (fade + 0.4vw rise) with `ease-out`. No overshoot, spring, or kinetic typography. Animatable: caption pill swaps, stat count-ups, optional clay underline. Not animatable: paper ground slides, hairline draws, card flips, clay pulses.

## Shadows

Depth ceiling is **paper lift** — soft, diffuse offsets only. At most one lifted plane per frame.

| Token | Value |
| --- | --- |
| `shadow-soft` | `0 1px 2px rgba(38,38,36,.04), 0 12px 32px -18px rgba(38,38,36,.16)` |
| `shadow-card` | `0 1px 3px rgba(38,38,36,.05), 0 22px 50px -26px rgba(38,38,36,.20)` |

**Paper-lift recipe** (required together on lifted cards): `shadow-card` + `1px solid {colors.hairline-soft}`. Shadow alone is insufficient.

## Component frontmatter keys

The `components:` block defines resolved UI recipes. Each entry lists properties that reference other tokens.

### Grounds

| Key | Background | Text | Padding |
| --- | --- | --- | --- |
| `ground-paper` | `paper` | `ink` | `frame-pad` |
| `ground-ink` | `ink` | `on-ink` | `frame-pad` |
| `ground-surface` | `surface` | `ink` | `frame-pad` |
| `ground-sunken` | `surface-2` | `ink` | `frame-pad` |

### Buttons

| Key | Background | Text | Typography | Rounded | Padding | Border |
| --- | --- | --- | --- | --- | --- | --- |
| `button-primary` | `clay` | `on-accent` | `label` | `md` | `14px 22px` | — |
| `button-primary-giant` | `clay` | `on-accent` | `section-head` | `lg` | `1.6vw 3.2vw` | — |
| `button-secondary` | `paper` | `ink` | `label` | `md` | `14px 22px` | `1px solid hairline` |

### Pills, chips, eyebrows

| Key | Background | Text | Typography | Rounded | Padding | Border | Shadow |
| --- | --- | --- | --- | --- | --- | --- | --- |
| `chip-mono` | `surface` | `muted` | `eyebrow` | `pill` | `0.55vw 1.1vw` | `1px solid hairline-soft` | — |
| `chip-mono-ink` | transparent | `on-ink` | `eyebrow` | `pill` | `0.55vw 1.1vw` | `1px solid rgba(239,234,221,0.32)` | — |
| `eyebrow-rail` | transparent | `muted` | `eyebrow` | — | `0` | — | — |
| `caption-pill` | `surface` | `ink` | `caption-pill` | `pill` | `1.1vw 2.2vw` | — | `shadow-soft` |
| `caption-pill-active` | `clay` | `on-accent` | `caption-pill` | `pill` | `1.1vw 2.2vw` | — | `shadow-soft` |

Karaoke pair: past/upcoming words use `caption-pill` at **0.82 / 0.5 opacity**; only the active word wears `caption-pill-active`.

### Cards and surfaces

| Key | Background | Text | Rounded | Padding | Shadow | Border |
| --- | --- | --- | --- | --- | --- | --- |
| `card-paper` | `surface` | `ink` | `lg` | `2.4vw` | `shadow-card` | `1px solid hairline-soft` |
| `card-sunken` | `surface-2` | `ink` | `lg` | `2.4vw` | — | `1px solid hairline-soft` |

### Ledger and data

| Key | Background | Text | Typography | Padding | Border |
| --- | --- | --- | --- | --- | --- |
| `ledger-row` | transparent | `ink` | `body-frame` | `1.1vw 0` | `border-bottom: hairline` |
| `ledger-numeral` | transparent | `ink` | `stat-ledger` | `0` | — |
| `hairline-rule` | `hairline` | — | — | — | `height: 1px; width: 100%` |

### Editorial and chrome

| Key | Background | Text | Typography | Notes |
| --- | --- | --- | --- | --- |
| `swatch-tile` | `surface` | `muted` | `label` | Palette plate atom; `rounded: md`, `padding: 1.4vw` |
| `quote-mark-clay` | transparent | `clay` | `quote-mark` | Hero-size clay — closer plate only |
| `colophon` | transparent | `muted` | `eyebrow` | Bottom-edge metadata strip |

## Applying tokens in compositions

Scene plates do not import `FRAME-claude.md` at runtime. Authors copy canonical hexes into CSS custom properties on the composition root:

```css
#ou-root {
  --paper: #F0EEE6;
  --ink: #262624;
  --muted: #6F6E66;
  --clay: #D97757;
  --f-body: "Hanken Grotesk", "Inter", system-ui, sans-serif;
  background: var(--paper);
  container-type: size;
}
```

Common patterns across `outro.html`, `compose-tasklist.html`, `thinking-big.html`, and `response-scroll.html`:

- **Frame envelope:** `width: 1920px; height: 1080px; overflow: hidden`
- **Container queries:** `container-type: size` on root; sizes expressed in `cqw` (equivalent to spec `vw`)
- **Paper texture:** radial dot grid at ~50% opacity (`rgba(38,36,30,.025)` on 30–34px spacing)
- **Font loading:** embedded `@font-face` blocks with `font-display: block`; scripts await `document.fonts.ready` before timeline registration

### Composition token mapping examples

| Composition | CSS vars | Typography applied |
| --- | --- | --- |
| `outro.html` | `--paper`, `--ink`, `--muted`, `--clay` | `.mcp` at 9.5cqw / 800 (near `claim-l`); `.supp` at 4.6cqw / 600 |
| `compose-tasklist.html` | full atom set + `--on-accent`, `--surface-2`, `--hairline` | `.x-eyebrow` → mono/eyebrow; `.x-h1` → 7cqw/800; `.x-stat` → 13.5cqw/800 (stat-numeral); `.x-chip` → clay pill |
| `thinking-big.html` | `--paper`, `--ink`, `--muted`, `--clay` | Serif wordmark at 9.5cqw via Galaxie Copernicus (composition-specific) |
| `response-scroll.html` | adds `--clay-text`, `--hairline-soft`, `--on-accent` | Newsreader body; clay send button with `on-accent` stroke |

## Token resolution reference

Use brace syntax when authoring from spec; use CSS custom properties when implementing plates.

<ParamField body="colors.{name}" type="hex string">
Canonical or semantic color. Only declared hexes may appear in frames.
</ParamField>

<ParamField body="typography.{ramp}" type="object">
Resolves to `fontFamily`, `fontSize`, `fontWeight`, `letterSpacing`, `lineHeight`, and optional `textTransform`.
</ParamField>

<ParamField body="rounded.{size}" type="px string">
One of `sm`, `md`, `lg`, `pill`.
</ParamField>

<ParamField body="spacing.{name}" type="vw | clamp | px">
Frame-safe-area uses `frame-pad` / `frame-pad-y`; layout gaps use `gutter`, `gap-tight`, `gap-loose`.
</ParamField>

<ParamField body="motion.{name}" type="cubic-bezier | duration">
Global easings and durations — not per-plate.
</ParamField>

<ParamField body="shadows.{name}" type="box-shadow string">
`shadow-soft` for pills; `shadow-card` for lifted cards (always pair with `hairline-soft` border).
</ParamField>

<ParamField body="components.{name}" type="object">
Resolved component recipe referencing colors, typography, rounded, spacing, shadows, and borders.
</ParamField>

## Pre-render checks (token-level)

Before finalizing any frame, verify token usage against these constraints:

- Clay at full strength appears **once** per frame
- Load-bearing copy ≥ **1.4vw** (~27px @ 1920)
- Lifted cards use the full **paper-lift** recipe
- Only `sm` / `md` / `lg` / `pill` radii on load-bearing chrome
- No `#FFFFFF`, `#000000`, or undeclared hex values
- Decorative colors (`kraft`, `manila`, `sky`, `sage`) stay in the catalog plate only

## Related pages

<CardGroup>
<Card title="Claude Paper design system" href="/claude-paper-design-system">
Brand atoms, typography philosophy, frame-scale authoring rules, and the squint/silence/restraint craft bar.
</Card>
<Card title="Frame treatments" href="/frame-treatments">
Seven normative plates that compose frontmatter components into identity, claim, karaoke, artifact, ledger, catalog, and closer frames.
</Card>
<Card title="Author a scene composition" href="/author-scene-composition">
Embed fonts, set CSS custom properties, and register paused GSAP timelines on `window.__timelines`.
</Card>
<Card title="Fonts and assets" href="/fonts-and-assets">
Self-hosted Hanken Grotesk, Spline Sans Mono, Newsreader, and Galaxie Copernicus woff2 files with `fonts.css` @font-face blocks.
</Card>
</CardGroup>

---

## 15. Audio track reference

> Voiceover tracks (Scotsman VO at 29.6s, explainer VO at 42.6s), generated SFX inventory (click, toggle, typenew), volumes, and word-level transcript.json timing.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/15-audio-track-reference.md
- Generated: 2026-06-10T06:34:57.790Z

### Source Files

- `index.html`
- `voiceover.mp3`
- `voiceover_explainer.mp3`
- `transcript.json`
- `compositions/compose-tasklist.html`
- `compositions/tesla-rap.html`

---
title: "Audio track reference"
description: "Voiceover tracks (Scotsman VO at 29.6s, explainer VO at 42.6s), generated SFX inventory (click, toggle, typenew), volumes, and word-level transcript.json timing."
---

The `claude-paper` master composition in `index.html` declares all audio on `<audio>` elements inside `#claude-paper`. HyperFrames reads `data-start`, `data-duration`, `data-track-index`, and `data-volume` on each element to schedule playback against the 53.3s root timeline. Voiceover and SFX are not embedded in scene GSAP timelines; scene compositions align visually to the same clock via local offsets that sum to these master `data-start` values.

## Audio element contract

Each `<audio>` element in `index.html` uses the same scheduling attributes:

| Attribute | Role |
|-----------|------|
| `src` | Relative path to the MP3 asset at the `claude-paper-launch/` root |
| `data-start` | Master-timeline start time in seconds |
| `data-duration` | Playback window length in seconds |
| `data-track-index` | Mixer lane ID (sections use 1–11; audio uses dedicated high indices) |
| `data-volume` | Linear gain (`1` = full, `0.85` = click/toggle, `0.2` = keystroke) |

<Note>
MP3 binaries are Git LFS objects (`*.mp3` in the repository `.gitattributes`). A shallow checkout may show 131-byte pointer stubs instead of playable audio. Run `git lfs pull` inside the scoped folder before preview or render.
</Note>

## Voiceover tracks

Two voiceover lanes are wired at the master root. Both use `data-volume="1"`.

### Scotsman VO (`#vo`)

| Field | Value |
|-------|-------|
| `src` | `voiceover.mp3` |
| `data-start` | `29.6` |
| `data-duration` | `2.17` |
| `data-track-index` | `8` |
| Narrative role | Angry Scotsman rap plays inside the compose player while the generated `tesla-rap` video runs; cursor pauses playback partway through `"numpties"` |

Master start `29.6` equals `sec-compose` `data-start` (`25.8`) plus the compose-ui local anchor `R = VS + 0.3` where `VS = 3.5`, giving `25.8 + 3.8 = 29.6`. The `2.17`s window ends when the in-player pause fires at local `PEND = R + 2.17`.

```html
<audio
  id="vo"
  src="voiceover.mp3"
  data-start="29.6"
  data-duration="2.17"
  data-track-index="8"
  data-volume="1"
></audio>
```

In `compose-ui.html`, on-screen captions track the same VO clock:

- `"Right."` fades in at local `R + 0.11`
- `"Listen up, you wee numpties."` holds from local `R + 1.03` through the pause at `PEND`

A separate ElevenLabs export (`ElevenLabs_2026-06-05T10_14_44_Scotsman_gen_sp100_s50_sb75_v3 (1).mp3`) sits alongside `voiceover.mp3` as the generation source; the master cut references `voiceover.mp3`.

### Explainer VO (`#vo-explainer`)

| Field | Value |
|-------|-------|
| `src` | `voiceover_explainer.mp3` |
| `data-start` | `42.6` |
| `data-duration` | `6.41` |
| `data-track-index` | `184` |
| Narrative role | Neutral presenter VO over the final TSLA explainer inside `compose-tasklist` |

Master start `42.6` equals `sec-tasklist` `data-start` (`40.3`) plus local `R = VS + 0.3` where `VS = 2.0`, giving `40.3 + 2.3 = 42.6`. The comment in `index.html` identifies this as ElevenLabs output at 6.41s.

```html
<audio
  id="vo-explainer"
  src="voiceover_explainer.mp3"
  data-start="42.6"
  data-duration="6.41"
  data-track-index="184"
  data-volume="1"
></audio>
```

`compose-tasklist.html` drives six seconds of in-player scrubber motion from local `R` and overlays phrase captions synced to ElevenLabs alignment (caption B for `"our base case"` enters at local `R + 3.4`). The standalone `tesla-rap` composition is the earlier Scotsman-style kinetic plate embedded in `compose-ui`; the explainer VO pairs with the editorial TSLA plate in `compose-tasklist`, not `tesla-rap.html`.

## Generated SFX inventory

All UI sound effects are declared in a single generated block in `index.html` (comment: `SFX:generated`). Three source files are reused:

| Asset | Use | `data-volume` | `data-duration` |
|-------|-----|---------------|-----------------|
| `click.mp3` | Cursor taps (buttons, send, download) | `0.85` | `0.07` |
| `toggle.mp3` | HyperFrames toggle flip in `connector-morph` | `0.85` | `2.67` |
| `typenew.mp3` | Per-keystroke typing swell (humanized stagger) | `0.2` | `0.57` |

### Click cues (`click.mp3`)

Ten click instances (`sfx-click-0` … `sfx-click-10`, note the gap at index 2):

| ID | Master `data-start` | Scene context |
|----|---------------------|---------------|
| `sfx-click-0` | `1.60` | `connector-morph` — `+` pill tap |
| `sfx-click-1` | `3.10` | `connector-morph` — menu interaction |
| `sfx-click-3` | `7.48` | `chat-response` — composer focus |
| `sfx-click-4` | `9.93` | `chat-response` — send tap |
| `sfx-click-5` | `20.20` | `followup-type` — composer click |
| `sfx-click-6` | `24.89` | `followup-type` — send tap |
| `sfx-click-7` | `31.77` | `compose-ui` — in-player pause tap (aligned with Scotsman VO end) |
| `sfx-click-8` | `33.20` | `compose-ui` — correction prompt tap |
| `sfx-click-9` | `38.42` | `compose-ui` — send after correction |
| `sfx-click-10` | `49.30` | `compose-tasklist` — download pill tap |

Track indices: `100`–`108`, `183`, `185`.

### Toggle cue (`toggle.mp3`)

| ID | Master `data-start` | `data-duration` | `data-track-index` |
|----|---------------------|-----------------|-------------------|
| `sfx-toggle` | `4.30` | `2.67` | `102` |

Plays over the HyperFrames ON toggle in `connector-morph` (section starts at `0`, local ≈ `4.3`).

### Typing cues (`typenew.mp3`)

Seventy-four keystroke instances (`sfx-type-0` … `sfx-type-73`), track indices `109`–`182`. They cluster in three typing bursts on the master clock:

| Master window | Scene | Keystroke IDs |
|---------------|-------|---------------|
| `7.80` – `9.51` | `chat-response` (starts `6.7`) | `sfx-type-0` – `sfx-type-15` (16 strokes) |
| `20.80` – `23.70` | `followup-type` (starts `19.4`) | `sfx-type-16` – `sfx-type-40` (25 strokes) |
| `33.57` – `37.30` | `compose-ui` correction typing (starts `25.8`) | `sfx-type-41` – `sfx-type-73` (33 strokes) |

Inter-keystroke gaps vary (roughly 0.07–0.16s) to mimic human typing cadence rather than uniform metronome spacing.

## Track index map

```text
Master timeline (#claude-paper, 53.3s)
├── Sections ............... data-track-index 1–11 (visual lanes)
├── Scotsman VO (#vo) ...... track 8
├── SFX clicks ............. tracks 100–108, 183, 185
├── SFX toggle ............. track 102
├── SFX typing ............. tracks 109–182
└── Explainer VO ........... track 184
```

Visual sections and audio lanes share the `data-track-index` namespace but use non-overlapping ranges so the renderer can mix them independently.

## `transcript.json` — word-level Scotsman timing

`transcript.json` at the project root holds ASR word alignment for `voiceover.mp3`. Timestamps are **relative to the VO file origin** (0-based), not the master timeline. To convert a word time to master time during the Scotsman window:

```text
master_time = 29.6 + transcript_word.start   // while VO is active
```

### Schema

Each entry is an object with three fields:

| Field | Type | Meaning |
|-------|------|---------|
| `text` | string | Word or punctuation token |
| `start` | number | Start offset in seconds from VO file start |
| `end` | number | End offset in seconds |

### Full word list (18 tokens)

| `text` | `start` | `end` |
|--------|---------|-------|
| Right! | 0.11 | 1.00 |
| Listen | 1.03 | 1.38 |
| up, | 1.38 | 1.63 |
| you | 1.63 | 1.82 |
| wee | 1.82 | 1.91 |
| numpties. | 2.07 | 2.64 |
| It's | 2.78 | 3.25 |
| Tesla, | 3.31 | 4.29 |
| and | 4.29 | 4.48 |
| I'm | 4.48 | 4.67 |
| about | 4.67 | 4.98 |
| to | 5.09 | 5.12 |
| tell | 5.12 | 5.38 |
| you | 5.38 | 5.54 |
| everything | 5.71 | 6.40 |
| you | 6.40 | 6.64 |
| need | 6.64 | 6.90 |
| to. | 7.07 | 7.28 |

<file-tree>
claude-paper-launch/
├── index.html              # all <audio> scheduling attributes
├── voiceover.mp3           # Scotsman VO (LFS)
├── voiceover_explainer.mp3 # TSLA explainer VO (LFS)
├── transcript.json         # word timings for voiceover.mp3
├── click.mp3               # UI click SFX (LFS, referenced)
├── toggle.mp3              # HF toggle SFX (LFS, referenced)
├── typenew.mp3             # keystroke SFX (LFS, referenced)
└── compositions/
    ├── compose-ui.html     # Scotsman player + caption sync
    └── compose-tasklist.html # explainer player + caption sync
</file-tree>

<Info>
Only the first ~2.17s of the transcript is heard in the shipped cut. Words from `"It's"` onward exist in `transcript.json` for the full generated take but fall after the `data-duration` window and the in-player pause. Caption timing in `compose-ui.html` uses the early phrases (`"Right."`, `"Listen up, you wee numpties."`) that fall inside the active window.
</Info>

### Caption ↔ transcript alignment

| Visual cue (compose-ui local) | Transcript anchor | Master equivalent |
|------------------------------|-------------------|-------------------|
| `R + 0.11` — `"Right."` caption | `"Right!"` at `0.11` | `29.71` |
| `R + 1.03` — `"Listen up…"` caption | `"Listen"` at `1.03` | `30.63` |
| `PEND = R + 2.17` — pause click | cuts into `"numpties."` (`2.07`–`2.64`) | `31.77` (`sfx-click-7`) |

## Master timeline audio map

```text
0s        10s        20s        30s        40s        50s   53.3s
|----------|----------|----------|----------|----------|-----|
 [clicks/toggle/type bursts in sections 1–4]
                              [Scotsman VO 29.6–31.77]
                                    [type burst 33.6–37.3]
                                         [click 38.42]
                                              [explainer VO 42.6–49.01]
                                                         [click 49.30]
```

| Audio event | Start (s) | End (s) |
|-------------|-----------|---------|
| Scotsman VO | 29.6 | 31.77 |
| Explainer VO | 42.6 | 49.01 |
| First click SFX | 1.60 | 1.67 |
| Last click SFX (download) | 49.30 | 49.37 |

## Editing and verification

When shifting VO or SFX:

1. Update `data-start` / `data-duration` on the `<audio>` element in `index.html`.
2. Adjust the matching local GSAP anchor in the scene composition (`R`, `PEND`, `END`, or caption `tl.add` callbacks).
3. For new Scotsman copy, regenerate `voiceover.mp3` and refresh `transcript.json` word timings before retiming captions.
4. Preview with `hyperframes preview` against the `claude-paper-launch` folder and confirm clicks line up with cursor press keyframes.

<Warning>
`compose-ui.html` contains a stale comment referencing master VO at `31.3s`. The authoritative master schedule is `data-start="29.6"` on `#vo` in `index.html`.
</Warning>

<ParamField body="data-start" type="number" required>
Master-timeline seconds when playback begins. Must match the sum of parent section `data-start` plus the scene's local audio anchor.
</ParamField>

<ParamField body="data-duration" type="number" required>
Length of the audible window. For Scotsman VO, this must equal the compose-ui `PEND - R` interval (`2.17`).
</ParamField>

<ParamField body="data-track-index" type="number" required>
Unique mixer lane. Keep SFX in the `100+` range to avoid colliding with section indices `1`–`11`.
</ParamField>

<ParamField body="data-volume" type="number" required>
Linear gain. Use `1` for voiceover, `0.85` for clicks/toggle, `0.2` for typing.
</ParamField>

## Related pages

<CardGroup>
  <Card title="Sync audio and SFX" href="/sync-audio-and-sfx">
    Procedural guide for wiring new voiceover and SFX elements with the same attribute pattern.
  </Card>
  <Card title="Master composition reference" href="/master-composition-reference">
    Full section stack, z-index order, and how audio track indices sit beside visual lanes.
  </Card>
  <Card title="Scene catalog" href="/scene-catalog">
    Scene durations and handoff points that anchor VO and SFX local times.
  </Card>
  <Card title="Fonts and assets" href="/fonts-and-assets">
    Git LFS setup for MP3 binaries including voiceover and SFX files.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Recovery when LFS audio is missing or preview plays silently.
  </Card>
</CardGroup>

---

## 16. Fonts and assets

> Self-hosted Hanken Grotesk, Spline Sans Mono, Newsreader, and Galaxie Copernicus woff2 files, fonts.css @font-face blocks, and Git LFS binary dependencies.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/16-fonts-and-assets.md
- Generated: 2026-06-10T06:35:21.300Z

### Source Files

- `fonts/fonts.css`
- `fonts/HankenGrotesk-normal-400-latin-fe1634.woff2`
- `fonts/SplineSansMono-normal-500-latin-53329b.woff2`
- `fonts/Newsreader-normal-500-latin-f0c28d.woff2`
- `fonts/GalaxieCopernicus-Book.woff2`
- `compositions/connector-morph.html`
- `voiceover.mp3`

---
title: "Fonts and assets"
description: "Self-hosted Hanken Grotesk, Spline Sans Mono, Newsreader, and Galaxie Copernicus woff2 files, fonts.css @font-face blocks, and Git LFS binary dependencies."
---

The `claude-paper-launch/` folder ships all typography as self-hosted `.woff2` binaries under `fonts/`, with `@font-face` rules either centralized in `fonts/fonts.css` or duplicated inline inside each scene composition. Voiceover MP3s and every font file are stored through Git LFS at the repository root; HTML, CSS, and JSON remain plain text.

## Asset layout

```text
claude-paper-launch/
├── fonts/
│   ├── fonts.css                          # canonical @font-face bundle (22 blocks)
│   ├── HankenGrotesk-normal-*-latin*.woff2   # 8 files (400–700 × latin/latin-ext)
│   ├── Newsreader-*-latin*.woff2             # 10 files (normal + italic subsets)
│   ├── SplineSansMono-normal-*-latin*.woff2  # 4 files (400/500 × latin/latin-ext)
│   └── GalaxieCopernicus-Book.woff2          # 1 file (serif display)
├── voiceover.mp3                          # Scotsman VO (LFS)
├── voiceover_explainer.mp3                # explainer VO (LFS)
├── ElevenLabs_…Scotsman….mp3              # ElevenLabs source take (LFS)
├── transcript.json                        # word-level timing (text)
├── index.html                             # master composition; audio refs at project root
└── compositions/*.html                    # per-scene inline @font-face + CSS vars
```

`index.html` does not load `fonts/fonts.css` or declare `@font-face` blocks. Typography resolves inside each loaded scene plate. Audio elements in `index.html` reference `voiceover.mp3`, `voiceover_explainer.mp3`, and generated SFX files (`click.mp3`, `toggle.mp3`, `typenew.mp3`) at the project root.

## Font families and design roles

| Family | CSS `font-family` | Weights in repo | Primary role |
| --- | --- | --- | --- |
| Hanken Grotesk | `'Hanken Grotesk'` | 400, 500, 600, 700 | UI body, headings, hero claims (`--f-body`) |
| Spline Sans Mono | `'Spline Sans Mono'` | 400, 500 | Labels, chips, uppercase chrome (`--f-mono`) |
| Newsreader | `'Newsreader'` | 400, 500, 600 (normal + italic) | Claude response serif (`--f-serif` fallback) |
| Galaxie Copernicus | `'Galaxie Copernicus'` | 400–600 (variable range) | Oversized thinking/claim serif (`--f-serif` primary) |

`FRAME-claude.md` names Hanken Grotesk for display and body ramps and Spline Sans Mono for label/mono chrome. Scene plates map those tokens to CSS custom properties:

| Variable | Typical stack |
| --- | --- |
| `--f-body` | `"Hanken Grotesk","Inter",system-ui,sans-serif` |
| `--f-mono` | `"Spline Sans Mono","IBM Plex Mono",monospace` |
| `--f-serif` | `"Galaxie Copernicus","Newsreader",Georgia,serif` or `"Newsreader",Georgia,serif` |

Galaxie Copernicus appears only in `sure-response`, `thinking-big`, `thinking-big-2`, and `compose-tasklist`. Other serif-heavy scenes (`chat-response`, `response-scroll`, `followup-type`) use Newsreader alone.

## `fonts/fonts.css` canonical bundle

`fonts/fonts.css` contains **22** `@font-face` blocks covering Hanken Grotesk, Newsreader, and Spline Sans Mono. It does **not** include Galaxie Copernicus—that face is declared only in the four compositions that need it.

Every block in the bundle follows the same contract:

- `font-display: block` — text stays invisible until the face loads (no fallback flash during render).
- `format('woff2')` — single compressed binary per subset.
- `unicode-range` — paired **latin** and **latin-ext** slices per weight/style so the browser downloads only the glyph range needed.

Paths are rooted from the project folder: `url(fonts/HankenGrotesk-normal-400-latin-fe1634.woff2)`. If you link `fonts/fonts.css` from `index.html`, place the `<link>` at the project root so relative URLs resolve correctly.

<Note>
No file in the scoped folder currently references `fonts/fonts.css`. The stylesheet is the authoritative copy-paste source when authoring or updating scene-level `@font-face` blocks.
</Note>

### Hanken Grotesk subsets

| Weight | Latin file | Latin-ext file |
| --- | --- | --- |
| 400 | `HankenGrotesk-normal-400-latin-fe1634.woff2` | `HankenGrotesk-normal-400-latin-ext-d9a6a0.woff2` |
| 500 | `HankenGrotesk-normal-500-latin-fe1634.woff2` | `HankenGrotesk-normal-500-latin-ext-d9a6a0.woff2` |
| 600 | `HankenGrotesk-normal-600-latin-fe1634.woff2` | `HankenGrotesk-normal-600-latin-ext-d9a6a0.woff2` |
| 700 | `HankenGrotesk-normal-700-latin-fe1634.woff2` | `HankenGrotesk-normal-700-latin-ext-d9a6a0.woff2` |

### Newsreader subsets

| Style | Weight | Latin | Latin-ext |
| --- | --- | --- | --- |
| normal | 400 | `Newsreader-normal-400-latin-f0c28d.woff2` | `Newsreader-normal-400-latin-ext-7a09be.woff2` |
| normal | 500 | `Newsreader-normal-500-latin-f0c28d.woff2` | `Newsreader-normal-500-latin-ext-7a09be.woff2` |
| normal | 600 | `Newsreader-normal-600-latin-f0c28d.woff2` | `Newsreader-normal-600-latin-ext-7a09be.woff2` |
| italic | 400 | `Newsreader-italic-400-latin-78bd98.woff2` | `Newsreader-italic-400-latin-ext-e36b6b.woff2` |
| italic | 500 | `Newsreader-italic-500-latin-78bd98.woff2` | `Newsreader-italic-500-latin-ext-e36b6b.woff2` |

### Spline Sans Mono subsets

| Weight | Latin | Latin-ext |
| --- | --- | --- |
| 400 | `SplineSansMono-normal-400-latin-53329b.woff2` | `SplineSansMono-normal-400-latin-ext-62a811.woff2` |
| 500 | `SplineSansMono-normal-500-latin-53329b.woff2` | `SplineSansMono-normal-500-latin-ext-62a811.woff2` |

### Galaxie Copernicus

Single file: `fonts/GalaxieCopernicus-Book.woff2`. Scene plates declare one block with a variable weight range:

```css
@font-face {
  font-family: 'Galaxie Copernicus';
  font-style: normal;
  font-weight: 400 600;
  font-display: block;
  src: url(fonts/GalaxieCopernicus-Book.woff2) format('woff2');
}
```

## Scene-level font embedding

Each composition under `compositions/` inlines the `@font-face` blocks its markup needs inside the root `<style>` tag. HyperFrames resolves `url(fonts/…)` relative to the `claude-paper-launch/` project root when the plate loads.

```mermaid
flowchart LR
  subgraph root["claude-paper-launch/"]
    IDX[index.html]
    FONTS["fonts/*.woff2"]
  end
  subgraph scenes["compositions/"]
    CM[connector-morph.html]
    SR[sure-response.html]
    OU[outro.html]
  end
  IDX -->|data-composition-src| CM
  IDX -->|data-composition-src| SR
  IDX -->|data-composition-src| OU
  CM -->|inline @font-face url fonts/…| FONTS
  SR -->|inline @font-face url fonts/…| FONTS
  OU -->|latin-only Hanken subset| FONTS
```

### Embedding tiers

| Tier | Compositions | `@font-face` count | Notes |
| --- | --- | --- | --- |
| Full UI stack | `connector-morph`, `chat-response`, `followup-type`, `response-scroll`, `compose-ui`, `tesla-rap` | 22 | Matches `fonts/fonts.css` |
| Full + Galaxie | `thinking-big`, `thinking-big-2` | 23 | Adds Galaxie Copernicus |
| Tasklist subset | `compose-tasklist` | 10 | Hanken 400/500/700, Spline 500, Newsreader 500, Galaxie |
| Sure-response subset | `sure-response` | 5 | Newsreader 400/500 + Galaxie only |
| Outro minimal | `outro` | 3 | Hanken 400/500/700 latin only |

`connector-morph.html` documents the pattern explicitly with a `/* local fonts (captured woff2, font-display:block) */` comment and the full three-family stack before setting `--f-body` and `--f-mono` on the scene root.

## Font loading lifecycle

All `@font-face` rules use `font-display: block`. Scene scripts gate GSAP timeline construction on font readiness:

```javascript
if (document.fonts && document.fonts.ready) {
  try { await document.fonts.ready; } catch (e) {}
}
```

This pattern appears in `connector-morph`, `chat-response`, `compose-ui`, `compose-tasklist`, `sure-response`, `outro`, and other plates. Combined with `font-display: block`, missing or slow font binaries stall visible text until load completes—or indefinitely if LFS assets were not pulled.

<Warning>
`font-display: block` plus `document.fonts.ready` means a missing `.woff2` pointer file (unpulled LFS) can freeze a scene on blank text. Pull LFS objects before preview or render.
</Warning>

## Git LFS binary dependencies

The repository root `.gitattributes` routes `*.woff2`, `*.woff`, `*.ttf`, `*.otf`, and `*.mp3` through Git LFS. HTML, CSS, JS, JSON, and Markdown stay as normal text.

### LFS-tracked files in `claude-paper-launch/`

| Category | Files | Count |
| --- | --- | --- |
| Fonts | All 23 `fonts/*.woff2` | 23 |
| Voiceover | `voiceover.mp3`, `voiceover_explainer.mp3` | 2 |
| Source audio | `ElevenLabs_2026-06-05T10_14_44_Scotsman_gen_sp100_s50_sb75_v3 (1).mp3` | 1 |

**26** LFS objects are registered under `claude-paper-launch/` in a full clone with LFS smudge enabled.

### Pull workflow

<Steps>
<Step title="Install Git LFS">

```bash
brew install git-lfs   # macOS
git lfs install
```

</Step>
<Step title="Fetch scoped binaries">

From the repository root:

```bash
git lfs pull --include="claude-paper-launch/**"
```

</Step>
<Step title="Verify font binaries">

```bash
file claude-paper-launch/fonts/HankenGrotesk-normal-400-latin-fe1634.woff2
# expect: Web Open Font Format (Version 2), not "ASCII text"
```

A 130-byte `ASCII text` file is an LFS pointer, not the font.

</Step>
</Steps>

If you cloned with `GIT_LFS_SKIP_SMUDGE=1`, run `git lfs pull` before `hyperframes preview` or `hyperframes render`.

### Referenced but untracked SFX

`index.html` references `click.mp3`, `toggle.mp3`, and `typenew.mp3` at the project root (comment: `SFX:generated`). These files are **not** in the current git index for `claude-paper-launch/`. They would match the `*.mp3` LFS rule if added. Until they exist locally, click and keystroke SFX cues in the master timeline will not play.

## Audio assets at project root

| File | LFS | Used by | Role |
| --- | --- | --- | --- |
| `voiceover.mp3` | yes | `index.html` `#vo` | Scotsman VO @ 29.6s |
| `voiceover_explainer.mp3` | yes | `index.html` `#vo-explainer` | Neutral explainer VO @ 42.6s |
| `ElevenLabs_…Scotsman….mp3` | yes | — | ElevenLabs source take (not wired in `index.html`) |
| `transcript.json` | no | timing reference | Word-level transcript |
| `click.mp3`, `toggle.mp3`, `typenew.mp3` | would be LFS | `index.html` SFX elements | Generated SFX inventory (not committed) |

## Authoring a new scene plate

When adding or editing a composition:

1. Copy the `@font-face` blocks your plate needs from `fonts/fonts.css` (plus Galaxie if using `--f-serif` with Copernicus).
2. Trim unused weights to keep the plate lean—follow `outro.html` (latin-only Hanken) or `compose-tasklist.html` (partial stack) as precedents.
3. Set `--f-body`, `--f-mono`, and `--f-serif` on the scene root to match `FRAME-claude.md` stacks.
4. Keep `url(fonts/…)` paths unchanged; do not prefix with `../`.
5. Await `document.fonts.ready` before building the paused GSAP timeline.
6. Commit any new `.woff2` files—LFS picks them up automatically via root `.gitattributes`.

## Verification checklist

| Check | Pass signal |
| --- | --- |
| LFS smudge | `file fonts/*.woff2` reports Web Open Font Format |
| Scene load | Preview shows correct Hanken/Newsreader/Spline/Galaxie shapes per plate |
| Serif handoff | `sure-response` renders Galaxie-weighted “Sure.” at 38.8s |
| Font gate | No flash of system-ui fallback before scene animation starts |
| VO playback | `voiceover.mp3` and `voiceover_explainer.mp3` play at 29.6s and 42.6s |

## Related pages

<CardGroup>
<Card title="Installation" href="/installation">
Git LFS setup, HyperFrames CLI prerequisites, and scoped folder layout.
</Card>
<Card title="Claude Paper design system" href="/claude-paper-design-system">
Typography ramps and font-family tokens from FRAME-claude.md.
</Card>
<Card title="Author a scene composition" href="/author-scene-composition">
Embed local fonts, set CSS variables, and register paused GSAP timelines.
</Card>
<Card title="Audio track reference" href="/audio-track-reference">
Voiceover timing, SFX inventory, and transcript.json word marks.
</Card>
<Card title="Troubleshooting" href="/troubleshooting">
Recovery for missing LFS assets and font-display:block loading stalls.
</Card>
</CardGroup>

---

## 17. Troubleshooting

> Recovery for missing LFS audio/SFX, font-display:block loading stalls, seam misalignment between consecutive scenes, and timeline registration failures.

- Page Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/pages/17-troubleshooting.md
- Generated: 2026-06-10T06:35:42.848Z

### Source Files

- `index.html`
- `compositions/chat-response.html`
- `compositions/response-scroll.html`
- `compositions/compose-ui.html`
- `fonts/fonts.css`
- `voiceover.mp3`

---
title: "Troubleshooting"
description: "Recovery for missing LFS audio/SFX, font-display:block loading stalls, seam misalignment between consecutive scenes, and timeline registration failures."
---

The `claude-paper-launch` master cut depends on Git LFS binaries, eleven scene timelines registered on `window.__timelines`, and seam choreography in `index.html` that must stay locked to each section's `data-start` / `data-duration`. Failures in this folder usually surface as silent preview, invisible text, pops at section boundaries, or frozen scenes — each maps to a specific recovery path below.

## Symptom map

```text
Preview/render symptom          Likely layer              First check
─────────────────────────────────────────────────────────────────────────
No VO / no clicks / no typing   LFS audio + SFX files     file size + Network 404
Invisible or late text          font-display:block + LFS  woff2 bytes + fonts.ready
Jump/pop at 6.7s / 13.0s / …    seam timing + layout      CUT constants vs data-start
Scene frozen / black frame      timeline registration     __timelines[id] + paused tl
```

<Warning>
Binary assets in this folder are Git LFS objects. A 131-byte file whose first line is `version https://git-lfs.github.com/spec/v1` is a pointer, not playable audio or a loadable font.
</Warning>

## Missing LFS audio and SFX

### LFS-tracked files in scope

Repository `.gitattributes` routes `*.mp3` and `*.woff2` through Git LFS. In `claude-paper-launch`, tracked audio includes:

| File | Role | Expected LFS size (from pointer) |
|------|------|----------------------------------|
| `voiceover.mp3` | Scotsman VO at `data-start="29.6"` | 153,744 bytes |
| `voiceover_explainer.mp3` | Presenter VO at `data-start="42.6"` | (pointer in repo) |
| `ElevenLabs_2026-06-05T10_14_44_Scotsman_gen_sp100_s50_sb75_v3 (1).mp3` | Source Scotsman take | LFS |

### SFX files referenced but absent

`index.html` wires 11 click tracks, 1 toggle, and 74 `typenew` keystroke tracks to root-relative paths:

- `click.mp3` — `data-volume="0.85"`, `data-duration="0.07"`
- `toggle.mp3` — HyperFrames toggle at 4.30s
- `typenew.mp3` — typing swell at `data-volume="0.2"`, `data-duration="0.57"`

These three files are **not present** in `claude-paper-launch/` and are **not tracked** in git. Preview and render will load the `<audio>` elements but produce no sound (Network 404).

<Steps>
<Step title="Confirm pointer vs real binary">

```bash
cd claude-paper-launch
head -1 voiceover.mp3                    # LFS pointer if it prints "version https://git-lfs..."
wc -c voiceover.mp3 click.mp3 2>/dev/null
file voiceover.mp3                       # should report "Audio file" after pull
```

</Step>
<Step title="Pull LFS objects">

```bash
git lfs install
git lfs pull
```

Re-run `wc -c voiceover.mp3`. A successful pull shows ~150 KB, not 131 bytes.

</Step>
<Step title="Restore missing SFX">

Add `click.mp3`, `toggle.mp3`, and `typenew.mp3` to the `claude-paper-launch/` root (same directory as `index.html`). Match durations wired in `index.html`: clicks 0.07s, toggle 2.67s, typenew 0.57s. If you regenerate SFX, keep `data-start` timestamps unchanged or re-sync against scene cursor/typing events.

</Step>
<Step title="Verify in preview">

Scrub to known SFX anchors: click at 1.60s (connector), toggle at 4.30s, first typenew at 7.80s, Scotsman VO at 29.6s, explainer VO at 42.6s, download click at 49.30s. All should fire without console 404s.

</Step>
</Steps>

<Note>
`transcript.json` holds word-level timing for the Scotsman VO. If you replace `voiceover.mp3`, re-validate `data-start` / `data-duration` on `#vo` against the new file length.
</Note>

## `font-display: block` loading stalls

Every `@font-face` in `fonts/fonts.css` and in scene plates (for example `compositions/chat-response.html`, `compositions/response-scroll.html`, `compositions/compose-ui.html`) sets `font-display: block`. Until the matching `woff2` finishes loading, the browser renders **no fallback text** for that family — layout can look empty or frozen, especially on first preview after clone.

### Font files affected

All self-hosted families are LFS-backed:

- Hanken Grotesk (400–700, latin + latin-ext)
- Newsreader (400–600, normal + italic)
- Spline Sans Mono (400, 500)
- Galaxie Copernicus Book (used in select plates)

Unresolved LFS pointers produce the same invisible-text stall as a network failure.

### `document.fonts.ready` gate

Most scene scripts **await** font load before measuring text or building GSAP timelines:

```javascript
if (document.fonts && document.fonts.ready) {
  try { await document.fonts.ready; } catch(e) {}
}
```

Plates that follow this pattern include `chat-response`, `response-scroll`, `compose-ui`, `followup-type`, `compose-tasklist`, `sure-response`, and `outro`.

<Warning>
`connector-morph` and `thinking-big` build timelines **without** awaiting `document.fonts.ready`. On cold load with unresolved fonts, placeholder width measurements and cursor handoff positions can be wrong at the seam-1 hard cut (6.7s).
</Warning>

<Steps>
<Step title="Pull font binaries">

```bash
git lfs pull
ls -la fonts/*.woff2 | head
```

Each `woff2` should be tens of kilobytes, not 131 bytes.

</Step>
<Step title="Confirm font URLs resolve">

Scene plates reference `url(fonts/HankenGrotesk-…woff2)` relative to the `claude-paper-launch` root. In browser devtools Network, filter `woff2` — expect HTTP 200 for every subset your plate uses.

</Step>
<Step title="Isolate a single plate">

Open a composition directly with dev helpers:

```
compositions/chat-response.html?dev=1
compositions/chat-response.html?t=6.5
```

If text appears after a delay then snaps layout, fonts loaded late. Fix LFS first; only then consider adding `document.fonts.ready` to plates that lack it.

</Step>
<Step title="Re-measure after fonts settle">

`chat-response` and `followup-type` bake `offsetWidth` into typing clips **after** `fonts.ready`. If you edit copy or weights, reload with cache disabled so measurements rerun on final metrics.

</Step>
</Steps>

## Seam misalignment between consecutive scenes

The root GSAP timeline in `index.html` drives **only** cross-section opacity, scale, blur, and `xPercent` throws. Section visibility windows come from each `#sec-*` div's `data-start` / `data-duration`. Seam pops happen when those two layers drift apart or when consecutive plates disagree on shared anchors (composer, cursor, paper).

### Section schedule (master)

| Section | `data-composition-id` | `data-start` | `data-duration` | End (start+dur) |
|---------|----------------------|--------------|-----------------|-----------------|
| `#sec-connector` | `connector-morph` | 0 | 6.7 | 6.7 |
| `#sec-chat` | `chat-response` | 6.7 | 6.9 | 13.6 |
| `#sec-response` | `response-scroll` | 13.0 | 6.7 | 19.7 |
| `#sec-followup` | `followup-type` | 19.4 | 6.0 | 25.4 |
| `#sec-thinking` | `thinking-big` | 25.0 | 1.3 | 26.3 |
| `#sec-compose` | `compose-ui` | 25.8 | 13.3 | 39.1 |
| `#sec-sure` | `sure-response` | 38.8 | 0.4 | 39.2 |
| `#sec-thinking2` | `thinking-big-2` | 39.0 | 1.3 | 40.3 |
| `#sec-tasklist` | `compose-tasklist` | 40.3 | 9.8 | 50.1 |
| `#sec-outro` | `outro` | 49.9 | 3.4 | 53.3 |

Overlapping `data-start` values before the prior section ends are intentional (crossfades and zoom-throughs). Total root duration is `data-duration="53.3"` on `#claude-paper`.

### Root seam constants

Keep these GSAP instants aligned with the table above when editing `index.html`:

| Constant | Time (s) | Transition type | Sections |
|----------|----------|-----------------|----------|
| (hard cut) | 6.7 | Hard cut | `connector-morph` → `chat-response` |
| crossfade | 13.0 | 0.6s opacity | `chat-response` → `response-scroll` |
| `CUT` | 25.2 | Inverse zoom-through | `followup-type` → `thinking-big` |
| `CUT2` | 26.0 | Inverse zoom-through | `thinking-big` → `compose-ui` |
| `CUT3` | 38.8 | Leftward cut-the-curve | `compose-ui` → `sure-response` |
| `CUT4` | 39.2 | Inverse zoom-through | `sure-response` → `thinking-big-2` |
| `CUT5` | 40.3 | Leftward cut-the-curve | `thinking-big-2` → `compose-tasklist` |
| `CUT6` | 49.9 | Leftward cut-the-curve | `compose-tasklist` → `outro` |

```text
Paper canvas (#F0EEE6 on html, body, #claude-paper)
├── z-index stack #sec-connector … #sec-outro (later = on top in crossfades)
└── rootTimeline only blends seams; scenes own internal motion
```

### Layout anchors that must match

**Seam 1 (6.7s, hard cut).** `connector-morph` ends with `.lcomposer` mirroring `chat-response` `.composer` (width `84cqw`, shadow, cursor position/velocity). `chat-response` picks up the cursor at `left:'22%',top:'45%'` with matched easing — a 1:2 split documented in both plates.

**Seam 2 (13.0s, 0.6s crossfade).** `#sec-response` starts at `opacity: 0` until the root fade. Message bubble and thin composer must sit at identical positions in `chat-response` and `response-scroll` (`top: 87%`, same placeholder `"Write a message..."`).

**Seams 3–4, 6 (inverse zoom-through).** Outbound section scales to `0.8`, `blur(20px)`, opacity `0.15`; inbound enters at `scale: 1.25` and settles to `1` over `0.5s` with `expo.out`. Adjust `CUT` / `CUT2` / `CUT4` together with overlapping `data-start` values — not in isolation.

**Seams 5, 7, 8 (leftward cut-the-curve).** Outgoing section throws `xPercent: -13` over `0.26s` with `power2.in` while fading to opacity `0.55`; incoming section is already at opacity `1` (or word at `x:210 → 0` in `sure-response`). Paper background must stay `#F0EEE6` so exposed right edges do not flash a different color.

### Scene tail holds

Internal timelines must run through each plate's `data-duration` so HyperFrames does not insert a black frame before the next section:

- `response-scroll` — hold comment targets ~6.7s tail before `followup-type`
- `connector-morph` — final hold from 6.3–6.7s matches `data-duration="6.7"`
- `sure-response` — 0.4s total beat; root zoom takes over at ~0.2s

<Steps>
<Step title="Reproduce at the seam">

```text
index.html with ?t=<seam-0.2>   # e.g. ?t=6.5 for seam 1, ?t=12.8 for seam 2
```

Compare outgoing and incoming plates side by side at the cut instant.

</Step>
<Step title="Check constant vs data-start">

If you move a section's `data-start`, update the matching `CUT` / crossfade time in the root script block. `CUT3` must stay equal to `#sec-sure` `data-start` (38.8). `CUT5` must match `#sec-tasklist` `data-start` (40.3).

</Step>
<Step title="Verify shared composer CSS">

For chat → response → followup, confirm composer `top`, `height`, `box-shadow`, and placeholder strings still match across `connector-morph`, `chat-response`, `response-scroll`, and `followup-type`.

</Step>
<Step title="Confirm paper underlap">

Keep `background: #F0EEE6` on `html`, `body`, and `#claude-paper`. Do not set scene roots to pure white — crossfades and cut-the-curve throws expose the canvas behind sliding cards.

</Step>
</Steps>

## Timeline registration failures

HyperFrames discovers compositions through `data-composition-id`, loads `data-composition-src` templates, and plays paused GSAP timelines from `window.__timelines[id]`.

### Registration contract

| Layer | Required shape |
|-------|----------------|
| Root | `#claude-paper` with `data-composition-id="claude-paper"` → `window.__timelines["claude-paper"]` |
| Section slot | `#sec-*` with matching `data-composition-id`, `data-composition-src="compositions/….html"`, `data-start`, `data-duration` |
| Scene file | `<template id="{id}-template">` wrapping a root `div` with the same `data-composition-id` |
| Timeline | `const tl = gsap.timeline({ paused: true });` then `window.__timelines["{id}"] = tl;` |

Root registration (master seam timeline only):

```javascript
window.__timelines = window.__timelines || {};
const rootTimeline = gsap.timeline({ paused: true });
// … seam tweens …
window.__timelines["claude-paper"] = rootTimeline;
```

Scene registration pattern (representative):

```javascript
window.__timelines = window.__timelines || {};
window.__timelines["chat-response"] = tl;
```

### ID inventory (must all exist after load)

`claude-paper`, `connector-morph`, `chat-response`, `response-scroll`, `followup-type`, `thinking-big`, `compose-ui`, `sure-response`, `thinking-big-2`, `compose-tasklist`, `outro`

`tesla-rap` is a standalone plate under `compositions/tesla-rap.html` — not mounted in the master `index.html` stack.

### Common failure modes

| Mistake | Symptom |
|---------|---------|
| `data-composition-id` typo between `index.html` and scene file | Section slot loads HTML but timeline never binds |
| Missing `window.__timelines["…"] = tl` | Frozen scene at frame 0 |
| Timeline left playing (`paused: false`) | Drift vs master clock on render |
| `data-duration` shorter than GSAP timeline | Black tail or early cut before seam |
| `data-composition-src` path wrong | Empty section div |
| `querySelector('[data-composition-id="…"]')` runs before template inject | Script throws; no registration |
| Duplicate keys in `window.__timelines` | Last writer wins; unpredictable scene |

<Steps>
<Step title="Inspect registrations in preview console">

After the master loads, expect twelve keys on `window.__timelines` (root + ten mounted scenes). Each value should be a paused `gsap.core.Timeline`.

</Step>
<Step title="Validate one scene in isolation">

```
compositions/compose-ui.html?dev=1
compositions/compose-ui.html?t=12
```

Autoplay and seek helpers are ignored by HyperFrames render but prove local GSAP wiring.

</Step>
<Step title="Align duration triple">

For each scene, keep these equal: `data-duration` on the section slot in `index.html`, `data-duration` on the scene root div, and the summed GSAP timeline length (including tail holds).

</Step>
<Step title="Check GSAP CDN">

`index.html` and scene plates load `gsap@3.12.5` from jsDelivr. Offline preview fails every timeline — confirm the script request succeeds.

</Step>
</Steps>

## Quick verification checklist

| Check | Pass signal |
|-------|-------------|
| `git lfs pull` | `voiceover.mp3` ≈ 150 KB; `fonts/*.woff2` ≫ 1 KB |
| SFX present | `click.mp3`, `toggle.mp3`, `typenew.mp3` exist at repo root |
| Fonts | Text visible immediately at `?t=0` on each plate |
| Audio | No 404 on `*.mp3` in Network tab during full 53.3s play |
| Seams | No pop at 6.7, 13.0, 25.2, 26.0, 38.8, 39.2, 40.3, 49.9s |
| Timelines | `Object.keys(window.__timelines).length === 11` on master load |
| Output size | Render reports 1920×1080, duration 53.3s |

<Info>
Local dev query params (`?t=` seek, `?dev=1` autoplay) are documented in scene scripts as ignored by the HyperFrames runtime. Use them only for browser debugging — not as render configuration.
</Info>

## Related pages

<CardGroup>
<Card title="Installation" href="/installation">
Git LFS setup and folder layout prerequisites before first preview.
</Card>
<Card title="Fonts and assets" href="/fonts-and-assets">
Self-hosted woff2 inventory and LFS dependency list.
</Card>
<Card title="Sync audio and SFX" href="/sync-audio-and-sfx">
`data-start`, `data-track-index`, and volume wiring for VO and generated SFX.
</Card>
<Card title="Edit the master timeline" href="/edit-master-timeline">
Adjust `CUT`–`CUT6`, section `data-start`, and root `window.__timelines` registration.
</Card>
<Card title="Transition grammar" href="/transition-grammar">
Normative seam types: hard cuts, opacity crossfades, inverse zoom-through, leftward cut-the-curve.
</Card>
<Card title="Composition model" href="/composition-model">
How root and scene compositions register on `window.__timelines`.
</Card>
</CardGroup>

---
