# Making a Music Video in Code: A Playbook for Claude ## What this file is and how to use it This playbook lets Claude make a music video where every visual is rendered in code: 2D and 3D scenes written as programs, drawn frame by frame and timed to measurements of the song. It comes from TJ Digital (tjrobertson.com). In October 2026, Tavi, TJ Digital's AI system, made the 4:48 music video "Don't Close the Tab" (https://www.youtube.com/watch?v=arpImsxochM). Tavi isn't tied to one AI model; she built this video using Claude Opus 5.5 in Claude Code, and TJ Robertson directed it over about twelve review rounds in about three days. Suno generated the music. Every visual was made in code, with no image or video generation model in the final picture. This file is that production's process, written for any song: the techniques, numbers and rules that held up, and the mistakes that cost time. Treat its numbers as tested starting points from one film at 1920x1080 and 24 fps. You'll need the song as a WAV file, its stems (Suno can export them), the lyric sheet, the style prompt if the song was generated, reference art for any character, Claude Code on a computer (a good graphics card helps, mostly for 3D scenes and for measuring the song faster), time, and someone to direct. Three ways to use it: 1. In a Claude Project: add this file to the project's knowledge. Claude can then plan the video with you, write the shot sheet and write the code. Measuring the song and rendering thousands of frames have to run on a computer with the tools installed, so for the build itself use Claude Code, or run the code yourself. 2. In Claude Code: save this file in the video's project folder as music-video-in-code-playbook.md (tjrobertson.com serves it as a .txt file) and add a line to that folder's CLAUDE.md, such as: "Before planning or building anything for this video, read music-video-in-code-playbook.md and follow it." 3. As a skill: save the file and ask Claude: "Make this playbook a skill. Add the skill's name and description header and save it where my skills go." Claude then loads it when a request matches the skill's description, such as asking for a music video, and you can also call it by name. The story of how the video was made, with frames from the film, is at https://tjrobertson.com/how-to-make-a-music-video-with-ai/. Questions about this playbook: https://tjrobertson.com/contact/ or tj@tjrobertson.com. Everything after this section is written to Claude. ## Before you start ### Measure and look, because you can't watch or listen - You can't watch the video or hear the song. Judge both by measuring (beats, drum hits, word times, loudness, the difference between frames) and by looking at frames (contact sheets around every cut, at full size and at phone size). - Motion faults hide in single stills. Look at consecutive frames through every fast move and at each shot's first frames. Wherever something should hold still and only grain or texture should change, measure the difference between frames. - The aim: the viewer notices the song and the images, never the editing. Every cut, word and camera move lands on the music, and nothing flashes, drops out or pops. When a choice is unclear, take the version a viewer would not notice for the wrong reason. ### What you do well, and what costs more Plan the video around these. They held true on "Don't Close the Tab". - 2D comes fairly easily to you, and it can be beautiful: type and kinetic words, shapes and abstract images, diagrams and charts, recreated app and web screens, cut-out characters moved as rigid pieces, and effects (glows, grain, camera shakes, perspective switches). Start from 2D. - Cameras are a strength: placing things in 3D space and moving a camera through it, including flat 2D art laid out in depth. - Your timing is close to exact once it is measured. You can't hear the voice or the music, so a cut or an event lands on its word or beat only when its time comes from measurement (word times, beats, hits found on the stems), never from a guess. On the film, 113 of 121 cuts landed within one frame of a measured event and the other 8 within five, and the director still caught a few sung words early or late by ear. - 3D scenes take considerably more effort. Every model and every set has to be built, lit and checked in code, and heavy looks render slowly. Use 3D worlds sparingly (for a move through space, for scale, or for a character acting in a place) and in a stylized look. Realistic 3D worlds look cheap unless every surface is detailed, and a near-realistic character looks uncanny until it matches its reference exactly. - Drawing realistic or organic images (people, places, painted scenes) and animating characters frame by frame are weak. For the first, use photos, footage or an image model where the project allows them. For the second, move characters as puppets (rigid parts on joints) or hold them still. - Generated video can't be cut to precise cues, so it never carries a scene: atmospheric inserts at most. When a brief asks for one of the costly kinds, say what it will cost and offer the 2D route before building. ### Generated images and video - On "Don't Close the Tab", the team spent about 1,155 Higgsfield credits on 56 generated test clips, and none reached the film. A clip can still serve as acting reference: it can find a pose that you then build in code. - If you test clips, start each one from your own render of the character, so it stays on model. In the prompt, describe the physical pose rather than the gesture's name ("paws flat against an invisible pane of glass", where "paws press together" gave praying hands), and rule out what the words imply ("no tears, no water"). - How the models behaved in October 2026 (check again before relying on it): Grok Video 1.5 used the start image as the exact first frame, so its clip could cut straight from the render; Seedance 2.5 treated the start image only as a reference; Kling 3.0 held the character only with both a start and an end frame; Hailuo 2.3 changed the eyes; Veo 3.1 Fast grew extra arms. - Review every generated image and frame before use. Image models invent interface text and gibberish signage, draw odd anatomy, and once produced an obscene gesture. - Agree a budget for paid generation (images, video, music, voices) at the start, and ask before passing it. ### What to ask for - The song as a WAV file, with its stems: the artist's multitrack, a music library's stems, or the generator's own export (Suno can export a song's stems). Suno had no public API in October 2026, so the person makes the song there and hands you the files. Check that the plan it was made under allows commercial use. - The lyric sheet, and the style prompt if the song was generated. - Reference art for any character. For a character someone already has, ask who made it and with what, and gather every source: expression and pose sheets, turnarounds, earlier renders and clips, and the generation history in the account they came from. Take its expressive range from the most expressive of these sources; the canonical render alone undersells it. - The frame rate, settled before you measure anything, since the envelopes, drum hits and sync checks are computed per frame. The film ran at 24 fps; 30 fps is the usual default for other video. - Whether the person wants to direct the video shot by shot. That changes how the work runs (Working with a director). - The budget for paid generation. Then decide what the brief leaves open, and show the calls that shape the whole video with the first look rather than asking up front: the look every scene fits; whose point of view the song is sung from, and who is never shown; whether a character sings, plays an instrument or neither; the tone; how pace and impact follow the song; and the climax. Ask only for a missing input you can't do without, and infer the rest. Unless the person has chosen to direct in rounds, run the video end to end. Stop only when a required input is missing, the machine can't be set up, a check fails twice for the same reason, paid generation would pass the budget, or a decision only the person can make blocks the next step. ### Tools - A computer, ideally with a GPU: it speeds up the measuring and WebGL 3D in headless Chrome. The film rendered on one consumer card (an RTX 5070 Ti) under Windows. - Python 3 with numpy, scipy, soundfile, soxr, librosa, Pillow, torch and torchaudio, plus demucs (stem separation), beat_this (beat tracking), whisperx or stable-ts (the first pass on the lyrics) and pronouncing (the CMU pronouncing dictionary). - Node 20 with puppeteer (it drives headless Chrome), three.js for 3D, and opentype.js if you set type in 3D. - ffmpeg and ffprobe. This playbook asks you to write a set of small tools: a beat tool, an envelope tool, a lyric re-timer, a sung-word checker, a song-time parser, a cut checker, a renderer, a camera-effects module, a probe, a chunk tool and a splice tool. Each is described precisely enough to build. Build each once, test it on the song, and keep it in the project. ### Keep the production's state in files A production that runs over several sessions keeps its state in files, because each new session, and each summary of a long one, loses detail. Read the files at the start of every session, point the project's CLAUDE.md at them so a fresh session finds them, and never rebuild a decision or a timing from memory. - The bible: the brief, the standing rules, where the work stands, and a dated decision log. Each entry says what changed and which file holds it. Mark the person's own calls with their words, so later sessions and agents can tell their rules from your proposals. Keep decisions that were later replaced, with the entry that replaced them. - The plan, with each earlier version kept as its own file. Never overwrite a plan the person has seen; the new one says what it follows. - The notes register (Notes, under Working with a director). - A lessons file, updated in the same session as each technique, measurement or correction, with the numbers that made it work, written so a video on another subject can reuse it. - Where agents build parts, a capability note from each for whoever plans next, in one shape: what its engine or world does well and poorly, the real cost, what to use it for and avoid, and ideas. ## The song: measure it before planning Measure the track into one timing file before planning, and make every plan, scene and check read it. Plan from the file, never from the brief or the generator's prompt, and never set a time by hand. On the film, a hand-set time for the final chorus was a second off, and a key change the style prompt asked for wasn't in the song. Put the video's turning points on measured events, such as a colour change on the band's first hit. ### The files and the order - Keep the mix, one WAV per stem, the lyric sheet, and a small settings file for the song: the frame rate, the meter, the BPM and a measured downbeat when the beat tracker needs them, which stems are the lead vocal and the drums, the sections, and the fixes for the word re-time (Sung word times, below). - Measure in this order: stems (only when there are none), beats and bars, stem envelopes and drum hits, the first pass on the lyrics, then the timing file, which re-times the sung words each time it is built. Run them all again after any re-measure and after any change of frame rate. - The timing file holds the sections, beats and bars, where each stem plays (entrances and drop-outs), the drum hits with their strengths, and the lines and word times. Draw a song map from it (sections, bars, each stem's level and the lyric lines along one time axis) to plan from. ### Stems - Real stems beat separated ones. A separation shows roughly where each instrument plays, but not its exact hits and entrances. On the film, the real stems gave every drum hit with its strength, and showed the drums, bass and guitar stopping just before a whispered name, with a quiet piano left under it. - Separate the mix only when there are no stems, with Demucs: ``` demucs -n htdemucs_ft -o separated -d cuda song.wav demucs -n htdemucs_6s -o separated -d cuda song.wav ``` htdemucs_ft gives drums, bass, vocals and other; it is slower than the base model and a little cleaner. htdemucs_6s adds guitar and piano, and its piano stem is its weakest. Each writes separated/MODEL/TRACK/STEM.wav. Use -d cpu on a machine without a GPU. ### Beats, bars, tempo and key Write a beat tool that does this: - Find beats and downbeats in the mix with beat_this, checkpoint final0, with no DBN post-processing: ```python from beat_this.inference import File2Beats tracker = File2Beats(checkpoint_path="final0", device="cuda", dbn=False) beats, downbeats = tracker("song.wav") ``` - Take the beat period from a BPM you give it, or else from the slower of the inter-beat-interval modes that hold at least 20% of the song's time. Trackers flip between a slow song's tempo and its double: a 67 BPM ballad read as 67 and 134 in turns. Give the BPM when the song's beat is the faster one. - Clean the grid: walking the raw beats, drop any beat closer than 0.72 of the period to the last one kept. - Bars: every fourth clean beat (or the song's meter), phased by the tracker's downbeats with a Viterbi pass that re-phases a bar only where the evidence holds for several bars or across a gap in the grid. When the tracker's phase is wrong, count bars through the whole song from one downbeat you measure yourself. The tracker's own downbeat list can hold half-bars: keep it as raw data, never use it as the bars, and report how many of its entries sit on a bar line. - Key: Krumhansl-Kessler key profiles on the chroma of the mix's harmonic part (librosa's harmonic-percussive split, then chroma), in 8 s windows every 4 s, summarized as stretches. It answers "did the key change the prompt asked for happen?" - Write the period and BPM and how they were found, the raw beats and downbeats, the clean beats, the bar lines, the local BPM per interval, the bar check and the key stretches. Refuse a song with fewer than 8 beats found. ### Stem envelopes and drum hits Write an envelope tool that reads every stem at the video's frame rate (frame i is time i / fps): - Loudness from 0 to 1 per frame, per stem: RMS over a window two frames wide, in dB, mapped from (ref - 34 dB) to ref, where ref is the stem's own loud level (the 98th percentile of frames within 60 dB of its peak). A quiet piano and a loud kit then both use the whole range. Use a one-frame attack and a release per instrument: drums 0.10 s, bass 0.35, guitar 0.18, piano and keys 0.22, synth 0.25, strings 0.40, lead vocal 0.15, backing vocals 0.20, woodwinds and brass 0.30, anything else 0.20. - Onset strength from 0 to 1 per frame, per stem: positive spectral flux on 2048-point frames, its slow floor removed, normalized to the stem's 99th percentile, with a 0.12 s release. - Split the drum stem into bands with 4th-order Butterworth filters run forward and back (zero phase): kick below 150 Hz, snare 150 to 2500 Hz, hats above 5 kHz. The snare band also catches the kicks, at about 0.6 of full strength, so set snare thresholds above that. - Drum hits per band: local maxima of the band's loudness above a threshold (kick 0.62, snare 0.55, hats 0.70), at least a minimum gap apart (0.11, 0.16 and 0.09 s), refined with a parabola through the peak. A hit's strength is its height divided by the band's 95th percentile of peak heights, capped at 1. - Peaks on a frame-rate envelope read the kit about 30 ms late (a quarter to two thirds of a frame). That is fine for camera pulses, which gate to whole frames. For a hit that must land on the picture (a fill's strokes, a slam), move it back to its onset: on a 2 ms RMS envelope (0.5 ms hop) of the band's own signal, find the last upward crossing, before the hit's loudest 2 ms, of a level 15 dB under that peak, searching up to 70 ms before the peak (or 1.5 frames, if longer). When the hit rises less than 30 dB, as hats do over a cymbal wash, use the point halfway up from the quietest point before it. A hit that rises less than 3 dB keeps its peak time and goes on an "unsure" list. - Write the hits in one file that the camera module and the checks both read: {"fps": 24, "bands": {"kick": [[t, strength], ...], "snare": [...], "hats": [...]}}, with times in seconds from the track's start. - Find where each stem plays (entrances and drop-outs) from its envelope. An instrument dropping out is as strong a cut point as an entrance. ### Notes of an exposed passage For a sparse, exposed passage (a solo piano intro), take per-note data off its stem: onset, pitch, velocity and decay. librosa's onset detection and its pYIN pitch tracker do this for a single line of notes. How the picture answers each note is in The camera and the music. ### Sung word times Every lyric on screen, every cut placed on a word and every singing mouth is timed from sung words measured on the vocal stem. Speech aligners are only a first pass on singing: they start each word where the previous word's text ends, so held notes and breaths pull word starts early, by up to about a second. 1. First pass. Prepare the lyric sheet: one sung line per line, lines that are only a section marker such as [Chorus] dropped, inline tags removed, curly quotes straightened. Align it to the vocal stem with either tool: - WhisperX (large-v3): a free transcription aligned with wav2vec2, the sheet's words mapped onto it in order, and words it didn't hear interpolated and listed. - stable-ts: a forced alignment of the sheet, one segment per line, plus a free transcription with voice activity detection, kept to catch ad-libs and sung changes to the words. On the film (541 words), stable-ts stretched the final chorus's first line over the guitar solo, and a second run misplaced three lines by up to 25 s. WhisperX placed every line within 1.4 s and heard all but one word. Check the line times before re-timing: the re-time searches about a second around each word, so a line in the wrong place needs a fix first. Keep the first pass as its own file and never edit it; put fixes in the song's settings. 2. Re-time every word on the vocal stem. Build it on a 5 ms analysis grid: - Landmarks: noise above 4.5 kHz, bursts after a closure, voiced onsets, dips in the 1 to 4.5 kHz formant band, and pYIN note changes and glides. - Phonetics: the CMU dictionary (the pronouncing package) says what each word boundary should look like: a sibilant before "so", a closure and a burst before "tab". Supply pronunciations for names and misspellings it lacks, and contractions as sung without the apostrophe ("dont", "youre"). - A Viterbi pass per line, with a minimum length per syllable, penalties for swallowed syllables and breaths, and a weak prior that the first pass runs early. - Each word gets four values. s is its first sound: the burst of p, t, k or ch (and of b, d or g when one is found), the start of s, z, sh, f, th, h, v or dh, otherwise the vowel. v is the vowel onset of its first syllable; it equals s for a word that starts on a vowel, nasal or liquid (m, n, l, r, w, y), and s is set to v when the word's first consonant runs into the previous word's (the z of "close" into "the"). e is its end: the next word's start, or the end of the sound before a breath. The confidence says how much worse the best path gets if the word moves more than 3 frames. - Always re-time from the first pass, never from your own earlier output, so re-runs reproduce instead of drifting. - It reads three kinds of fix from the settings. A fix for a misplaced line spreads its words evenly over a start and end you give, then re-times them; it keeps that start only if no landmark is found or the two agree within 0.12 s. Anchors are hand-checked word times the path must keep; after a whispered word, anchor the next word too, since a whisper has no voicing for the path to cross. Doubts are words to list for checking. - It reports its stats, the words to check, every word that moved more than a frame, the worst lines, and comparisons with any hand-measured onsets. It can draw each line: the stem's spectrogram with the first pass, the re-timed words and the landmarks. On the film, after the re-time, 16 of 17 separately measured onsets (measured on the stem by another agent, from the bursts, the pitch track and spectrograms) were within 2 frames starting from stable-ts, and 15 of 17 starting from WhisperX (median error 0.026 s either way). The two routes missed different words. The re-time is the bulk pass: every word that goes on screen or carries a cut is still measured again in the next step, whichever route you used. 3. Check every word that will appear on screen or carry a cut against three sources. Write a checker that takes a window (start and end in seconds) and the words sung in it: - Forced alignment in short windows on the stem, with torchaudio's MMS_FA pipeline (a wav2vec2 forced aligner that works on 16 kHz mono audio). Start each window about half a second before the line, since a window that starts after a word can't find it. Run two or more windows, each starting half a second earlier and ending half a second later than the last. MMS_FA reads only the letters a to z: drop apostrophes and punctuation, spell a plain number as it is sung ("2024" as "two thousand twenty four"), and write anything else with digits out in words. MMS_FA's model is licensed CC-BY-NC 4.0, for non-commercial use only. For commercial work, use an aligner whose model allows it, such as the English wav2vec2 model WhisperX aligns with (torchaudio's WAV2VEC2_ASR_BASE_960H, MIT licensed), with the text written in that model's own letters. - The pitch track's note starts, from pYIN: a new note when the pitch leaves its run's median by 0.7 semitone, with blips under 40 ms merged. Expect one note per sung syllable. - The loudness envelope: a dip marks a consonant, and high-frequency hiss a fricative. Also find the syllable nuclei (loudness peaks in the voiced band), noise segments and bursts above 4.5 kHz, and vowel changes inside a held note (the ratio of the 500 to 1200 Hz band to the 80 to 500 Hz band changing fivefold within 60 ms while the pitch holds). - Flag a word when any window scores it under 0.2 (the mean character score, from 0 to 1) or the windows disagree by more than two frames. A score under 0.2 is no answer: a whispered word can score near zero, and so can a window that cuts the word or a wrong lyric. Treat a flagged word as unmeasured until the strip settles it. - Draw a strip for each line and read it before trusting any number: the spectrogram to 8 kHz, the pitch as dots, the aligned starts with their scores (flagged ones in red), each word's first consonant and vowel onset, the note starts, nuclei, noise bars, vowel changes and the beats. Times slip where a line follows a held note or a reverb tail, where one held note carries several words, and on fast runs. Check the words that look right too. 4. Settle hard cases on a detailed spectrogram: a dark gap is an unvoiced consonant, and a vowel change inside one held note shows in the balance of the frequency bands or in the formants. Trust a voiced note start over a word guess, and never correct a time measured on the stem against an older table. 5. After any re-time, rebuild everything made from the word times (cuts keyed to words, mouth data, envelopes) and run the cut check again (Cutting). Which instant to use: - An impact, a slam or a cut on a word lands on the first frame at or after the vowel onset of its first syllable, because the beat sits on the vowel. - Writing and typing start at the first consonant. - Measure how a key word is sung as well as when. A whispered word asks for a hushed picture rather than a slam. Recited lines, held notes and belts decide where holds, push-ins and singing faces go. ### Write every time against the track - Write each event's time as a reference to the music, resolved from the timing file, never as raw seconds: - b:14.7 is the beat nearest 14.7 s. - bar:18 is the bar line nearest 18 s (a time, not a bar number). - w:good@18.03, wv:good@18.03 and we:good@18.03 are the sung word "good" nearest 18.03 s, at its first sound, its vowel onset or its end. - Any of them takes an offset in seconds: b:14.7+0.1. - Use one parser for these, shared by the scenes (JavaScript) and the checks (Python), that stops with an error on any reference it can't resolve. Give it a command that prints what one reference resolves to, and its frame. Re-measuring then moves every event written this way with the music, and no event is skipped silently. Anything held as plain seconds (the film's final edit was) has to be rebuilt from the new measurements and checked again. - An instant change on a hit starts on a whole frame (Motion and motion blur). - When a note names a beat ("the first beat of the next measure"), restate it by its intent ("the beat after the word") and check it against the bar lines and drum hits before building. On the film, the director's own count was a beat off, and the intent behind it was right. ## Planning ### One vision before any shot list - Write one vision for the whole video before any shot list, so every section serves one idea. Design it backward from the final image: the video in one sentence, the idea, the places and their rules, how the world changes on the way to that last image, the colour script, the set pieces, the rhymes (Using the song's structure), and how energy follows the song. - Test a central metaphor by asking whether it can grow into the ending, and drop one that leads nowhere. - Keep the set of metaphors small and consistent, made of familiar things in real materials. Introduce each one once, beside the real thing it stands for (a repository is created, then a shelf labelled with its name drops into the world); after that the stand-in reads alone. Show a world's rule once before the moment that depends on it. A metaphor the viewer would need explained reads as a mistake. - A line about a concrete thing gets a concrete image from the video's own world; avoid a symbol there, however well it fits. An abstract process becomes an everyday action everyone knows (painting over something for forgetting). ### Two layers: the story and the music - A music video runs on two layers. The story layer shows only what the song needs told: it sets up its world early, then comes back only for beats that move the story. The music layer plays with the song: performance, lyrics as objects, abstract images on the beat. The music layer takes more of the screen as the song builds. - A draft that gave nearly every lyric line a literal picture shrank most shots below a second and left the key moments no room. Don't show everything the song says: pick what matters most and give it room. ### Places, styles and colour - Different styles for different shots suit a music video, as long as the mix looks intentional (One look across the video). Give each place its own medium, camera and palette, so a cut says where you are. - Match each style to its line's weight: a playful treatment of a serious line doesn't land. - Bring in new colours and kinds of image as the song builds, and hold colour back early so its arrival lands. One setting held through an exciting section gets dull. ### Designing from the lines - Design each section from what its lines mean. A section built as a list of things to show misses the song's point. - Never show a negated line happening. When the song says something won't happen, a picture of it happening tells the viewer the opposite. Express the line's feeling another way, and if the negated thing appears at all, show it struck out. - Don't answer a big line with a literal image smaller than its meaning. Keep each abstract image tied to its line, so viewers can connect the two. Prefer visual puns and transformations to a literal picture of each line. When a line has to land and no picture of it does, set its words instead (Lyrics and type). - In a song sung to "you", consider never showing who is addressed, so viewers put themselves in that role. Show that side only through what they would see (their screen, their clicks) or as a faceless figure. - Open on the main character in their own world, doing something: it makes the character personal and the viewer curious. Holding back their face until a key line keeps a quiet opening interesting and makes the reveal an event. - A song that is funny because it takes itself seriously is played straight. - An example that stands for a kind of thing is one any viewer grasps at once: a storm-repair page ranking first on Google reads instantly, and a cold-chain audit page leaves viewers puzzling. - Nothing on screen gets ahead of the story or contradicts it. A label that announces a final state ("done", a total) appears only after the animation reaches that state, and a note, sign or message doesn't answer a problem before the words raise it. Names, dates and versions on screens and props are facts of the story: a name appears only once the story gives it, a date has the right weekday for its year, and neighbouring shots agree on the year. - Every state runs forward across cuts: a light that has gone out stays out, the time of day only moves on, and something destroyed stays destroyed (check later shots before destroying anything that comes back). A light change that means time passing happens on screen and travels from its source (dawn goes rose, then gold, then day). A memory has its own place and look (the past in one colour against the present's full colour), and the return to the present is shown happening. ### Using the song's structure - A song repeats itself, so plan its rhymes. A repeated line or situation comes back in the same framing, lens and staging with one thing reversed (daylight for dark, calm for panic), so the change is the only difference; build both from the same assets. A later chorus can resolve the fear of an earlier one, and the last image can return to the first. - Don't spend a big line (the title line, the hook) on its literal action. Give the line itself the weight, with its words on screen or big imagery, and land the action on the next beat: the words first, then the action. - Let a visual finish before the word it serves, and cut on the beat where a held word begins, so the held word plays over the next shot. - Give an instrumental solo or break a job in the story, and design it as a montage on the lead instrument's accents, measured on its own stem. It is the place for the biggest scale and for other art styles: short vignettes, one idea each in its own style, each landing its actions on the accents and holding before its cut. Keep them short, and reuse strong ones if the break needs filling. Shots of a character playing the solo work for about two quick shots; more gets boring. Anything shown being built must visibly build on the beats. ### How energy follows the song - Match the picture's energy to the arrangement. Big visual impacts (slams, jolts, giant type) go only where the music hits. Where there are no drums, actions are pressed rather than slammed, the camera drifts and lands on chords, and shots hold through the music's pauses. Giant type slammed over a solo piano opening was "a bad call". - A big musical moment gets an equally big image that keeps moving through the peak: a shot that stopped dead at a solo's climax felt awkward. Don't cut away from the payoff as the beat lands. - Put what must be read (a date, a name) in a quiet stretch, and keep reading-heavy or everyday shots out of the exciting ones. - A soft opening still has to hook at once, with things moving and the viewer kept curious. ### What earns a place on screen - Put something on screen only when it helps the viewer understand something hard to follow from the song alone, or when it is interesting in itself. If it does neither, leave it out, even when the words name it. - One idea per shot. Each shot shows one thing clearly and earns its place against its neighbours: if something better could be shown, or the shot beside it deserves the time, cut it. Two important messages never share a shot; give the second its own moment. When something has done its job, take it off cleanly, on a beat or a cut. - Show it long enough to take in, and no longer than what happens in it. Nothing the viewer has to understand flashes by: a date or a screen's key line gets at least a full second. A shot that outlasts what happens in it reads as dull: cut it into shorter shots that each carry one beat, or give it more to show. When the words list things faster than they can be shown, show the one or two worth seeing and hold them across the list. - Each cut brings something new: something else happening, or a clearly different view. A cut to the same subject from a slightly different angle reads as a mistake unless something visibly happens across it, and a run of shots with the same framing, move or layout reads as slow. Make the second shot clearly different, cut away to something else and back, or merge the two into one continuous shot. ### The shot sheet - Write the plan as a shot sheet before building any of it. First plans tend to pack every shot with ideas: start with fewer, each made clear. - Open with a section overview: each section's time, feeling, story and music. Then, for each section: a line of its measured musical events; its purpose; and its shots. Give each shot an id, its song times to the hundredth of a second, the place, the medium, the image in one sentence with the lyric quoted, how the camera crosses the cut, and a status (keep, rework, new, versions, picked). List every sung word in the section to the hundredth, flagging words that align poorly so they are measured again when the shot is built. Write each pick and its reason into the shot's entry, so the plan is also the record of decisions. - About 1 to 2 s a shot is a starting point, and what each shot has to deliver overrides it. A draft built to that length was too quick to follow; the approved cut of "Don't Close the Tab" averaged about 2.4 s a shot (122 shots in 4:48). Quiet sections and the outro take longer shots, and quick runs go only where every frame reads at once. Reactions held about 1.5 s and emotional beats 3 to 6 s read well. - A long shot needs enough happening in it: a heavy half-time bridge played as one long shot was boring, and worked as nine hard cuts on the snares. - When the person shares a reference video, study it frame by frame: step through its moving moments a few frames apart (one still per shot misses the camera's motion), read its source when it is public, and write down its craft as numbers (camera moves, type sizes, cutting pace). Borrow its technique and pace, and keep your own look unless the person asks for the reference's. ## The look ### Choose a look you can finish - Plan the look from what you do well (Before you start). Use 3D worlds sparingly, only for a move through space, for scale, or for a character acting in a place, and make them in a stylized look, because each 3D world has to be built and lit model by model. A stylized look forgives missing detail: the lower the fidelity of the art, the less missing detail shows, and darkness hides it too. Keep what the viewer must read closely (a screen, small type) in 2D. - Render the same two or three shots in every candidate look and compare them on one page. Then test the favourite on the hardest shots rather than the hero close-up: a wide, a far field, a big camera move, the smallest type. In 3D the world costs more than the character, so judge a look on a wide view of its world. - Refine the look with before-and-after stills from fixed cameras. - Attempt a showpiece set only when there is time to finish it; built with shortcuts, it looks like a mess. - To replace a look partway through, test the new one on the shots where the old one was strongest. If it wins there, it can replace the old look everywhere. - On the film, realistic 3D seen wide looked unfinished. A riso print look, with the 3D rendered straight into its inks, fixed it (The riso print look). ### One look across the video - When 2D and 3D shots share a video, render the 3D in the 2D look: the same palette, line, texture and grain, through the same final pass. A filter laid over a lit render still looks like 3D under a filter. - For a drawn look, draw outlines where object ids differ, at depth steps and at creases, with widths set in world units on each object and clamped to a pixel range. Give all the pieces of one object one id, so no line runs along a seam. - Mixed looks read as one video only with rules: one palette, type system and grain throughout; one meaning for each look (the past in a single ink, for example); and a change of look only at a story beat. Show the change as an event inside a shot, such as the new look spreading out from one point. A change of look at a cut with nothing to explain it reads as a failure to keep the look consistent. - When a shot moves to another medium, check that its idea still reads. - Make every effect in the look's own terms, or the effect shows its edges. In a print look, a light is bare paper ringed in ink, and a fade knocks the inks back toward paper. A glow put through the look bands into rings. Where the look allows a glow, clamp the highlights first, by the brightest channel so warm light keeps its hue; then apply the look and lay the glow back on top as light. Fade a light by dimming its source. - Motion follows the look too. Drawn characters can move on twos while the camera, the light and the expressions stay on ones. Texture redrawn on twos (a boil) reads as a living drawing on a moving shot, but it shimmers on a still hold full of thin lines, so turn it down there. - Carry no look from one video into the next as a default. This film's palette, inks and showpieces were its own choices. ## The riso print look The film used a riso print look: a few inks printed as halftone screens on paper, a little off register, with grain. The numbers below worked at 1920x1080 on that film. Its palette and its uses of the look are examples. ### When it suits a video - It suits graphic design (type, cut-out shapes, a few colours) and a video whose 2D and 3D shots must match, since both can print through one pass. It forgives missing detail. - Colour can become a code the viewer learns: an ink set per section, brand colours made from overprints. A section can change printing method (blueprint, pencil, night) without a new engine, in 30 to 60 minutes to a first proof. - A print has no glow, no depth of field and no glass or smoke, so each needs a print version (Light and effects in print). Nothing prints darker than its darkest inks overprinted, so a dark mood comes from composition (a small figure, one light, a big dark frame); tears and moody lighting barely print. Fine detail at a distance and small type are fragile. 3D worlds cost far more than 2D in this look too, so use them sparingly. ### The print pass Print every shot, 2D and 3D, through one pass so they match. - Each ink prints from its own plate, a coverage layer. A pixel on a plate is solid (full ink), a tint (a tone printed as halftone dots) or a flat (solid ink at partial coverage: an even, lighter colour with no dots). A knock-out cuts a shape out of a plate. - The pass screens each tint as round dots at its ink's own angle, offsets the plates, adds grain and paper fibre, and multiplies the inks over the paper, so overprints make new colours (pink over yellow prints orange). Start from real riso ink colours. - Values that worked: a 7 px halftone cell; screen angles of 15, 75, 0 and 45 degrees, then 30 and 60, with the darkest ink at 45 and yellow at 0; the colour plates 1.5 to 2 px off register, each in its own direction, and the key plate (the darkest ink, for lines and type) on register; grain at 0.22 on the film's own scale. Big flats print blotchy at that grain: on them, use grain 0.1, with the key ink's density at 1.3 and paper fibre at 0.45. - The inks mix in linear light, so partial coverage prints much lighter than expected: a dark ink at 90% printed a mid slate. Deep darks need coverage of 0.97 or more, and no minimum light added everywhere (a floor of 0.06 lifted every dark in a set). The deepest dark is the darkest ink over a second dark plate: navy over cool grey printed about RGB 36, 51, 83, while the same dark at 95% with grain printed a mid-blue that didn't read as night. - If a tone curve runs after the print, print through its inverse, so a colour asked for is the colour printed. ### Printing 2D Most of these hold for 3D shots too. - Print darks and glows as flats. A dark printed as a tint reads as dusty haze, and where a screen starts round a glow it draws a ring. Keep one mode within a gradient: a tint that switches to solid partway prints a hard line. - A pixel on one plate is either solid or screened. A graded tint over a partial solid on the same plate flipped to a screen where it darkened past half, and drew a ring. Put shading on a second plate. - At most two inks overlap in one place. Four overlapping tints printed an even beige; every ink at once prints mud. - A light ink over a dark one turns to mud (yellow over navy printed olive): knock the dark out first. Writing that glows on a dark ground is opaque strokes with the ground printed round them. - Misregistration fringes anything drawn in two inks: at 1:1, every spine in a wide of bookshelves had a magenta ghost. Keep fine detail on one plate and colour in flat blocks. Trap small two-ink marks: knock the dark ink out about 1.2 px wider than the mark and inset the second ink about 1.5 px, so the offset shows the lighter ink, never a dark fringe. - The cell is the print's resolution. A tint finer than the cell vanishes, so a line that must read is solid ink, and a pattern meant to be seen is at least twice the cell (about 14 px). Small things are solid ink too: a tint on a dot a few pixels across prints as grey mush, and a mark built of dots under about 4 px radius reads as speckle, so draw it as a solid shape and fade a small dot by shrinking it. A regular grid printed as a tint (LED dots) can moire with the screen. - A knock-out erases what is beneath it, so draw a container, then its contents, then anything crossing it. Paper-white type needs every plate knocked out under it. - A halo round type is knocked out of every plate. Secondary type in grey or a tint weakens below about 20 px. - Small type also beads into halftone dots at full 1080p, and on the film the cause was never found. The plate reaching the pass was clean, and neither making the type solid instead of tinted nor judging solidity by coverage instead of colour changed a pixel. Keep small type solid, large and in the key ink, and check it at 1:1 early. - A recreated screen changes state in print terms: dark mode is one swap on the key plate (paper and the key ink trade places), a fade from white knocks every plate partly toward paper, and a screen going dark is the key plate laid over everything. ### Printing 3D A print filter over a lit render failed: gradients banded, lights broke into dots, and it still looked like 3D with a screen on it. What worked was rendering the 3D straight into the inks. - Render ink coverage. Each surface's material says what it prints: a fill (solid or a tint), a halftone shade in one ink on the side away from a key direction, patterns. One pass writes a coverage layer per ink and a G-buffer (depth, normals and object ids), and the layers go through the same print pass as the 2D shots. - Every surface writes every ink (zero for the inks it doesn't use), so the depth test knocks out what is behind it, like a cut-out. Anything that should tint what is behind it (glass, dust, haze, a glow) must be a decal that adds ink; drawn as a surface, it knocks the world out to bare paper. A decal can only add ink: take ink away (light on a wall, a shaft) with a decal that multiplies what is beneath by one minus its coverage, and print bare paper with opaque geometry. - Outlines from the G-buffer belong to no plate. They stay when the inks fade (scale their weight with the key ink's), they print over decals, and they ring any particle or light in front of an outlined object: turn them off, or give the edge the nearer object's weight, on particles, lights and whatever a decal covers. Widths of about 1.7 to 6.5 px at 1080p matched the 2D strokes at a medium shot. - Fade distance into a flat ink, and keep solids flat as they thin, or the screen comes back far off. - 2D type over a 3D shot prints in the same pass, with the 3D frame as its paper, so it shares the dots and grain. ### Light and effects in print A print can't glow: paper is its brightest white, so light is ink taken away, bare paper ringed in yellow and orange. - Keep bare paper for the source. Compute the light on each surface as one number, soft-clipped as 1 - exp(-k * x) so lit surfaces never reach paper, and print it through one ramp of overlapping bands: paper, yellow, orange, the key ink, the key ink over a second dark plate. A pool, a shadow, a rim and dust then agree, and switching the light is one value. Keep the order all the way out, or a far area looks lit by a second light. - Give each step of the ramp about 0.15 s when the light changes: an eased change crossed every step in about three frames and read as a switch. - On a pale surface strong light is still paper, so warmth shows only at moderate light. Add a warm glow there as yellow, then orange, ink. - A highlight is a reflection: reflect the view ray off the surface, test it against the light's rectangle, and knock every ink out to paper there. It slides as the camera moves, as gloss does. With a strong yellow fringe it reads as a sticker. - Keep glows small and flat. A large soft glow printed as rings or a coarse dot haze: make it a flat, or end it within about 0.3 s. Wipe a glow inside the silhouettes in front of it, and give a group one glow behind it, since one per figure tinted the figures in front. - In a dark scene, paper needs a tone of its own, lighter than the night (a flat cool grey), or its writing vanishes. Dust prints as the light it floats in, never where unlit. For colour to arrive, change the shade as well as the light: knock out part of the dark and print the material's own colour. - Print versions of what a print lacks: the plates springing into register for a rack focus; two inverted frames, or one ink flashing out of register, for a hit; the plates sliding apart for panic; a split-fountain rainbow for iridescence; the plates lifting off one by one for becoming light, with the darkest shrinking away rather than rising (dark rings read as soot). ### Motion in print - The boil moves each plate by a few tenths of a pixel, re-rolled every second frame. It suits moving shots; on a still hold full of long thin lines it shimmers (12 Hz at 24 fps). A boil of 0.6 worked on moving shots and about 0.1 on still holds. - The boil, the dots and the grain sit on thresholds, so float noise in the render time flips them and splices flicker: snap render time to the frame grid (Deterministic frames). - Motion blur gives a solid partial coverage along its smear. Print coverage that changes across the shutter as a tint, so a whip smears into dots like a real print, and keep a steady partial solid (an anti-aliased edge) solid; the variance of coverage across the sub-frames tells them apart. - Along a fast camera move, let the plates slip apart, each ink offset by about 0.12 of the camera's slip in its own direction. ### Checking a print - Crop at 1:1. A downscaled preview of grain looks halftoned, so check at 1:1 before fixing a solid; two-ink fringes and beaded type show only there. Look at a 1:1 crop of the smallest type in the first style test. - On still holds, compare consecutive frames at 1:1 at the spot in question. Differences that alternate high and low mean something changes on twos. Phase correlation separates a whole-picture shift (the boil) from a local crawl (z-fighting under the outline pass). - The grain is expensive to encode (about 12 MB a second at CRF 16), so review copies need a higher CRF, and every review includes at least one clip at full resolution: compressed review copies smooth away the texture the audience will see. ## Building scenes ### The engine: shots on one clock - Build the video as an edit file of shots on one clock: a list of shots, each with an id, a start and end written against the track, the module that draws it, and its options. Values several shots share are defined once in the edit and referenced by name. - Each shot module has a small contract: an async ready() for everything slow (fonts, textures, shader compiles), a synchronous render(t), and a dispose(). - A shot with no module yet draws a card with its id, its time, the words it plays under and its description, so the edit plays against the soundtrack from the first day. A card stands only for a shot not built yet: a module that fails to load fails the render. - Keep timing and placement apart from materials, so the look can change after the timing is approved. - The film's engine worked this way: 122 shots on one clock, 3D worlds rendered in the 2D look, and 2D shots built as a camera moving over layers of flat art. - Build a preview page that plays a scene against the track with its time taken from the audio element, so a slow preview drops frames rather than drifting. Let it step by a beat as well as by a frame, and show the stems' levels at the playhead. ### Every frame is a function of time - Each scene draws frame t as a pure function of t: no wall clock, no unseeded randomness, no CSS animations or transitions. The renderer jumps between arbitrary frames in parallel tabs, and chunks and patches start partway through the video. - Draw random values from a seeded generator (mulberry32 is enough), with seeds tied to stable names: the shot, the word, the object. - Simulations step at a fixed size from a fixed start: a worker continues from its last step or re-simulates from the start, so any frame range renders identically. - Anything else that looks stateful is still a function of t. Re-run springs and follows from rest over a fixed window that ends at t, starting no earlier than the shot's first frame, so a cut doesn't kick them. Give particles closed forms from their birth time and place. Integrate anything with memory once, at build time, into a table each frame reads. - Load fonts from local files, declare every face, and wait for them before the first frame (A render fails loudly). - A subtle finishing pass (soft bloom, vignette, grain seeded by the frame number) ties scenes together. In the riso look, the print pass does this job. ### Keep approved frames from moving When many approved shots share one engine, a change must not move a finished frame. - Give each new feature its own random stream. Keep making a draw even when its value is overridden: one draw added to or dropped from a shared stream changes every shot that draws from it afterwards. - Put new features behind an option, with the old path kept. Compare stills of approved shots before and after a change: no pixel should move. - Keep snapshots of approved shared sets, and author shots in the set's own coordinates. When a set or a look changes, carry approved motion over unchanged and re-derive each camera from what it was meant to frame. - Give each effect one owner, or it applies twice (a shake from both the shot and a shared compositor). Only the shot that holds a shared character may clean it up. ### Moving the camera - Key camera moves with keyframes, and interpolate zoom in log space so scale changes read as steady travel. Give an approach or a pull-out an even change of distance (the same ratio every frame), slowing only into its landing: an in-out ease runs fast in the middle, and things near the path whip past the lens. - A move through several keys stops at each eased key and brakes where a long segment meets a short one, so run it as one smooth path through all the keys, timed by how fast the view appears to move. - In 3D, a field-of-view zoom keyed in degrees changes the picture's scale unevenly (a linear 5 to 40 degree zoom halved the picture in three frames and smeared the type): key it densely, with the scale changing by the same ratio each frame. - Key a 3D camera's heading rather than a look point near the lens, which swings the view when the next key looks far away. - When an object grows toward the lens as the camera pulls back, drive both from one curve, or the object barely grows on screen and can outrun the frame. Interpolate an approaching object's distance in log space so its size grows steadily. - Move at the head of a shot and hold at the tail. Start the move as the shot opens, let it land (settling by about 60% of the shot worked), and hold for a beat before the cut, still or creeping 2 to 3.5% a second at most: a move that runs up to the cut makes the cut feel jarring. Push into a cut only into dark or into a transition. - Nothing starts in a shot's last frames (a dart, a blink, a prop popping in); props arrive while the edit is on another shot. - Keep the camera still while the key action happens and through a burst or an impact, and let it react a few frames after. - A camera move keeps its subject readable. A close, quick move round something complex disorients; a wider, slower move (a slow orbit, a pull-out) that ends on an establishing view reads. Moving on every word doesn't make a shot clearer. - Show a new place whole before anything happens in it. - Camera motion carries through a cut or settles before it, and never reverses at it: a fast pull-out cut into a slow push-in jarred. When a new camera position reverses a movement's screen direction, show the space again in a wide. - When several shots cover one sequence in one world, animate the action once, on one clock, and make each shot a camera on it, so continuity across the cuts holds. Start the next shot's action under the current shot, out of its view, so the next shot opens in motion. Make changes the viewer shouldn't see while no shot is looking. - When a shot continues the one before (one take split by a cut, or a 2D frame that carries on in 3D), the next shot starts from exactly the outgoing shot's last frame. Settle the outgoing shot on that frame early, and build the next shot from the outgoing shot's own parameters; across engines, solve the match from the outgoing frame's measured pixels. Meet its last camera key at zero speed, match its tone as well as its geometry, and check that the frames either side of the cut differ only by grain. The camera grammar tied to the music (landings, hits, the drum layer) is in The camera and the music. ### Staging for the lens What a thing reads as depends on its size on screen and its angle to the lens. - A face carries an expression only above about 60 px tall. A prop that reads up close can read as a scratch from afar, and a small mover reads in a wide by its trail. Scale reads from repeated things receding beside things of human size. - An action along the lens axis barely changes the picture, so stage it across the frame. - Flat things (pages, cards, a label) read only face-on: turn them to the camera that reads them. A falling flat thing turns about one axis, never edge-on, and its contact shadow gathers before it lands. A fold reads as a fold only when its creases show first. - Particles read as what they resemble: white specks on a dark ground as stars, dark specks rising as soot, specks in front of bright glass as dirt on the glass. Show a mote only where light catches it, keep fields sparse, and send debris out past a word's ends, never across it. - Anything that passes near the lens by accident reads as a wall or a blot: route props and particles away from the camera, fade particles and thin structures as they near it, and keep things thrown at the lens smaller than the frame. - Plan 3D framing in numbers before rendering. Project the set's key points through the camera keys and search positions, aims and lenses against explicit limits: the subject in frame with margins, held props visible beside the body, lettering above the bottom band, nothing close to the lens. If nothing passes, move the action. Fly every camera and object path for clearance against the set and the character, in every shot and version that sees it. - Write a probe that runs a scene frame by frame and lists lettering resting in the bottom 12% of the frame, lettering over a face, a prop cut by the frame's edge, and anything too close to the lens, exiting non-zero when it lists something. Scenes register their faces, props, camera and 3D scene for it. It can see text drawn on a canvas (wrap the canvas text calls) or in the page; check lettering it can't see (built in 3D, dot or LED text, text inside images) by eye on stills that carry the band's line. - Give the probe a query mode that answers questions about the live scene at a given time (a position through the real camera, an object's state), so you query the scene before tuning anything by eye, and a variants mode that renders several values of a parameter in one page load, tiled into a labelled sheet. Before tuning a value, render an extreme one to prove the render path draws it, and prove each new engine feature in a test of one or two shots before a real shot uses it. - Then look at a contact sheet of the whole clip at full size: single stills miss a camera passing through a wall. ### Worlds and light - A world should look complete, though not cluttered. A long view is either filled with the detail viewers expect or closed off by walls, fog, buildings, a closer or downward camera, or a look that avoids fine detail. An empty ground running to a bare horizon, a grid floor (it reads as a game engine's editor) or a flat void reads as unfinished. - Close the far field in layers that grow paler and simpler with distance and take the sky's colour. Put characters in a real place from the first frame, with a few structural cues (floor seams, corners, a window set in a thick wall). Get richness from structure where the camera goes rather than from more objects. Give every set piece a reason to be where it is, and build what a reverse angle will see. - Every pool, shaft or patch of light needs a source the viewer can see, because the eye goes to what is lit and asks why. Light evenly unless a visible source motivates a pool, and keep a glow's source in frame. Drive the light from its sources, so one change (a window going dark) changes everything it lit at once. - Light a character from the camera's side so every framing shows its form: a key beside the lens and a rim from behind, set per shot, while the lamps in the set stay where they are. A back-lit character needs bounce and fill, or it reads as a dark hole inside a rim. - A drawn light reads as light only with a hot core, a soft halo and no outline, and it stays the brightest value in the frame. - A dark scene still shows the place: each plane keeps its own dark, a step apart from the next, and edges catch a little light. In the dark, whatever appears should bring its own light, since that is the change the eye reads fastest. ### Characters - Build a character from reference art by measurement, never by eye. Render the model and crop the reference over the same box, measure positions, sizes and colours as numbers, and turn each difference into a parameter correction, one change at a time. - Reference views from image models disagree with each other, so agree one canonical view with the person and match it exactly. - Once matching a near-realistic character starts, budget to finish it, or choose a stylized look from the start: near-right looks creepier than an exact match or an open stylization. When a character looks uncanny, find the specific details. On the film they included photographic eye highlights, eyes slightly too big, and a tone curve that turned a bright orange into salmon. - Judge the model and the render separately: a note on light is a render fix, and a note on shape is a geometry fix. - Build each emotion at several intensities (25 to 100%), for the face and the body together, and pick the level the moment needs. Extremes read as cartoon. Serious moments get quiet expressions, with no sweat drops, O mouths or comic poses. Emotion reads in the eyes and lids more than in the mouth. - A reaction comes about a third of a second after its cause, and a big moment gets a beat of stillness before the reaction and before the camera moves on. An emotion carries across a cut unless something on screen changes it. - A character acts toward a goal in its place rather than standing and emoting, over distances long enough to read as purposeful. Its eyes follow the action, and go to the lens on a line addressed to "you". - Keep the character alive between keys. It blinks just after a phrase ends, never mid-word or on a cut, at most about 6.5 s apart. Its eyes make small movements round a held gaze, since a fixed stare reads as dead. - Each time the character appears, they are somewhere new doing something, with one expression and one action keyed to the shot's hits, never parked in the middle of the frame smiling. A look to the lens makes a line sung to "you" land harder; check each look on a still, the frame after it lands. Hold the automatic blinks off during keyed acting: a blink inside a widening of the eyes read as a happy squint. Answer a held belt with layers (the camera flying back, giant letters on its kicks, the lyric on screen) rather than one long close-up, which reads as static. - Test every pose as a still silhouette. Limbs need space between them and the body (arms hanging against it look like a mannequin's), and identifying features go on the outline. - A crowd reads as characters when each figure has a job you can name and touches the set; figures floating at random heights read as balloons. Fewer, bigger figures near the camera read better than hundreds of small ones, which read as a texture. - Nothing the scene adds covers a character's face when it matters. Hold props low or beside the face, and route particles and flights round it. Before rendering, find anything that passes between the lens and the face and hide it for the whole shot, so nothing pops. Check props and reflections for accidental faces: two dots and a curve read as a face. ### If a character sings - Settle early whether a character sings and whose voice the vocal is. When lip-sync won't land, or the voice doesn't fit the character, treat the vocal as the character's inner voice: they don't mouth the lines in the story world, and they sing only where that makes sense and can be exactly right. - Where an animated character sings, drive the mouth from syllables measured on the vocal stem, never from loudness. Each syllable opens on its vowel (m, b and p close the lips first). A held note keeps the mouth still except for its own vibrato, taken from a pitch track (pYIN from 110 to 900 Hz in 10 ms steps, in semitones). A belt shuts the eyes and holds the mouth open for the whole note, across a cut if the note runs on. - Lip-sync driven by loudness failed most visibly by moving the mouth through held notes. ### Words in a 3D world - Words in a 3D world face the camera that reads them. Turn or tip the surface toward the lens, check the text direction on every face that can be seen (a far side reads mirrored), and hold the word still while it is read. - Size a word for the farthest camera that sees it, and its texture for the closest. Text moving past the camera needs to be big (about 100 px tall), few and slow, with a short shutter. Small text that must be read goes on a big card near the lens, or into 2D. - Lay text out through the final camera so occluders (a figure, window bars, a railing) fall between words, never through a letter. Nothing covers a word at the moment it must be read; at other moments a word may be partly hidden, but only while the viewer can hear it. - 3D text needs real kerning and placement bound to the ink. opentype.js 1.3 ignores kerning stored in GPOS extension lookups, so read the pair tables directly. ### Craft for every shot - Beautiful and legible over merely impressive. Pick objects and imagery with an obvious meaning tied to the line and the palette. A raymarched fractal was technically impressive but "weird and kind of ugly"; a flower blooming out of a box read immediately. - Restraint. Many small, bright, multicoloured things at equal contrast read as confetti and are painful to look at: keep two or three colours dominant, put colour in blocks, order repeats into rows and grids, and give each frame one bright place (one small flash for a run of events, rather than one per event). The eye goes to the brightest, warmest thing and takes whatever fills the middle as the subject, so put the subject there and push competing structure to the edges. Stage what moves or must be read against the calmest part of the frame: a change reads only where nothing else is happening (fill an empty shelf rather than scatter arrivals over a full wall). - Show each stage of a physical action in turn: where it comes from, where it is going (the destination appears just before it arrives), the contact on its cue, and what it brings, starting at the contact point. A change the story depends on is complete and shown on the thing that changes. A reaction comes after its cause is on screen; when the cause is in the next shot, play anticipation. - One transition per handoff. If an object flies into the lens, the object itself is the transition: its surface fills the frame, the cut happens underneath, then it clears. A colour cover plus an iris wipe on top of the same hit read as two transitions overlapping. A mostly blank surface (a card, a page) that fills the frame reads as an empty frame, so darken it as it comes. - Handoffs that worked: push the camera through an object (into the glass); morph one scene's shape into the next scene's object; let an interface become the world instead of cutting away from it (a list of chats pouring out into a mountain); carry one element across the cut while its world falls away, handing it to its twin at the same screen position on both sides (pasted text drops out of a chat window and lands as a page in the next scene); carry a fall or a push straight into the next shot's motion; cross-dissolve where elements line up; or dip through black for four to six frames between unrelated scenes. A moment too short to show on its own can become such a handoff. - When one form hands over to another (a page to particles, 2D to 3D, one line of words to the next), bring both to the same state first, then swap: each particle starts at its patch's place, size and average colour. - A thing that leaves reads best dissolving into its own dots, each whole for the first third of its life and gone within about 0.4 s. Shorter lives blink out, and longer ones leave a haze over the next action. - A reveal needs contrast between what opens and what is behind it: a pale page torn open onto pale paper can't be read. - A recreated app or web screen is there to be recognised, not read: show where it is (its title, the app) and the one line that matters, pushed in, highlighted or zoomed until that line dominates, with the rest cropped away or dimmed. - Invented names and marks must not pass for real ones. Give an invented company no web address that could exist (show a link by its page title), and check that an invented icon doesn't resemble a real brand's logo (one read as Instagram's and was redrawn). Show a made-up source by what happens to it (its link breaks, or its page flips to "Page not found"), which reads faster than a misprint. Credit anyone else's work shown in the video, on screen and in the post. ### Motion and motion blur - Ease every move. From the LottieFiles motion-design skill, these worked: entering cubic-bezier(0.05, 0.7, 0.1, 1), leaving (0.3, 0, 1, 1), moving on screen (0.2, 0, 0, 1), ambient (0.4, 0, 0.2, 1); an overshoot of 3 to 5% only for light things such as paper; staggers under 0.5 s; and primary, secondary and ambient motion in each scene. Something leaving keeps its speed past the frame's edge instead of easing to a stop the viewer never sees. - An event keyed to a cue (a word, a hit) reads on the cue's frame. Key the moment the viewer reads as the event, which can fall mid-flight (a page crossing a pane of glass). Arrivals land still moving, on a gentle ease-out or a 60 to 70 ms snap; an overshooting ease shows the landing early and jiggles after it. The cause leads by a frame or two (an expo-eased snap started 1 to 2 frames early lands on the word), and the effect starts on the cue, with nothing moving before it. - A big move that starts on its cue shows about a sixth of its travel on that frame (an ease-out over about 0.75 s): a faster snap blurs to an empty frame, and an ease-in-out sits still after the cue. A burst or a spreading wave shows its change on the cue's frame, and what it touches reacts in order of distance (about 20 ms a metre), so the reaction reads as caused. - Motion blur averages sub-frames spread across a shutter of about half a frame. On a 2D canvas, sum them with the "lighter" composite mode at alpha 1/n + 0.002, so a still solid sums to full strength. Take the sub-frame count from the fastest thing on screen, as well as the camera: about one sub-frame per 5 px it travels in a frame at 1080p, up to 16 to 20 (3 to 4 sub-frames printed a fast whip as 3 to 4 ghosts; 10 to 12 made one smear). Keep one count through a whole move: switching mid-move makes one frame sharp and the next smeared. - The frame grid: anything that should change at an instant (a counter's digits, a state flip, a jolt or a camera shake, a landing, an element popping in) changes on a whole frame, keyed to the frame's own time rather than each sub-frame's, so all of a frame's sub-frames fall before it or after it. Otherwise the blur prints it twice. Round clocks and counters to the frame before drawing (Math.round(t * fps) / fps), or the blur smears their digits. - Keep the camera slow over fine detail, which blur averages into mush. Draw small bright particles with no shutter, stretched along their screen velocity. Give shots that carry words or line art a short shutter or none, and sell speed with a drawn stretch on the in-between frame. Never leave a smear as the only thing on screen for more than a few frames: a thing in flight keeps its shape and colour readable. ### Colour, fine detail and WebGL - Keep designed colours through a 3D render: render in linear light and develop once at the end, with a curve that leaves values below about 0.68 alone and rolls off above. Neutral and ACES tone mapping turned a bright orange salmon. Pass flat designed colours placed in the scene through that curve's inverse, give screens and glowing faces their own exposure (divide their brightness by the shot's exposure), clamp highlights before bloom, and make perceptual changes such as an invert in display space rather than linear space. - Draw nothing finer than a pixel. Filter procedural patterns by their size on screen and fade them to their average as they shrink; keep lines at least about 1 px and points 1.5 to 2 px wide, fading them by what was lost; set a pattern's pitch from the shot's camera distance; and keep fine detail near the camera. Make two regular grids on screen whole multiples of each other, or they moire. Size each texture for the tightest framing that uses it. Hard SDF intersections alias (round the edges), and fine repeating patterns read as pleats. - WebGL works in headless Chrome on the GPU. Split heavy shaders into tiles per draw to stay under the GPU watchdog, and accumulate several jittered or sub-frame samples for anti-aliasing and motion blur. Chrome keeps about 16 WebGL contexts per page and silently drops the oldest, which can be the scene's own renderer: share one renderer, draw many views with one offscreen renderer copied into 2D canvases, and release a context once its output is baked into a texture. Compile the shaders before the first frame (renderer.compile in three.js), or the first frame is the slow one. - Measure layout at render time (getBoundingClientRect) instead of hand-placing annotations, and measure text at the pixel size it prints: fonts with optical sizes change width with size (a word in DM Sans ran up to 13% wider per em at 17 px than at 60 px). Lay out a whole line once, draw it as one string so the font spaces and kerns it, and reveal its words or letters at their laid-out places, so nothing shifts as later words arrive. Give layered elements an explicit z-index. ### Pitfalls that broke frames without an error - Object spreads that overwrite fields: {t, ...bbox} replaced a cue time with a box's top edge, and {slant: undefined} replaced a default and drew NaN strokes. Build option objects from defined values only. - Geometry moved in a vertex shader is culled by its resting bounds: turn culling off or grow the bounds. - Extra passes (shadows, outlines, occluders) must run the same deformation and discards as the main render, or a dissolved part keeps its shadow. - An injected shader hook must not return early when the outputs are written at the end of main, must not reuse the material's uniform names, and needs its own program cache key for each variant. - In canvas, lineWidth = 0 is ignored, and an anticlockwise full ellipse runs from 0 to -2 * Math.PI. Wrap an angle difference into -180 to 180 degrees before easing a heading. ### Flicker - Flicker reads as a mistake. Faces of separate objects never share a plane: keep them 1 to 2 cm apart, and lift decals with a polygon offset, since an outline pass turns z-fighting into crawling bands. - Set the near plane as far out as the shot allows: a 24-bit depth buffer resolves only about (z times z) / (near times 16,777,216) at distance z. - Anything switched by a threshold (an outline, a level of detail, fog) fades through it rather than popping. - To find a flicker the person reports, crop the exact spot they point at and compare consecutive frames at 1:1. A measurement over the whole frame can blame the wrong cause, such as the look's own texture instead of two faces fighting in one small spot. ### Parallel agents - The lead session designs every shot and owns the shared engine, the edits, the assembly and the review pages. Agents build engines, worlds and sets, and own only the files they create. - Run few workstreams, and take each shot to its best version before the next: many agents on many sections leave nothing finished. - Anything several agents' shots show (a set, a prop, a palette) has one definition, built once by its owner. Otherwise each agent builds its own: four agents once built four different windows for one room. - Work through the owner: ask for a hook instead of patching around shared code, extend a module with options whose defaults reproduce it exactly, and read a neighbour's published data on every build instead of copying its numbers. Hand ownership over explicitly when an agent finishes. - Brief each agent with the shared grid (the clock, each shot's window and the events it must land on), the standing rules and what not to touch. Check the brief against those rules before sending it: a test that breaks a rule proves a shot the video can't use. On every change of direction, pause the running agents and resume each with a new brief. - Start a new world or look with style frames, judged before shots are built in it. - An agent hands back a test edit, its render, a contact sheet, a note of what is still rough and an exact merge list. The lead looks at the sheet, merges, runs the checks, and tracks each merge list as a task until it is in the render. - Shared modules do nothing when imported, and shared data lives in a module that imports nothing, so there are no import cycles. Only the owner changes the shared engine, and during production a change goes in behind an option that is off by default. - Patch shared files by exact anchors that must each match once, so a stale patch stops instead of undoing another agent's work. - While the final chunks render, lock the shared modules and queue the agents' requests. Never leave a shared module half-edited while any render runs: a module loaded later in the render picks up the edit. ## The camera and the music ### Every action on a musical event - Key every visible action to an event measured on the stems (a kick or snare, an instrument's onset or note, a sung syllable). An even beat grid or a rough time puts actions where nothing plays, and they read as a clock. - Let an action's consequences take the hits that follow: a plug seats on one hit, and the power arrives on the next two. - Give each moving element one layer of the music, and put the biggest event on the shot's strongest hit. In an instrumental stretch, cut and animate on the lead instrument's onsets. - Draw a gesture at the start of a held note and move the camera in the gap after it. Land a payoff on a hit and hold it before the cut. - Idle and repeating motion is the exception: lock it to the bars and beats (a breath per bar, a cursor blinking on the beat). - End on the stem's last events (the final chord and its release), never on the length of the file. - In a sparse, exposed passage (a solo piano intro), give each note a visible answer from its per-note data: light notes get small gestures and deep notes big moves. Pitch can set height, and the music's groupings can become the image's. Let each answer linger, with an afterglow of about 3 s, so the picture builds: answers that vanished with their notes left an empty field. ### Builds, reveals and flows - Build on the hits, one readable change per hit, each done before the next. Pieces unroll along the structure's own path and lock on the beat with a small flare. Pieces flying in read badly. A drum fill gets one step per stroke. - A big reveal spreads outward from one point on the biggest hit, slowly near that point so it can be followed. - A continuous flow runs on a clock that jumps ahead a little on each note, so it never runs backwards. - Things that carry words move on some notes and hold between them, so they can be read. - A transformation goes in recognisable waves on the words or the band's drop-outs, never as a plain fade. - Versions of a passage are each keyed to their own notes. Combine them by rebuilding one piece, re-timed to the notes each part now covers, never by splicing their frames: a spliced part keeps its actions on the notes it was made for. ### A shot lands moving Adapted from mexicat/pdoom-video, a code-rendered music video whose code is public: - A shot lands already moving: it opens punched in and tilted, and springs to rest with a small overshoot in about half a second. The reference video used about 12 to 16% and 3 to 5 degrees; the film's 2D shots were gentler (mostly about 5% and about 1 degree), and few of its 3D shots used a landing at all. Never cut to a dead-still frame on a hit. - Snaps run 0.15 to 0.3 s on a strong ease-out (outExpo, 1 - Math.pow(2, -10 * x)) and land on their syllable or hit, and a shot's move settles before its cut. Inside one location, snap or cut to a fresh framing on the beat, so the energy comes from the camera rather than new sets. - On a vocal, give each key sung word its own framing, and put big reframes and whips inside held notes, landing on the next word's first syllable: a whip on a belted word hid it for most of the note. ### Hits that jolt the frame - The frame reacts to a big hit: it jumps on the hit (displaced, tilted, punched in) with nothing before it, springs back past rest, and shakes briefly. The review note behind this: "camera shake and some intentional jerks will do a lot to help these moments land". - Sizes that worked at 1080p, in units of 1/9 of the frame height (120 px): about 0.04 to 0.06 for a syllable, 0.08 to 0.13 for a landing, and 0.17 to 0.25 for a shot's one signature hit, with half-lives of 0.04 to 0.12 s. - Alternate the tilt's side on consecutive hits, let a belted note rumble while it's held, and invert the colours for two frames on the single biggest hit. - How strong depends on the genre and the brief: this film's director wanted it "pretty wild", and a promo usually wants less. ### The drum layer The drum layer puts the measured hits under the camera's moves. It is on by default in a music video (set it per shot: the film switched it off in about a third of the shots once the drums played, mostly holds and quiet stretches), and an option in other videos cut to music when the brief asks for energy. - Kicks of strength 0.5 or more punch the zoom about 1.4%, decaying with a half-life of 85 ms. - Snares of strength 0.85 or more jolt the frame lightly, in proportion to their strength. - Hats of strength 0.6 or more shimmer the zoom about 0.35%, with a half-life of 45 ms. - Apply it in exactly one place: a shot's own camera and a compositor both adding it played every hit twice. - Fade it out over a shot's last 0.25 s, so no hit jolts the frames before a cut. - Set it per shot: off for holds, turned down for a whispered word, off where a word or label must land sharp. ### Building the camera-effects module Write one module, used by 2D canvas, HTML and three.js scenes alike, that returns offsets added to a shot's own camera: - Units: x and y in units of 1/9 of the frame height (120 px at 1080p, at zoom 1), with y up; rotation in radians; zoom as a fraction (0.05 is 5% closer). Sum offsets into a view whose zoom is a factor: add the x, y and rotation offsets, and multiply the zoom by (1 + each offset's zoom). - Two springs do most of the work: ```js // a damped spring's response to a step at t0: 0 rising to 1, with overshoot function spring(t, t0, freq, damp) { const x = t - t0; if (x <= 0) return 0; const w = 2 * Math.PI * freq, wd = w * Math.sqrt(1 - damp * damp); return 1 - Math.exp(-damp * w * x) * (Math.cos(wd * x) + (damp * w / wd) * Math.sin(wd * x)); } // a step that leaves already moving (a snap): (3.6 Hz, 0.74) overshoots about 5%, (3 Hz, 0.42) about 26% function springStep(dt, freq, damp) { if (dt <= 0) return 0; const w = 2 * Math.PI * freq; return 1 - Math.exp(-damp * w * dt) * Math.cos(w * Math.sqrt(1 - damp * damp) * dt); } ``` - settle: the shot holds a displaced frame (zoom 0.12 and rotation 0.05 by default) and springs to rest from a time you give: the offset times (1 - spring) at 1.3 Hz with damping 0.7. - hits: each is a jolt plus a shake. The jolt starts on the hit with nothing before it: the offset times (1 - springStep). Three presets, each listed as jolt (y, rotation, zoom, spring frequency, damping) and shake (amplitude, rotation, frequency, half-life): - slam: jolt (-0.45, 0.07, 0.16, 3.0 Hz, 0.38); shake (0.22, 0.028, 14 Hz, 0.10 s). - word: jolt (-0.16, 0.025, 0.05, 3.6 Hz, 0.42); shake (0.08, 0.01, 14 Hz, 0.06 s). - tap: jolt (-0.07, 0.01, 0.02, 4 Hz, 0.5); shake (0.035, 0.004, 12 Hz, 0.05 s). - Each hit also pushes x by 0.12 toward a side that alternates between hits, and tilts toward that side. A per-hit scale multiplies the whole hit. - shake: smooth value noise (a hashed value per integer step, smoothstep between steps) on x, y and rotation, decaying from the hit. - rumble, for a held note or belt: noise of amplitude 0.06 and rotation 0.008 at 16 Hz for as long as the note is held, easing in over 0.08 s and out over 0.15 s. - drift, a hand on the camera: slow noise of amplitude 0.04 and rotation 0.004 at speed 0.35. - music, the drum layer: zoom plus 0.014 times the sum of recent kick strengths of 0.5 or more (each halving every 0.085 s), plus 0.0035 times the sum of recent hat strengths of 0.6 or more (each halving every 0.045 s), plus a tap hit scaled by 1.7 times the strength for each snare of strength 0.85 or more. Multiply the layer by a smoothstep fade over the shot's last 0.25 s. The drum-hits file gets an offset: where the track starts on the video's clock. - Adapters: a 2D canvas transform about the frame's centre (translate to the centre, scale by the zoom, rotate by minus the rotation, translate by minus x and plus y times the unit of H / 9 pixels, translate back); a CSS transform for an element covering the frame; and, for a three.js perspective camera after its lookAt, turn the lens by (field of view / 9) per unit of x and y, roll it by the rotation, and narrow the field of view by the zoom (new fov = 2 * atan(tan(fov / 2) / zoom)). The 2D and 3D shots then hit alike. - Gate hits to whole frames: decide whether a hit has begun from the frame's own time (Math.round(t * fps) / fps), never each motion-blur sub-frame's time, so every sub-frame of a frame agrees. A hit landing inside one frame's shutter otherwise prints as a double image. - Throw on anything malformed: a drum-hits file in another shape, a strength outside 0 to 1, times going backwards, the drum layer asked for without drums, an unknown setting. ## Lyrics and type ### Lyrics on screen - Unless the brief says otherwise, put lyrics on screen as often as they can be part of the world and done creatively, and never let lyrics be the only thing on screen. Words placed in the world make a line land harder, and it is hard to overdo. - No sung word is readable before it is sung. That covers all text in the picture that quotes the song: a typed or sent message, a prop, a line in a document, a name the song hasn't sung yet. A chat message that showed a lyric 1.3 s early gave the word away. - Each word lands on its first syllable, readable on that frame rather than after an entrance animation. A word that splits lands part by part ("ANY" on "an", "THING" on "thing"), and typing advances syllable by syllable. - Before its syllable a word may be on its way only in a form that can't be read (edge-on, a dim placeholder), for about 0.4 s at most. Round a reveal's frame up, so it never shows a frame early. - A line lettered as one block waits until all its words are sung. - Show each lyric word once. A message shown being typed and then again in the conversation is the same words twice: pick one. A word sung just before a cut is already in place on the next shot's first frame. - A line that arrives word by word with the vocal reads like captions, so it needs little time after its last word: lines held 0.6 to 1.1 s after their last word read well. - When the track garbles a sung line (generated vocals can carry artifacts), put the line's words on screen as part of what is shown, each on its syllable and as the shot's biggest type, and leave the last word time to be read before the cut. - When a line has to land and its literal picture won't, set its words in big type in the video's own style, struck on the beat (Type on the beat). - The cut check flags typed or streamed text that quotes the song early. Check other text in a scene (paper, props, signs) on frames. ### Placing lyrics in the world - Put lyrics on things the shot already shows: a window's panes, book spines, chat titles, a page's headline, a chart line that writes the words as it climbs. Size them to the set so the whole line fits the frame, and clear other lettering while the lyric is up. - A lyric may be partly hidden, since the viewer hears it, but nothing may cut a word into pieces that read as other words: put anything in front of a lyric between its words, never across a letter. - Give each lyric moment its own staging, vary neighbouring ones, and drop any staging viewers can't follow: word cards orbiting a character drew "What are these signs?" - Keep one typeface for lyrics across the video, with other voices (an interface, a character's handwriting) in their own faces, and craft the type for its shot: generic slammed type looks cheap. ### Type on the beat - Strike one word per hit, as the most legible thing in its frame, and let the camera settle before the next word. - A slammed word scales from about 1.12 times its size (1.35 for a stressed or belted word) to full size in 0.16 s on outExpo, then creeps toward the lens so a held word stays alive. An opaque halo lets it read over any picture. - Lay type out per shot in the shot's empty space, clear of the subject. Size words by meaning (a function word about 0.6 the height of the content words), and vary the layout of consecutive type shots. A hook can put one word per hit, filling the frame, with the palette flipping between words. - Kinetic words keep one grammar through a shot: one word standing at a time, or the line building in place. Lay the words out before staging the shot: big words take the part of the frame they cover, so the subject and anything else that must read go in the outer thirds. Reveal in the order the eye reads the frame as the camera sees it (left to right, top to bottom; a stack filled from the bottom reads upward). - Kinetic words that follow the voice enter one at a time: the next starts once the previous one has landed, and a word that follows within 0.1 s pops in. Text being read holds still, and so does the camera on it: a camera that follows typing eases each step over the time to the next keystroke. ### Legible type - Text that must be read at a glance is solid, in the plainest high-contrast ink (dark on a light ground, light on a dark one), never a tint. Colour is for marks such as an underline: a meaning carried by a text colour goes unnoticed and just looks like a mistake. - Over a busy ground give type a soft halo, and add a thin dark keyline where the ground turns as bright as the type; light or glowing words need a dark ground. Check type and thin shapes against their ground in every lighting state of the shot. A rectangle behind type reads as a text selection; use a soft round shape. - A settled frame never cuts a word or a key shape: keep them whole, with a margin from all four edges and clear of each other, since an edge crop can change a word ("they" half off the edge reads "hey"), and tangents and overlaps at a hold read as mistakes. A frame in motion may cross words. On a screen or a document, put each rest frame's edges in the layout's text-free bands (between a header and a divider, between cards or rows), with a margin: a settle that starts about 5% tighter cuts a line that only just fits. - Sizes at 1080p for a phone: titles at least 48 px, body at least 24 px, labels at least 18 px; 17 px mono labels were too small. Check every scene at 480 px wide, and the smallest type at 1:1 in the encoded file. ### Keep words out of the bottom 12% - In a 16:9 frame, nothing meant to be read rests in the bottom 12% of the height: text that low is hard to see, and just above the line is enough. Lettering that only crosses the band during a move doesn't count. - Fix an offender with a slightly lower aim or a slightly wider frame, never by moving its timing. ### Text while the vocal sings - Viewers can't read and listen at the same time. While the vocal sings, text on screen is either short (a label, a name, a number, a key word) or the words being sung. Never put a passage on screen that says something other than the words. - Context the song doesn't carry belongs in the post's copy, off the screen. ## Cutting ### Where to cut - Cut on musical events: a beat or the half-beat between beats, a section's first downbeat, the end of a sung phrase, an instrument coming in or dropping out, or a strong drum hit. - Never cut inside a sung phrase that carries a moment: let the shot run the whole line. Inside a line, cut on a beat in a vocal gap once its words are whole, or on a big hit inside a held note. Two shots with the same camera, light and state play as one take, so such a cut can stay invisible. - A full-frame layer (type or a graphic over the shots) snaps to the cut frames, so it never leaves a sliver of the shot beneath at a cut. If it would start within about 0.3 s after a cut, start it on the cut; if it would end within about 0.45 s before a cut, extend it to the cut. A cut that falls inside a full-frame layer is hidden under its most opaque moment. ### How long shots run - Cutting to music tends to produce more cuts than viewers can take in: one music video's first cut had more than half its opening shots under a second and was hard to follow. Count the shots under a second before showing a cut. - A quick run needs simple images, or similar ones, so there is little new to take in. Get the energy from camera moves, the drum layer and type rather than from the cut rate, and plan a fast split on the measured hits, never on even lengths. - Inside fast runs, a piece with one bold image and one short word was readable in about 0.2 to 0.25 s, and each piece carried one change; most of the film's fast pieces ran about 0.45 to 0.66 s, and no shot was shorter than 0.5 s. These are examples of what worked rather than minimum lengths. - Outside fast runs: an image the viewer has to take in holds about 2 s or more; a graphic holds at least 1.5 s after its last element settles, longer when it carries words (about 0.25 s per word on screen plus 0.5 s); a showpiece runs about 3 s. - Avoid long static holds: let a hold creep, or push in from an instrument's entrance to the key word. Save real holds for the moments that earn them. ### Heads, tails and holds - Never cut while something is still moving into place (typing, a falling page, a dissolve) or as the last letter of text to be read appears: such cuts look like mistakes. When the slot is short, take the time from the head (bring the element in earlier, or open with the action already under way when the context shows what happened), shorten the animation, or take the time from a weaker neighbouring shot, never from the tail. - Write a check that lists the cuts where the outgoing shot is still moving, with a crop of where (from the difference between its last frames), and the cuts that fall inside an animation a scene declares, at its worst-case timing. Mark a move meant to carry across a cut so the check skips it. A camera that drifts through every shot gets most of its cuts flagged: judge those by the crops (a drift lights every edge, a move one place). - Never stack a second transition on one that already hands over (a cover or a wipe on top of a whip): it reads as two transitions. ### Checking sync - After every change to the edit or the timing file, run a cut check that flags cuts more than a frame from a musical event, gaps and overlaps between shots, shots over a length limit you set (unless marked as holds), and on-screen text that quotes the song before it is sung. - Label contact sheets with the song time and the last word sung. - Preview against the track with the time taken from the audio element, stepping by beats as well as frames. ## Rendering ### The renderer Write a renderer in Node that drives headless Chrome with Puppeteer: - Serve the project folder over local HTTP (correct MIME types, no caching, nothing outside the served folders), and open the scene in several tabs (six worked), each rendering its own contiguous slice of the frame range. - Launch Chrome with the sRGB colour profile forced, GPU rasterization on, the GPU blocklist ignored, background timer throttling and renderer backgrounding off, scrollbars hidden, audio muted and font hinting off. On Windows, ANGLE on Direct3D 11 gives fast WebGL in headless mode. Set the viewport to the frame size. A device scale factor of 2 renders at double size for cleaner dots and edges, downsampled with lanczos in the encode; a canvas scene must size its backing store by devicePixelRatio for this to help. - The page contract: window.renderFrame(t) is async and draws frame t as a pure function of t; window.sceneReady becomes true once the scene can render; failures go into the array window.sceneFailures; window.frameMeta, if set after a frame, is saved with it. - For each frame: call renderFrame(f / fps), check the failures, capture the screenshot through the Chrome DevTools Protocol (Page.captureScreenshot, PNG, from the surface), and write it as a PNG named by its absolute frame index (00000.png, 00001.png and so on). - Write a manifest beside the frames (frame rate, size, scale, alpha, scene, query) and refuse to mix frame rates or sizes in one folder. - Give it a resume mode that renders only the frames missing or broken after a crash, and a check mode that verifies a folder without rendering. - In Git Bash on Windows, write URL paths such as work/index.html without a leading slash, or the shell turns them into Windows paths and the page never loads. ### Deterministic frames - A frame's time comes from its integer index: frame f is time f / fps on the track's clock, plus a fixed offset when the picture starts elsewhere on the track. - Snap that time to a fine grid before anything uses it: 16 steps a frame (1/384 s at 24 fps, 1/480 s at 30). A floor, threshold or hash on time turns a difference of 1e-7 s into changed pixels, and a spliced seam then flickers. Make window.renderFrame an accessor property that wraps whatever function the page assigns with the snap, so a renderFrame the page sets itself is snapped too: ```js const GRID = fps * 16; const snap = function (t) { return Math.round(t * GRID) / GRID; }; let inner = async function (t) {}; Object.defineProperty(window, "renderFrame", { configurable: true, get() { const fn = inner; return function (t) { return fn(snap(t)); }; }, set(fn) { inner = fn; }, }); ``` - Start every test, patch and chunk on the frame grid: a shot that starts at t0 first shows at ceil(t0 * fps) / fps, so test it from that frame. - To check that a scene is deterministic, render one frame from two different start points and compare them pixel for pixel. ### A render fails loudly - A scene that fails to load, a library or font that doesn't arrive, a page error (an uncaught exception or a rejected promise), an HTTP error or failed request for any page resource, or a failure the scene reports stops the render with a non-zero exit and a clear message. Nothing draws a stand-in in its place. - A request for a file that may be missing on purpose carries a marker in its query (optional=1) so the renderer lets it pass. - Load every library and font from local files. A scene lists the font faces it draws with, and its setup fails if document.fonts doesn't settle within 15 s, or a listed face doesn't load, matches no declared face, or isn't available after loading (document.fonts.check). A system font differs between machines, so declare every face from a local file. - A page that isn't ready after two attempts fails the render; the one retry covers a transient load failure. - A render isn't done until every frame in its range is written. At the end, verify each PNG's signature, its size against the expected frame size, and its closing IEND chunk. - Render from a frozen copy of the edit (or the scene files) and record what each render used, so you can tell which renders a later change made stale; stop a render that a change has made obsolete. After the final render, revert experiments from a backup or a diff, never from memory, so the code still makes the master. - To stop a render, stop its own Node process. Never kill chrome.exe by name: it closes the person's own browser and other agents' renders. ### Rendering in chunks and joining them Render a long video in chunks whose edges fall on cuts. Write a chunk tool with five commands: - plan: chunk edges at cut frames, so no chunk starts inside a shot. Take them from section starts or given times (each snapped to the nearest cut, and refused when none is within about 3 s), from a length in seconds, or exactly at given shots' first frames. - render: render each chunk into its own frame folder (kept for splicing), encode it video-only with the BT.709 encode below, check its decoded frame count, and save what it used: its shots, the edit's other settings, the render settings, and hashes of the code and data files the scenes read. - status: compare each chunk's record with the edit and files now, and say which chunks are missing, current or changed, and what changed. - join: concatenate the chunks' video streams with ffmpeg's concat demuxer, giving each chunk an explicit duration, then lay the whole soundtrack under the joined picture once. Strip any chunk's own audio first: a chunk's audio running a hair past its picture made the concat demuxer drop a frame at a seam. Refuse missing chunks, and changed ones unless told to go ahead. - qa: check the decoded frame count against the plan; every seam (the film's first and last frame of each chunk against the chunk's own, with a mean grey difference under 1.0 at 320 px wide); the BT.709 tags; runs of flat frames (grey standard deviation under 4, listed with their times and shots to judge as intended or not); the soundtrack's offset against the source by cross-correlation at four points (3 s of mono audio at 8 kHz each, failing beyond 5 ms or below 0.9 correlation); and the loudness and true peak of the film beside the source. A chunk's encode, with frames named by absolute index (this one starts at frame 1476 and runs 804 frames): ``` ffmpeg -framerate 24 -start_number 1476 -i frames/c02/%05d.png -frames:v 804 -c:v libx264 -preset slow -crf 16 -vf "scale=out_color_matrix=bt709:out_range=tv,format=yuv420p,setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=tv" -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -movflags +faststart c02.mp4 ``` The join list (join.txt), one entry per chunk with its exact duration in frames divided by the frame rate: ``` file 'c01.mp4' duration 61.500000 file 'c02.mp4' duration 33.500000 ``` Stripping a chunk's audio, then the join with the soundtrack laid once: ``` ffmpeg -i c01_with_audio.mp4 -map 0:v:0 -c copy c01.mp4 ffmpeg -f concat -safe 0 -i join.txt -ss 0 -t 288.041667 -i song_gain.wav -map 0:v:0 -map 1:a:0 -c:v copy -c:a aac -b:a 320k -ar 48000 -shortest -movflags +faststart film.mp4 ``` The -ss value is the track's time at the picture's frame 0. The soundtrack is cut one frame longer than the picture (4:48 at 24 fps is 6,912 frames, or 288 s, and 6,913 frames is 288.041667 s) so -shortest keeps the last frame. ### Re-rendering a stretch: splice by frame index - To change a stretch, render it again in context, with the shots on either side included so a whip or dissolve across the seam is real, starting on the frame grid a frame or two before the change, into its own folder. - Then lay its frames over the old render's by frame index into a new output. Write a splice tool that leaves the old frames untouched, refuses a patch that is off the grid or would leave a gap, applies patches in order (a later one wins where two overlap), and reports which frames changed and whether each patch's first and last frames match the old ones. A mismatch there is a visible jump at the seam. When it writes a frames folder, it copies frames and never links them: rendering into a folder of links writes through them into the base. - After a crash, fix the cause and render only the rest. ### The encode: BT.709 and the last frame Frames rendered as RGB images are encoded with the BT.709 matrix and tagged BT.709. Without out_color_matrix, the conversion from RGB uses BT.601 and the colours shift; without setparams, the primaries and transfer are left untagged, and untagged video shifts colour on phones. A file encoded from frames with only -pix_fmt yuv420p (ffmpeg's default route) carries BT.601 colours and no tags. The full encode in one pass, for a render that isn't chunked: ``` ffmpeg -framerate 24 -start_number 0 -i frames/%05d.png -ss 0 -t 288.041667 -i song_gain.wav -frames:v 6912 -map 0:v:0 -map 1:a:0 -c:v libx264 -preset slow -crf 16 -vf "scale=out_color_matrix=bt709:out_range=tv,format=yuv420p,setparams=color_primaries=bt709:color_trc=bt709:colorspace=bt709:range=tv" -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -c:a aac -b:a 256k -ar 48000 -shortest -movflags +faststart final.mp4 ``` - Every encode made from rendered frames uses this conversion and these tags, including your own helpers: a renderer's mux, a splice, a chunk, a review clip encoded from frames. A copy or a join made from tagged video keeps the tags; a join of untagged chunks stays untagged. - For frames rendered at device scale 2, put the downsample first in the filter: scale=1920:1080:flags=lanczos:out_color_matrix=bt709:out_range=tv, then the rest as above. - -shortest drops the last frame when the audio is even a fraction of a frame shorter than the picture. When the audio is a stretch of a longer soundtrack, cut it a frame long (-ss and -t before its -i, as above), cap the picture with -frames:v, and count the frames afterwards. Check every deliverable before it goes out: ``` ffprobe -v error -count_frames -select_streams v:0 -show_entries stream=nb_read_frames,color_space,color_primaries,color_transfer,color_range -of json final.mp4 ffmpeg -v error -i final.mp4 -f null - ffmpeg -nostats -hide_banner -i final.mp4 -vn -af ebur128=peak=true -f null - ``` The first must report the expected frame count and bt709, bt709, bt709, tv. The second is a full decode and prints nothing when the file is sound. The third prints the integrated loudness and the true peak (Sound and delivery). ### Speed, disk and one GPU - Heavy looks render slowly. With one page rendering at a time, the film's scenes through the print pass, 3D and 2D alike, ran at about 1.1 to 1.8 frames a second (2D interface scenes rendered before the print look ran at about 6), and the 4:48 film took 87 minutes in eight chunks, about 1.33 frames a second. The screenshot set the pace more than the drawing: a frame drawn in about 30 ms took 0.4 s with its capture. - Queue headless renders and run one at a time where you can: renders that share a GPU slow each other down and fail. When a check of whether the GPU is free fails, count it as busy. With several agents on one GPU, test renders waiting for the GPU cost more time than the frames themselves. - Keep one local server that no agent restarts, since a restart kills the renders using it. Give each agent's scratch files its own prefix, so no agent overwrites a script another is running. Retry a frame that comes out blank: with agents editing files, a page can load one half-written. - Frame folders fill a drive fast: the film's frames, kept from every render, passed 300 GB. Once a frame folder's clip is encoded and checked and a newer render has replaced it, delete the folder; the code can render any frame again. ## Checking ### What to look at - Contact sheets around every cut and transition and through every scene, at full size; the first and last frames of every graphic; consecutive frames through every fast move. Write a sheet tool that tiles a frame folder between two times, every n frames, and labels each tile with its shot, the song time and the last word sung. - Text at phone size, and the smallest type at 1:1 in the encoded file. - Ask of every element what a viewer would take it for, at the size it appears and in the moment's tone, and redraw or remove anything that could look unintentional: a green chevron on a comparison card read as a check mark endorsing a competitor. - Check each shot's written description against its frames. A description is a claim, and described beats often never show: make the beat read or take it out. - When the look has fine texture (grain, halftone, fine patterns), include at least one clip at full resolution in every review. ### What to measure - The cut check after every change to the edit or the timing file, and the count of shots under a second. - The probe on every shot with a moving camera or 3D, and the check for cuts made while something still moves. - Frame differences wherever something should hold still. - Determinism: one frame rendered from two start points. - The seams after any partial render or splice. - Frame counts, colour tags, a full decode, and loudness and true peak, all on the encoded file. ### Before the person watches - Judge a piece ready yourself before asking for its review: the person shouldn't be the one catching technical slips. - Confirm that every render is newer than the last change to the code and text it uses, and that the edit points at the newest version of each shot. - Have a fresh-eyes pass, by a reviewer agent where there is one, check the stretch against the standing rules and list the fixes that matter most, each with an owner, and what to protect. - A card belongs only where a shot isn't built yet; a card where a built shot belongs means the shot failed to load. ## Working with a director Shot-by-shot direction is a choice the person makes at the start. Without it, build end to end and deliver. With it, run the production in review rounds, as "Don't Close the Tab" was made. ### Agree the rounds - Agree the rounds at the start and name them, for example: a look board (the main subject and a key frame or two in each candidate look), the plan, a rough cut of the opening, section rounds in song order, a watch of the whole video, and approval for the final render. - Each round is a published page that opens with the decisions wanted, numbered so the person can answer by number, each with your pick and a short reason, then the evidence. Render as you go, so each round shows real shots. - Put the whole video in front of the person early as a playable cut, with a card for each shot not built yet, so pacing and story are judged before looks. - Before the final render, the person watches the assembled video end to end. A whole watch finds what section rounds miss, such as a missing reveal or two neighbouring shots making the same move. - When you ask for a technical go-ahead ("render the final now?"), say what it changes and what it costs. ### Versions of shots that aren't settled - Until a shot's idea is settled, build two to four versions that differ in idea (a different lead or device), and let polish wait for the pick. A shot whose idea is settled is built once. - Change only what is being decided: the same camera and timing grid, so parts of different versions can be cut together. Versions of a shot cover the same span of the song, so they are compared on the same music. Start each version's clip on the shot before, so the cut is seen. - Show the versions side by side with a short lean, and don't pre-filter: the person often picks against the lean or combines two. Combine parts by rebuilding (Builds, reveals and flows), never by splicing frames. - Write each pick and its reason into the plan, keep a strong runner-up for another place, and use a treatment picked for a recurring event everywhere it recurs. Compare looks the same way, on the same shots at the same moments. ### Keep building while you wait - A round stops only the work that depends on its answer. Publish what is ready, say so, and keep building; a question that doesn't block the next step never ends your turn. - Report the calls you made with their reasons, open to override, and keep questions for what only the person can decide. - Before a long absence, ask for the decisions the next hours depend on. Through an unattended stretch, spread the time over tests, tools and versions rather than one path that would be lost if the person rejects it. When nothing more can be built without them, polish what exists without cluttering the frames. ### Notes - Log every note in the notes register as a checkbox under its round, with its time, its shot and an owner. Tick it when it is fixed, and tell the person what changed since the last version. - Before fixing a note, find exactly what it means: the shot and the frame, then that spot across consecutive frames. A time on a review page that plays the video in parts may be the part's own time; ask for a screenshot when unsure. On the film, a reported flicker was first looked for in the wrong place; it was on the inner sides of the posts framing a doorway near the middle of the picture, not at the picture's edges as first assumed. - Treat a suggested fix as one option, and find the cause. - Prove a fix with a pixel comparison at the same frame: identical pixels mean the change did nothing, so revert it. Show the change as before and after at the same moments. - Notes often name bars, beats or sung words: check each against the timing file before building (Write every time against the track). - A note that states a general rule becomes a numbered rule for every shot built afterwards; approved shots change only if the person asks. Keep the rule's own reach and record where it came from: "the product close-ups matter most" does not mean "show the product only in close-up". When a rule's reach is unclear, read it back to the person. - When a rule or a wording changes, sweep every copy of it (code, edit data, plans, shot descriptions, post copy), then render again what changed. Keep earlier cuts reachable, so a replacement can be checked against what the old shot did well. - Notes often arrive while work is running. Log each as it arrives, and brief every agent whose work it touches before that work is shown. ### Replanning and how far to rework - When the person says the approach is wrong, or remakes after a change of look have left the video a patchwork, stop building and write down what went wrong. Then rewrite the plan for the whole video as one design, worked backward from where it ends. Existing shots are material to draw on, and the new plan may change or drop any of them. Test the ideas you are least sure of while the plan waits, save the old plan as its own file, and get the new plan approved before building more. - During production, rebuild a shot or a set from scratch whenever that is the easier way to its best version. A set that falls behind as the shots around it improve is rebuilt or cut. - After the person approves the final, try only easy fixes, and keep the approved version when a fix would mean rebuilding scenes or new techniques. - Rebuilding freely suits a piece with the budget for it; otherwise ask how much rework the budget allows. ### Review pages - For a long cut, build a page that plays it as one film (in parts on one clock, if the host limits file sizes), with a shot list that follows the playhead and jumps to the moments the notes named. Build a page per round of versions, newest first, so the person picks by letter, and a page for the plan with frames beside its sections. - To let the person choose between audio options, use one silent video and one audio file per option, kept in sync by script: seek, play, pause, and a drift check every 400 ms that corrects anything over 80 ms. - Hosts cap sizes. In October 2026, files published alongside a Claude artifact page could be up to 15 MB each for video or audio and 16 MB for text, with 64 MB and 255 files for one publish and 256 MB and 511 files for one version (a page's own stored files allowed video up to 20 MB). Check the current limits. Set each clip's bitrate from its length so it fits, and cut a long video into parts at frame boundaries. - Republish to the same address each round, so the person keeps one link. Split an update that is too big for one publish into several, with the new parts under new file names, so the live page never mixes old and new parts, and turn the clips of rounds already decided into stills. Name each encode by its source and settings, so a page never points at a half-replaced file, and send only what changed. - Some hosts serve .mp3 but not .m4a. Python's http.server can't seek video, since it doesn't support range requests, so preview locally with a server that does. - A published page may stay private until the person shares it: say so when you send the link, and how to share it. The person may pass a page on, so put nothing on it that the video itself doesn't show. ## Sound and delivery ### The soundtrack: one static gain - When the song is the whole soundtrack, never re-mix, compress or limit a mastered track. Reach the loudness target (-14 LUFS integrated, with the true peak at or below -1 dBTP) with one static gain, usually a cut, since most commercial masters are louder than -14 LUFS. - Measure the track, then apply the gain: ``` ffmpeg -nostats -hide_banner -i song.wav -af ebur128=peak=true -f null - ffmpeg -i song.wav -af volume=-4.2dB -c:a pcm_s24le song_gain.wav ``` The gain is -14 minus the measured integrated loudness: a track measured at -9.8 LUFS gets -4.2 dB. If raising a quiet track to -14 LUFS would put its true peak above -1 dBTP, stop at the peak limit and say so in the report. AAC encoding can raise the true peak, so measure the encoded file, never only the WAV. - Lay the gained track under the joined picture once, never the chunks' own audio, and check the finished file against it for an offset by cross-correlation: extract 3 s of mono audio at 8 kHz from both at the same moments (ffmpeg with -ss, -t, -ac 1, -ar 8000 and -f f32le), cross-correlate them with an FFT, and read the lag. ### What to deliver - The master: H.264, 1920x1080, the video's frame rate, BT.709 tags, AAC audio at 48 kHz, -14 LUFS integrated and a true peak at or below -1 dBTP, measured on the encoded file. - A review copy small enough to send to a phone (under about 30 MB). Set the video bitrate from the length: the target size in megabits divided by the seconds, minus the audio bitrate. 30 MB is 240 megabits, so a 288 s video gets about 0.83 Mbit/s in all, and with 128 kbit/s audio its picture has to drop to 480p: ``` ffmpeg -i final.mp4 -vf scale=-2:480 -c:v libx264 -preset slow -b:v 650k -maxrate 900k -bufsize 1800k -colorspace bt709 -color_primaries bt709 -color_trc bt709 -color_range tv -c:a aac -b:a 128k -movflags +faststart review.mp4 ``` - For a video over about three minutes, also share a 720p copy with anyone judging detail, and a full-resolution clip when the look has fine texture. - A vertical 9:16 version is a second build of the same scenes, laid out for that frame; a crop of the 16:9 frame loses what was composed for it. ### The report When you deliver, report what was made and how long it runs, the sources it used, the QA results, the source of every on-screen visual, anything a post needs to mention (AI-generated material, credits for other people's work), and anything you were unsure about. ### Posting it honestly - Say exactly how the video was made, in every post: what was generated and with which tool, what was made in code, and which model did the work. Word the claim as broadly as it is true: "no video generation model" lets viewers assume that generated images were used, so the film's posts said no image or video generation model was used. Before the copy goes out, check the claim against the build: for a claim that no generation model made the picture, check that the render loads no image or video files. - Use the same wording in every post, title and description, and when the claim changes, search the copy for every wording of it. - Credit on-screen sources in the description. - Set a platform's AI-content label where its rules call for one. YouTube's disclosure policy lists AI-generated music among the cases that need a label, so an AI-generated song needs it even when every visual is code; TikTok asks for a label on realistic AI-generated images, audio or video. Check each platform's current rule. - On YouTube, a music video goes in the Music category. It isn't made to rank for a search term, so write its title and copy for curiosity and candour. - Check that the plan the song was made under allows commercial use. ## Common mistakes ### The song and timing - Setting a time by hand, or from a generator's prompt, instead of from the timing file. - Trusting a speech aligner's times on a sung vocal, or checking only the words that look wrong. - Keying actions to an even beat grid instead of measured hits. - Slamming type or jolting the camera where the music has no percussion, or slamming a whispered word. ### Planning and shots - Starting to build before the shot sheet exists. - A literal picture for every lyric line: shots shrink below a second and the key moments get no room. - Showing a negated line happening, or spending a big line on its literal action. - Cutting fast because the music is fast, with images too new or too detailed to take in. - Illustrating what the viewer already understands because the words name it (pipes for "plumbing"), or flashing an image per item of a sung list. - Making the core idea beautiful at the cost of clarity. - Carrying one video's look or showpiece ideas into the next video as defaults. ### Lyrics and type - A lyric readable before it is sung, including text inside the scene (a chat message, a note, a name). - A passage on screen that the viewer would have to read while the vocal sings, or text that says something other than the words. - Labels sized for a monitor, or words resting in the bottom 12% of the frame. ### The look, 3D and characters - A realistic 3D world seen wide: it looks cheap unless every surface is detailed. - A filter laid over a lit 3D render instead of rendering the 3D in the look (for a print, into the inks). - A long view running to an empty horizon, or a pool of light with no visible source. - Matching a character by eye, or stopping a near-realistic match short of exact. - Every emotion at full intensity, or a reaction that changes faster than a viewer can follow. - A character parked in the middle of the frame, smiling, shot after shot. - Lip-sync driven by loudness, which moves the mouth through held notes. - In a print look: darks printed as tints or short of full coverage, the default boil on a still hold of thin lines, and judging the print from downscaled previews or compressed copies. ### Camera and cutting - Adding the drum layer in two places on one shot, or leaving it on into the frames before a cut. - Stacking a second transition on one that already hands over. - A camera move that runs up to the cut, or reverses across it. - Cutting while something is still moving into place, or as the last letter of text to be read appears. ### Rendering and delivery - Anything in a frame that depends on the wall clock, unseeded randomness or unsnapped time. - A render that draws a stand-in for a missing scene or font instead of stopping. - A change to a shared engine that moves an approved shot's frames. - Checking a moving 3D shot with single stills: a camera passing through a wall shows only on a contact sheet of the whole clip. - Rendering a changed stretch without the shots on either side: a whip or dissolve across the seam is then fake. - Joining chunks with their own audio, or letting -shortest drop the last frame. - Encoding frames without the BT.709 matrix and tags, in your own render or splice helper as much as in the final encode, and sending a file whose tags weren't checked. - Limiting or re-mixing a mastered track to reach the loudness target, or measuring the WAV instead of the encoded file. - Killing a render by stopping chrome.exe by name. ### Working with a director - Running review rounds and versions of every shot on a video the person hasn't chosen to direct shot by shot. - Pausing all work for an answer that doesn't block the next step. - Turning a note about what matters most into a rule about what alone is allowed. - Showing the person renders older than the last fix, or a card where a built shot belongs.