# Troubleshooting

> Recovery for missing LFS audio/SFX, font-display:block loading stalls, seam misalignment between consecutive scenes, and timeline registration failures.

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

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