# Example: long-form talking head
A single speaker to camera — an explainer, a podcast solo, a course lesson. The recording is long and raw: restarts, flubbed lines, and dead air between thoughts. The edit cuts it down to the clean story, back-to-back, never mid-word. The transcript drives the A-roll; the waveform separates silence from performance.
## 1. Brief
Write the brief first. It records the source files, the target duration (or "keep everything good"), and any editorial instruction. Absent a target length or explicit direction, **make no editorial cuts**: keep every good part, drop only silences and double takes, and keep the story chronological.
## 2. Analysis
The transcript is the spine, so transcribe everything with speech.
- **Transcribe every video and any external audio.** `transcribe` writes word-level start/end times to a JSON file — the times you cut on. Run it on each camera take and on any separate recording (a lav or interface track you will sync to).
- **Render the waveform to read the gaps.** `waveform` marks silence in red and returns it as second ranges. A transcript marks only speech, so a gap in it can be silence *or* something to keep — a laugh, a breath. The waveform tells them apart: red is dead air to cut; a gap that still shows signal is performance to keep.
- **Resolve double takes visually.** The transcript shows repeated lines; usually the **last** take is the keeper. When takes read equally well, `grab` the first word of each and keep the sharpest — motion blur means a bad take.
## 3. Lay out the A-roll
Drop **every** double take and silence, and put the good parts in chronological order.
```tsx
import { For } from "solid-js";
const raw = "/Recordings/take.mp4";
// Kept stretches, in order — source range only.
const takes = [
{ src: raw, sourceIn: 48.2, sourceOut: 53.9 }, // opener — third take, sourceIn on the first word
{ src: raw, sourceIn: 61.7, sourceOut: 69.4 }, // next sentence — sourceIn opens ~0.4 s early for a breath
{ src: raw, sourceIn: 74.0, sourceOut: 78.1 }, // mid-sentence pickup — flubbed clause dropped
{ src: raw, sourceIn: 95.2, sourceOut: 102.8 }, // closer — trailing air left in sourceOut
];
// Chain them back-to-back: each start is the sum of the durations before it.
let cursor = 0;
const aRoll = takes.map((t) => {
const start = cursor;
cursor += t.sourceOut - t.sourceIn;
return { ...t, start };
});
export default function Project() {
return (
{(clip) => (
)}
);
}
```
The silence you *keep* between sentences lives inside the clips, not in a timeline gap — a gap in a sequence freezes or blanks the frame. Carry a pause by extending a clip's `sourceOut` (or opening the next `sourceIn`) into the real silence, and keep the timeline gapless.
Save the file — the app recompiles and re-renders it — and get the spine right before layering anything on top.
## 4. Cut points
- **Open tight.** Set the first `sourceIn` on the first word — dead air at the top kills retention.
- **Between sentences, leave 0.3–0.5 s of silence.** Enough to breathe, not to drag. Tune it with each clip's `sourceOut` / next `sourceIn`.
- **Mid-sentence, butt the words together.** When you drop a clause inside a sentence, close the gap as far as it goes — never mid-word. Grab the frames around the join to confirm the word is whole.
- **End on up to 0.8 s.** Leave a little trailing air in the last `sourceOut` so the video doesn't stop abruptly.
## 5. Verification
Run `check` on the scene first: on a long timeline of many clips, a `sourceOut`/`start` that don't meet leaves a gap no sampled frame would land on, and the check names those spans outright.
Then the cut points, which matter most. Capture the **first frame of every clip** with `capture` at each clip's `start`, and check the cut didn't land on a bad frame — motion blur is the usual tell; nudge `sourceIn` a few frames to a settled one. Reconcile against the brief, and re-check neighbouring cuts after any structural change.
## 6. Visual hook (optional)
A hook makes the video readable at a glance. Aim for a frame you could lift out and use as a thumbnail.
- **Just a title.** One line of large Inter at medium weight, in a single colour. That is the whole hook: **no sub-header, eyebrow, or secondary line**, and **no background, box, panel, or fill** — the text sits directly on the A-roll.
- **Placement.** Beside the speaker's head or below it, **never covering the head**. A popular strategy is to place it A-roll aware.
- **Duration.** Keep it on screen as long as the viewer needs to read it.
One line of copy is a job for the native `` tag:
```tsx
The one editing trick
```
## 7. Captions (optional)
Add captions **last**, after every cut and overlay is verified. `src` names the recording's subtitle file (`.srt`, `.vtt`, or a transcript `.json`). Use the **`whisper`** preset aligned to the bottom, and start it where the hook ends — set both `start` and `sourceIn` to that timestamp so the transcript stays aligned (see `reference/jsx/captions.md` in the project's docs). Keep captions off overlays and off the important part of the A-roll.
```tsx
{/* Hook holds until 00:03; captions begin there. */}
```