# HyperFrames composition model

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

- Repository: heygen-com/hyperframes-launches
- GitHub: https://github.com/heygen-com/hyperframes-launches
- Human docs: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b
- Complete Markdown: https://www.grok-wiki.com/public/docs/heygen-com-hyperframes-launches-996f3eaa626b/llms-full.txt

## 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>
