How I made a launch film with Claude, Remotion and a few prompts.

The whole pipeline behind the DYNAMO launch films, with the real prompts: brief, art direction, generated plates, image to video, Remotion, sound, Suno and a pacing check.

The DYNAMO launch film, 93 seconds: generated retro plates and the real console, built in Remotion and cut to the music's bar grid.

I made two launch films for DYNAMO in one evening and the next morning: a 93-second motion film built entirely in code, and a 93-second retro “infomercial” with generated photographic plates. Friends asked how. This is the whole pipeline, with the real prompts.

The short version: Claude writes the film as a React program in Remotion. Every cut sits on the music’s bar grid. Generated images and clips are props inside that program, not the film itself. A script checks that every line on screen holds long enough to read.

The stack

  • Claude Code with Opus 5.5: the script, the Remotion code, the music, image, clip and sound prompts, and every revision.
  • Remotion 4: React components rendered frame by frame to MP4. The motion film adds three.js through @remotion/three.
  • Codex image generation: photographic plates (storyboard frames that become the actual shots).
  • Grok Imagine via the Grok Build CLI: six-second image-to-video clips from approved plates.
  • ElevenLabs: sound effects.
  • Suno: the score.
  • ffmpeg: contact sheets, measurements and the final web encode.

Plates, clips and sounds come from small shell scripts that read prompt files, so any shot can be regenerated by name from the terminal.

1. One feeling, then a script

Before any picture, write down who the film is for and the one thing it should make them feel. For the launch film:

The one feeling: I’m the bottleneck between my agents. I want the screen where nothing needs me.

Then a table: each unmet need, what the viewer sees instead, and the product truth behind it. “I can’t step away” became “He goes home; the office works all night; morning has answers.” That table is the film.

The motion film’s script went one step further. It never shows the problem:

Spine: It runs. You decide. No problems on screen. Every beat shows the inverse of a pain the viewer already feels, so they supply the “before” themselves.

The script is a timeline, not prose. Pick a tempo first, because the tempo sets the grid:

96 BPM, 4/4: a bar is 2.5 s, 36 bars = 90 s. Bar n starts at (n−1) × 2.5 s.

Every row of the script is a time, a picture and a super (the line on screen).

2. Art direction from reference videos

Name the references and say exactly what you’re taking from each. The first motion-film cut was a “Mercury-style” 63-second film. The launch film borrowed a 1988–1993 tech commercial and played it straight.

The most useful rule in the launch film’s look section:

Two worlds, one rule. Retro never touches the UI’s pixels.

The world is retro; every shot of the product is pixel-sharp. Match cuts carry you between them: an index card becomes the first row of the product’s inbox, a fax stack becomes the work list, a TV channel becomes the company menu.

For the motion film I wrote craft rules Claude could apply to every shot:

  • Hero crops, not the whole app. Show one element at 2–4× size (a card, a row of stamps, a memory line), the rest dimmed and out of focus.
  • One camera per chapter. Each chapter is a continuous move through several UI states, not a row of dissolves.
  • Transitions that mean something. Slab → sidebar. Night sky → Work list. Card → phone notification. The last ember → the D.

Never fake the product. The UI in both films is the real console rebuilt from its own components and design tokens, filled with a fictional company’s data: bigger type, fewer rows, punchy seeded numbers.

3. Storyboard frames that become the shots

The launch film needed photographic scenes: a founder buried under CRT monitors, a robot chief of staff, a yacht, a talk-show couch. Each is one prompt file, p-<name>.txt, sent to Codex’s image tool by a ten-line script:

# ./gen.sh name → name.png from p-name.txt via Codex image generation
codex exec --skip-git-repo-check --sandbox workspace-write -C . --image $ref - < p-$n.txt

Characters stay consistent because every scene with a person attaches the same reference image of the cast (ref/cast.png). A real prompt:

Use your image generation tool to create ONE landscape image, 3:2 aspect (1536x1024 or larger). Keep the man and the robot from the attached reference exactly the same characters: bearded man with glasses and curly hair, teal/magenta/purple 1990 windbreaker over a graphic tee, stonewashed jeans; the boxy worn beige robot with camera-lens eyes. The man walks toward camera in the centre, flanked by five robots, two on his left and three on his right. All five robots are IDENTICAL copies of the reference robot: the same boxy worn beige body, the same camera-lens eyes, the same proportions and wear, no variation in design. They stride out of thick fog, heroic low angle, backlit by pink and cyan light beams, on a glowing magenta perspective grid floor. 1980s action movie poster lighting. Photographic still from a sincere 1990 American TV commercial: shot on 35mm film, warm practical lighting, shallow depth of field, rich colour, subtle film grain, slightly soft like broadcast. No readable text, no logos, no words, no letters anywhere in the image.

What makes these work:

  • Describe the character the same way every time, word for word, and attach the reference.
  • Say the film stock and the era (“sincere 1990 American TV commercial: shot on 35mm film”). It sets light, grain and softness in one line.
  • Ban text. “No readable text, no logos, no words” in every prompt. Generated text is garbage, and anything readable goes in the code, where it’s crisp.
  • Leave screens blank. Monitors glow “a dark blank green phosphor… nothing written on it.” Remotion pins the real UI onto them later with a four-corner homography (a CSS matrix3d), so the plate’s monitor shows the actual product.

Review plates as one contact sheet. Reject, edit the prompt file, rerun that name.

4. Image to video, only from approved frames

Motion comes last and only for plates that earned it. Grok Imagine animates a single approved frame into a six-second 720p clip. The script asks the Grok Build CLI to call its tool exactly once:

grok -p "Call your image_to_video tool exactly once with image=$root/public/plates/$n.png, duration=6, resolution_name=\"720p\" and this prompt: \"$p\". Save the video it returns as $root/public/motion/$n.mp4. Reply with only the saved path, or the tool's error verbatim." \
  --output-format plain --no-subagents --always-approve

All the shots run in parallel. The prompts live in motion/prompts.json, and the pattern that matters is lock the camera and say what doesn’t change:

“Locked-off camera, no camera movement, the monitor screen stays perfectly still. The relaxed man raises the mug, sips his coffee and leans back with a content smile. The robot beside him slowly turns its head toward him. City lights twinkle through the window.”

“Locked-off camera. The fax machine keeps feeding out a long curling sheet of paper that piles onto the heap. Nothing else changes.”

A locked camera and a still screen keep the pinned UI aligned with the clip. Camera moves (“Very slow push in”, “Slow orbit to the right”) are reserved for shots with no screen in them, and Remotion adds its own camera on top anyway. A clip only goes into the film once its name is added to a MOTION set in the code; until then the still plate is used, so a failed generation never breaks a render.

5. Claude builds the film in Remotion

Claude does most of the work here. The structure that kept it manageable:

  • lib.ts: the music grid, one ease, the design tokens, small helpers (tw to tween between two times, kf for keyframes, pop for a spring that overshoots once).
  • One file per act or chapter, plus the rebuilt UI (ui.tsx, screens.tsx).
  • plate.tsx for photographic plates with a camera and corner-pinned screens.

Cut on the bar grid. The launch film’s track was measured, not assumed: 96.325 BPM, first downbeat at 0.238 s. One function then places everything:

// "Upgrade Now": 96.325 BPM, first downbeat at 0.238 s, measured from its kick and snare.
export const BEAT = 60 / 96.325
export const DOWN = 0.238
/** Start of bar n (1-based), in film seconds; fractions count beats (bar(7.5) = bar 7, beat 3). */
export const bar = (n: number) => DOWN + (n - 1) * BAR

The motion film goes further and names the hits measured from the track’s onsets: swell: 4.81, reveal: 15.16, morning: 53.03, hold: 62.23, peak: 84.1. Scenes start and end on those names, so “the card rises on the lift” is a line of code, not a guess on a timeline.

One ease for everything. The console’s own curve, fast out: Easing.bezier(0.23, 1, 0.32, 1). Motion feels like the product because it is the product’s motion.

three.js for depth. The motion film opens on orange dust drawn into a fluted glass slab, with bokeh and bloom. One trap worth knowing: the React Three Fiber postprocessing wrapper draws nothing under Remotion, so bloom uses three’s own EffectComposer with an UnrealBloomPass, rendered in a useFrame. Render with --gl=angle.

Review with contact sheets. shots.mjs bundles once, opens one browser, renders frames at the seconds you list, and tiles them into one image with ffmpeg’s xstack. Claude and I both read it before rendering anything. (The first version ran remotion still in parallel; the parallel renders fought over the GPU.)

6. Sound effects under the score

The launch film has a cue sheet of 36 sounds, each one an ElevenLabs prompt and a length in sfx/prompts.json:

“vcr-pause”: “VCR pause button: mechanical clunk, tape audio stops with a warbly slow-down, then quiet tape hiss”, 1.2

“hold-rise”: “short rising electronic tone that fills up over one and a half seconds, like a hold-to-confirm button”, 1.5

The cues are placed on the same grid, ["info-slam", bar(5), 0.55], at levels well under the music: “it carries the film, these sell the picture.” A sound that doesn’t exist yet is simply silent, so the film renders at every stage.

7. Suno prompts written to the edit

Most guides cut video to a song you already have. Here the script came first, and Claude wrote the music prompt to land on its bars. Three parts.

Style of music (the motion film):

Instrumental 1980s sci-fi film score, analog synthesizers, 96 BPM, D major. Wondrous, warm and confident, a dawn over a neon city. Polyphonic brass-synth swells with expressive ribbon pitch bends, shimmering poly-synth pads, a pulsing 16th-note analog sequencer, deep sub bass, a glassy four-note FM bell motif, gated-reverb electronic drums, huge hall reverb, tape warmth. Cinematic and premium, builds steadily to a triumphant final chord with a long reverb tail.

Lyrics, tags only (Instrumental on). Each tag is a section of the film:

[Intro: shimmering pads, dust in light, the four-note bell motif, a warm brass swell]
[Night: pulsing analog sequencer bass, soft gated drums on 2 and 4, distant arpeggios]
[Build: sequencer tightens, bright arpeggios climb]
[Morning: filter opens wide, strings rise, drums fuller, confident and bright]
[Drive: full band, hits on every downbeat]
[Outro: drums drop out, bell motif alone over pads, final major chord, long reverb tail]
[End]

Exclude styles: vocals, choir, vocal chops, EDM drop, dubstep, trap hi-hats, lo-fi, guitar solo, dark, horror

Then a bar map in the script says where each section has to land (Intro bars 1–3, Night 4–11, the morning lift on bar 12, the final chord on the D at 0:55).

For the launch film the prompt is a timestamped brief instead: “0:00–0:15, ‘the old way’: a thin, nervous 16th-note synth arpeggio that sounds like it’s playing through a cheap TV speaker… a tape-stop drops it into one beat of silence at 0:14,” through to “1:22–1:25: a shameless, triumphant keytar solo over big gated drums.” It names a key (“E minor resolving to G major”), a length (93 seconds), a recurring motif, and ends with what to avoid: “Played completely straight, like a real 1989 ad. No vocals, no vocal chops, no sound effects, no EDM drops.”

Suno won’t hit your bars exactly, so the grid in the code is measured from the track you keep, not the tempo you asked for.

8. A pacing check that fails the build

The most useful twenty lines in the project. Every super has to stay up long enough to find it after a cut and read it while things move:

// every super must stay up for ≥ 0.5 s (find it after a cut) + chars ÷ 15 (read it while watching motion)
const need = 0.5 + text.length / 15, have = b - a
if (have + 1e-9 < need) { bad++; console.log(`SHORT ${have.toFixed(2)}s < ${need.toFixed(2)}s  ${text}`) }

node pacing.mjs lists every line that’s too short and exits non-zero. Two more rules from the script: the caption lands before its action, and results hold for at least a second. Claude can’t feel pacing; it can run a check.

9. Render and ship

remotion render src/index.ts Film out/dynamo-film.mp4 --codec h264 --crf 16 --gl=angle

The masters are big (85 MB for the motion film, 470 MB for the 60 fps launch film). An H.264 encode capped at about 1 Mbps (-crf 24 -maxrate 1M, 30 fps) with -movflags +faststart brings the launch film to 11 MB at full 1080p: the file on this page. The 9:16 phone cuts are a second composition in the same code.

What I’d do differently

From the commit history:

  • Lock the track before the timeline. The motion film’s script was written for 24 bars, a 60-second cut. The finished film is 92.8 seconds, recut to the launch film’s track. Start from the music you’ll keep.
  • Readable beats pretty. The opening was rebuilt twice: first a lens-based rebuild with bokeh, dust sheets, fanned glass and pixel erosion, then “a readable org of department cards instead of the blurry slab.” The second is the one that tells you what the product is.
  • Write the reading rule into the script on day one. The pacing check arrived as its own commit after the first cut. Every later edit was faster because of it.
  • One focal point per shot, from the start. The last pass of UI work was giving each shot “one clear focal point”: larger type so rows fit whole, blur only at the far edge.
  • Render less, look more. The launch film went through four full 470 MB renders in about twelve hours. Contact sheets would have caught most of what changed.
  • The message keeps moving. The final commit replaced “Nothing needs you.” with “Your 20 minutes. Their 24 hours.” Keep the copy in one place.
All field notes ←