The person brings paired recordings, numbered so each screen capture starts with its webcam file (the screen has no sound; the webcam carries the mic), the brand kit (fonts, colours, logo, any mascot art) and the finished files the walkthrough shows off. You deliver a 1920×1080 cut of the best takes: the screen under a camera that zooms to and highlights what is being talked about, the presenter in a round corner bubble, karaoke captions, a brand motion graphic on every jump in time, and the finished videos full screen with their own sound.
Everything is local and free except speech-to-text, which is whisper-cli unless the
person agrees to pay for elevenlabs-speech-to-text. Record the pairs, crops, bubble
side and fps where you keep the job's notes, and the brand in refs/brand.md (ask the
brand questions in guide-capture-a-brand, route B).
A still screen of the product shown full frame (an INSERT, a screenshot) moves rather
than sitting: hn4a-compositor-make-product-ui-exciting.
Steps
- Probe and transcribe (
ffprobe-inspect-media). Probe every file: screen recordings come VFR and often ultrawide; webcams 1080p30. Transcribe every webcam's audio in parallel (whisper-cli-transcribe-with-word-times) and look at the screens (step 2) while they run. Mark anything the mic heard the computer play back (the product's own videos, a tab). - Look at the screen. A contact sheet per recording at one frame every 10 s
(
python-contact-sheet,video --every 10). Choose one 16:9 region per recording that holds everything shown, and check one crop at full resolution. Note which way the presenter looks (toward their screen): the bubble goes on that side (guide-present-with-an-avatar, Layouts). - Write the paper edit (
guide-cut-best-takes, route B:python-cut-phrases-from-takes): the cleanest complete take of every line, as a text cut list. Get to the UI within seconds. Add aJUMPwith a label ("LATER THAT DAY", "A FEW MINUTES ON") wherever time passes, a 2xFASTitem for any action that pays off a line (a line about asking for changes → the typing), anINLINEitem for a file the presenter plays inside the UI (aligned withalign), and anINSERTfor a finished file shown full screen.planuntil it resolves. Gate: the person reads the plan as text with its total length; a cut list change costs nothing now. - Cut the tracks (
python-cut-phrases-from-takes,ffmpeg-normalize-loudness): the screen crop scaled to 2560×1440 (room to zoom), a 720×720 face crop of the webcam, the mic, on one 30 fps grid (ffmpeg-frame-exact-trim, The frame grid); the voice to −16 LUFS. Mux the screen track and voice into a plain rough cut. Gate:review_approvewith the rough cut, before any graphics. - Build the spec (
guide-add-titles-and-motion-graphics,hn4a-compositor-motion-graphics,hn4a-compositor-in-scene-titles): one build script readstimeline.jsonand writes the spec, bottom first:- An ink background, then the screen track under a camera with highlight rings on
what's named (
guide-show-a-product-on-screen, A screen recording under a camera), at the calm pace (hn4a-compositor-calm-explainer-camera, its walkthrough row: a 4% creep, 0.7 s eases landing 0.15 s before the phrase). Clamp framings to the screen, except one that frames cards under the bubble: frame those beside it and let the ink show past the screen edge. - The webcam: full frame for the opening line, then on the presenter's own gesture
into a 270 px bubble 44 px from the corner over 0.7 s (
guide-present-with-an-avatar, Layouts), while the screen flies in from the side they point to (anxand a −6°rotatekey). Then the bubble track for the rest, a 6 px accent ring, faded out during inserts. - Karaoke captions on
words(guide-caption-a-video, the 16:9 walkthrough row: the spoken word on an accent pill, an ink outline that reads over a white UI), in a box above the bottom edge clear of the bubble;skipthe insert spans. - Each JUMP: a dotted panel in the brand's primary colour wipes across with an accent band leading it, the mascot runs through bobbing every 0.22 s, a clock spins beside the label in the brand's display face. 0.35 s lead and tail around the 1.6 s hold.
- Each INSERT: the finished vertical video 1000 px tall centred on the primary colour, an accent ring, a short tag ("THE RESULT") and the mascot. An end card of 3.2 s.
audio:voice.wav, eachinline_NNNN.wavat its item's start, each insert's file at its start at 0.9.
- An ink background, then the screen track under a camera with highlight rings on
what's named (
- Stills, then the live spec. A still at every framing, highlight, jump and insert
(
still --at), run one after another. Fix boxes in the build script and rebuild. Gate: the live spec (hn4a-compositor, Live spec, then render) (cut/walkthrough.json), with the stills. - Render and deliver (core skill): 8 workers, frame count against round(duration ×
fps), a contact sheet looked at. Then
deliverthe render.
Lessons from the first round
The first delivery came back with these notes; build them in from the start.
- Get to the UI in seconds. A 15 s full-frame webcam opening was too long. Cue the switch on the presenter's gesture: they pointed up-left on "this", so the screen flew in from the left as they shrank into the bubble.
- Bubble on the side the presenter looks toward (
guide-present-with-an-avatar): bottom-right looked away from the UI; bottom-left looked into it. - Zoom less (
guide-show-a-product-on-screen): 2.1x cut off text; 1.15–1.6x framing the whole card held. - A highlight ends with its shot: one timed "+3 s" stayed up after the cut to the next recording.
- Keep the action that pays off a line. After a line about asking the app for a livelier read, the person wanted to see the typing: a 2x FAST item, keyboard sound at tempo.
- A clip shown inside the UI stays inside the UI. The first cut played in the app's review panel, so show it there (INLINE, zoomed on the player) with the file's own sound aligned to the mic by envelope cross-correlation (5 ms hops, r 0.81). Only the finished video at the end goes full screen.
Choices this workflow makes
- A text paper edit, not a waveform cut (
guide-cut-best-takes, route B). Takes are many and split across files, and the person approves words; the cut list names them. - Cues on phrases. Every zoom, highlight and caption reads comp times from
timeline.json, so a re-cut rebuilds the spec without touching a number. - A 2560×1440 screen track under a 1080p frame (
guide-show-a-product-on-screen, Choosing). - The original files for anything played back. The mic's copy is roomy and late; the file's own sound is clean.
Dead ends
- Highlight boxes estimated from a contact sheet landed a whole row high; read them
off a gridded frame of the cut screen track (
guide-show-a-product-on-screen). - Text layers with
htmland nostyle.font: the runtime checks the first family instyle.font; without one it fell back to Times and the render aborted. - The mic's copy of a played-back clip: it leaked into the transcript as speech and sounded like a room recording. Skip it; use the original file.
- A mascot PNG with a coloured drop shadow lost its shadow on a background of the same colour and read as a blob. A die-cut sticker version (ink body, accent screen, a white 14 px outline) reads on the brand colour and over screenshots.
- Stills in parallel: 16 at once hung. One at a time takes about 1.4 s on a 2,100-layer spec.
Worked example
Acme Co.'s desktop app walkthrough: 30 min of footage in 5 pairs (screens 3440×1440 VFR, webcams 1920×1080 at 30 fps) cut to 5:40.
| Pair | Screen crop (from 3440×1440) | Kept | Round 1 note |
|---|---|---|---|
| 1 | 1351×760, one window centred | intro, install and account setup | intro too long; zooms to 2.1x cut off text |
| 2 | 2512×1413, two windows side by side | starting a project, the brief, the first review | add the typing as FAST 2x |
| 3 | 2512×1413 | following progress | a highlight outlived its shot |
| 4 | 2512×1413 | the first cut, played in the review panel | keep it inside the UI (INLINE) |
| 5 | 2512×1413 | the final cut full screen, the sign-off | approved |
- The cut list: 74 phrases, 4 jumps, 1 FAST, 1 INLINE, 1 INSERT; 271 segments after pause squeezing, cut in 51 s with 8 threads.
- The spec: about 2,100 layers (captions are two per word). Stills about 1.4 s each, one at a time. Rendered with 8 workers.
- Cost: nothing beyond speech-to-text; every other step ran locally.


