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

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