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

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