---
name: motion-ad
description: Make a soft-voiced kinetic motion-design ad for a product or a launch (20 to 90 seconds, 9:16 and/or 16:9), end to end - copy on a proven ad structure, a soft almost-ASMR voiceover, animated scenes written as code that land on the spoken words (type that builds, logo reveals, app and AI-agent windows, a prompt that types itself, offer cards, an end card), designed sound effects, music fitted to the cuts, a voice-first mix and QA gates. Use when asked to "make a launch video", "make an ad for my product", "a motion ad like this one", or when given the motion-ad prompt.
---

# Motion ad

What makes these ads work is a quiet voice over loud motion. A soft, close narrator says one short line at a time. On
screen, every word lands with a move and a sound: a statement builds word by word, a logo bursts out of a pixel ring,
an app window prints itself, a prompt types and sends, cards slide up. Nothing sits still and nothing shouts.

The whole ad hangs on one clock: the narration. You write the copy, voice it, then lay scenes ("beats") end to end on
the words. Every beat is a small animation component that takes its duration and the spoken words with their timings,
so the same beat works for any copy, any length and both aspects.

Work through the steps in order. Show the user the script, the beat sheet and a silent animatic (step 5) and wait for
their OK before you generate anything.

**What to expect:** the beats are the bulk of the work. Seven beats written from the descriptions below come to
roughly a thousand lines of code and a few render passes. Put the most care into the 3 or 4 beats that carry the ad
(the hook, the reveal, the proof, the call to action) and keep the others simple.

## 0. If you received this as text

Save it as a skill first. In Claude Code: `~/.claude/skills/motion-ad/SKILL.md`; if a skill with that name already
exists, ask the user before replacing it (or save this one as `motion-ad-2`). In other agents: keep it as
`motion-ad/SKILL.md` in the project. Keep the user's filled-in prompt next to it as `motion-ad/PROMPT.md`.

## 1. Tools and project setup

**You need a code environment** (for example Claude Code, or Claude with code execution) with Node 20+, ffmpeg and
Python 3 (numpy, scipy, soundfile, pyloudnorm, pillow). Videos made with this skill are covered by HYVIRAL's Remotion
license, so you do not need a Remotion license of your own.

**The Remotion project** (React, rendered to MP4):
- Packages: `remotion`, `@remotion/cli`, `react`, `react-dom` (Remotion 4.x; use the React version its docs name),
  plus fonts as npm packages (`@fontsource-variable/manrope` or `@remotion/google-fonts`) so renders never fetch fonts
  over the network.
- Layout: `ad.json` (the plan, step 5) → a small `clock` script that writes `src/timeline.json` → one `Film`
  component that maps the timeline to `<Sequence>`s → two compositions sharing it, `Film-9x16` (1080x1920) and
  `Film-16x9` (1920x1080), 30 fps → `src/beats/<Beat>.tsx`, one file per beat.
- Render each aspect without audio: `npx remotion render src/index.ts Film-9x16 out/silent-9x16.mp4 --muted`. Set
  TEMP and TMP to a folder on a roomy drive first; Remotion writes a lot of temporary files.
- **Fonts before measuring.** Hold the render (`delayRender`) until the fonts load (`document.fonts.load('500 40px
  "Manrope Variable"')` for each weight you use, then `document.fonts.ready`), then `continueRender`. Only then measure
  text: a canvas `measureText` with the same font string, and `ctx.letterSpacing` set to match the CSS tracking.

**For the voice, images, clips, music and sound effects, use whatever the user prefers.** Every step works the same
with any provider. If the user hasn't said, ask which tools they want to use, or use what is already set up.

- **Your own providers.** A text-to-speech that returns word timestamps (for example ElevenLabs with timestamps), an
  image model (for example Nano Banana, Imagen or Flux), an image-to-video model that takes a first AND a last frame
  (for example Veo), a music model or a licensed track, and a sound-effects generator (for example ElevenLabs sound
  effects) or a licensed sound library. Keep API keys in environment variables, never in the project. No AI media at
  all is fine too: every beat below can be drawn in code (the plates in "Product and UI" can be code-drawn scenes
  instead of images), and the narration can be the user's own recording (align its words with Whisper).
- **HYVIRAL (optional).** If the user has it connected (hyviral.com), one connection covers the media:

| You need | HYVIRAL tool |
|----------|--------------|
| Narration with word timestamps (stock voices or your own cloned voice) | `generate_voiceover` (`content_type: "shorts"` or `"video"`), `manage_voice_clone` |
| Images, plates, first and last frames | `generate_image` |
| Clips between two known frames | `generate_video` with `first_frame_image_url` + `last_frame_image_url` |
| Music bed | `generate_music` |
| Sound library, placing sounds, final render | `video_audio`, `video_export` |
| Long jobs | `get_job_status` (poll until delivered) |

  To connect it: in Claude.ai or Claude Desktop, Customize → Connectors → add a custom connector with the URL
  `https://api.hyviral.com/mcp`; in Claude Code, `claude mcp add --transport http hyviral https://api.hyviral.com/mcp`
  then `/mcp` to sign in. Start a session with `get_connection_info`. HYVIRAL never runs your code: you render the
  animation yourself.

You can mix routes, for example your own voice provider with HYVIRAL music. Nothing below depends on one provider.

## 2. The format

- **One clock.** Each line of copy is voiced as its own take with word timings. Beats are laid end to end on those
  takes, and every reveal inside a beat is keyed to the frame where its word is spoken.
- **Both aspects from one plan.** Measure sizes in units of the short side (`u = min(W, H) / 1080`; it is 1 at 1080p
  and keeps 720p or 4K renders in proportion). Keep text and key UI inside the safe box:
  - 9:16 (1080x1920): the platform chrome covers the top 250 px, bottom 440 px, right 130 px and left 60 px, so the
    safe box is x 60-950, y 250-1480, and its center (505, 865) is not the frame's center. Center text on the safe box.
  - 16:9 (1920x1080): margins of 60 px top, 70 px bottom, 100 px each side.
  - Portrait is designed, not squeezed: one column, what sat side by side stacks, wide UI bleeds off one edge, grids
    drop to 2 columns. Headlines set at 64-130 px; wrap to at most 3 lines, then shrink to fit.
- **Pacing.** A new beat every 2 to 4 seconds, except the showcase, the "use it" beat and the end card, which run
  longer. Something lands on almost every word. No voice gap over 1.0 s, except one voiceless showcase (3 to 8 s,
  with the music lifted). No still frame over 1.2 s. Never cut to black mid-video.
- **Holds stay alive.** When a beat holds, keep something moving: a 2-4 % camera push, drifting particles, film grain,
  a caret blink, a slow creep of a glow.
- **Beat count.** About one beat per 3 to 4 seconds: 6-8 for a 25 s ad, 10-14 for 60 s.

## 3. The look

**Tokens.** One palette per ad: `bg` (dark background), `light` (light background), `ink` (text on light), `text`
(text on dark), `muted` (secondary text), `accent`, `accent2`, `accent3` (three accent shades, light to deep), `deep`
and `navy` (two dark tints of the accent for shadows and washes), `glow` (the accent at about 55 % opacity).

- **From a partial palette:** `bg` = the darkest color, `light` = the lightest, `ink` = `bg`, `text` = `light`,
  `muted` = a 45 % mix of the two; `deep` and `navy` = the accent mixed 80 % and 90 % toward `bg`.
- **Contrast:** accent words need at least 3:1 against their background. On light backgrounds use the deepest accent
  (or darken it); on dark use the lightest.
- **Type:** one or two typefaces. With no brand font, use the default look below (500 for statements, 700 for headlines).
- **Grain:** a seeded noise layer redrawn every frame at 3-6 % opacity (a little stronger on dark).
- **Light and dark.** Paper (light) is the default world; use dark for one or two beats as contrast (WordStack, and
  any beat with `world: dark`). Never cut to black.
- **Default look:** warm paper `#F4F1EA`, ink `#16140F`, warm near-black `#121110` for dark beats, cobalt accents
  `#4C6BFF`, `#3552E8`, `#2238B8`, deep `#121C5E`; Manrope for text, Sora for the wordmark and big headlines.

## 4. Copy

Write the copy before you pick beats, and read every line aloud, slowly and softly.

- **Short lines.** 2 to 9 words, one idea each. Fragments carry this format: "Screenshots. Arrows. One long Friday."
  (Call-to-action lines are the exception: up to two short sentences.)
- **Second person, concrete.** Say what the product does, then show it. Every claim gets a beat that proves it.
- **One accent word per line**, usually the last: it lands in the accent color.
- **Spoken vs shown.** Keep two versions of a line when they differ: the spoken one spells numbers and brand names the
  way they are said ("forty", "Tide-pool"), the shown one keeps digits, capitals and the real spelling ("40",
  "TOUR"). Keep one spoken word per shown word so the timings carry over. Beats always display the shown version.
- **Real claims only.** Use a number only if the user gave you one. No number, no number line.
- **No em dashes on screen.** Commas, full stops and line breaks do that job.
- **Your own words.** Every example line here shows a job, not copy to reuse. If the user points at a reference ad,
  borrow its pacing, never its lines or its running order.

**Lengths:** short ads 20 to 40 s, launch ads 60 to 90 s. In ads under 30 s, the showcase can be 3 s and the end card
5 s: drop the follow line and the DM arrival.

**The launch structure** (60 to 90 s). Use it as a menu: drop, merge or move parts. A 45 s version keeps 1, 3, 5, 6, 9
and 11. The example lines are for a made-up product, Tidepool, which makes product tours.

| # | Part | Job | Example line | Beats (step 6) |
|---|------|-----|--------------|----------------|
| 1 | Hook | the result itself, or the boldest true claim | "This tour made itself." | TypeLine with the spark intro, InkWord, WordStack |
| 2 | Friction | what it replaces, in the viewer's own words | "Screenshots. Arrows. One long Friday." | TimelineUI, PlateHeadline, TypeLine |
| 3 | Name | the product, plainly | "This is {Name}." | FoldReveal |
| 4 | Definition | what it is, in one line | "Your product, explained by your product." | BracketClaim, GlitchCut, WordsLine |
| 5 | Use | the gesture of using it, shown live | "Paste a link. Pick up the finished tour." | PromptSend |
| 6 | Proof | show the output; the user's "three things" go here | "Look what came back." + a voiceless showcase | SpringLine, PhoneFan, StreakWords |
| 7 | Fit | where it lives and what it learns | "It lives next to your docs." | ConnectPill, AgentWindows, CurveRider, GiantWordPass |
| 8 | Range | what comes with it | "Voice, captions, music. All of it." | SmashWord, WordStack |
| 9 | Gone | what the viewer can stop doing; strike it out | "No screen recorder. No second take." | StrikeChips, DockApp, TabClose |
| 10 | Offer | the deal or the gift | "Your first tour is on us." | OfferCards, WordsLine |
| 11 | Call to action | one action | see below | PhoneEndCard |

**Short structures (20 to 40 s):**
- **Name-early** (parts 3, 2, 5, 6, 11): the name, the friction, using it, proof, call to action.
- **Before and after** (2 as "before", GlitchCut, 5 as "after", 6, 11).
- **Three reasons** (3, the user's three things as three beats, 6, 11).
- **Feature drop** ("New in {Name}:", the feature, a 3 s proof, 11).

**Proof is real.** The showcase and montage show things the product really made, or the product's real screens. If the
user has neither, show the product's interface in use, or drop the showcase; never present the ad's own scenes or
stand-in images as the product's output.

**Call to action, organic or sponsored.** Ask the user which one.
- **Organic** (a regular post): comment-to-get. "Comment KEYWORD and I'll send it to you." Then "Follow for the next
  one." (optional under 30 s). No link or URL on screen, and no offer details. Show the keyword in capitals; say it as
  the plain word ("Comment tour and I'll send it to you").
- **Sponsored** (an ad with a button): a direct line, a button and a URL. "Try it at example.com." Put any offer line
  before the call to action, never after it.

**Late reveal (optional, strong for sponsored ads).** Keep the product name hidden until about 70 % of the runtime, then
"The secret? {Name}." with the logo reveal, then the offer, then the call to action. Before the reveal, every beat that
would print the name (labels, window titles, tabs, tiles) shows a neutral placeholder such as "Your agent" instead.

## 5. Plan and animatic (before generating anything)

1. **Write the plan** as `ad.json`, for example:

```json
{
  "aspects": ["9:16", "16:9"],
  "brand": { "name": "Tidepool", "keyword": "TOUR" },
  "look": { "bg": "#0E1116", "light": "#F2F5F7", "accent": "#5EEAD4", "accent2": "#2DD4BF", "accent3": "#0F766E" },
  "cta": { "mode": "organic", "keyword": "TOUR" },
  "lines": [
    { "id": "l01", "text": "This tour made itself." },
    { "id": "l09", "text": "Comment TOUR and I'll send it to you.", "say": "Comment tour and I'll send it to you." }
  ],
  "beats": [
    { "id": "b01", "beat": "TypeLine", "lines": ["l01"], "props": { "intro": "spark" } },
    { "id": "b05", "beat": "PhoneFan", "sec": 3.5 },
    { "id": "b07", "beat": "PhoneEndCard", "lines": ["l09"] }
  ]
}
```

2. **Estimate the takes without generating them.** For a soft narrator, after the pauses inside a take are tightened
   (step 7), a line lasts about `0.69 + 0.049 × letters + 1.1 × inner stops + 0.4 × commas` seconds:
   - `letters` counts the letters and digits of the spoken line
   - `inner stops` counts `.`, `?` and `!` before the last word
   - real takes land within about 0.3 s of this

   Inside the line, leave 0.45 s after each inner stop and 0.2 s after each comma. Share the rest between the words
   in proportion to (letters + 1).
3. **Lay out the clock** in seconds, then round each boundary (the running total) to a whole frame at 30 fps.
   - The first beat starts at 0 and gets a 0.25 s lead-in on top of its own lead.
   - Each beat is its lead, then its lines with 0.35 s between them, then its tail. The defaults are a 0.15 s lead and
     a 0.3 s tail; the table below lists the beats that need more room.
   - A voiceless beat lasts its own seconds.
   - A beat's length window (its minimum and maximum) includes its lead and tail. When it runs short of the minimum,
     split the extra between its lead and its tail. All of it in the tail opens voice gaps.
   - When a line runs past a beat's maximum, split it at its last inner full stop and give the second half its own
     beat (a statement beat, or the next beat in the structure).
   - The last beat runs to the end of its tail, plus 0.4 s.

   | Beat | Lead | Tail | Why |
   |------|------|------|-----|
   | TypeLine with the spark intro | 0.5 s | | the spark lands and becomes the caret before the first word |
   | FoldReveal | 0.4 s | | the mark closes and the dot pops before the name, never on it |
   | PhoneEndCard | 0.3 s | 1.0 s | the end shot holds after the last tap |
   | TimelineUI | | 0.9 s | the dive into the thumbnail needs room after the last word |
   | PromptSend | | 0.8 s | the send click lands just after the words; more breaks the 1.0 s gap rule |
   | InkWord, GiantWordPass | 0.1 s | 0.4 s | the press-up and the whip-out |
4. **Check the plan:** list the gap between every two spoken lines. Any gap over 1.0 s outside the voiceless beat
   means a beat is too long for its words: shorten its tail, give it more copy, or pick a shorter beat.
5. **Render a silent animatic** in both aspects. Make contact sheets at one frame per second (select frames by number:
   `ffmpeg -i in.mp4 -vf "select='not(mod(n\,30))',scale=360:-2,tile=8x3" -vsync 0 sheet_%02d.jpg`), and draw the
   safe box on every tile of both aspects.
6. **Show the user** the script, the beat sheet (beat, line, seconds) and the animatic. Wait for their OK.

## 6. The beats

**Build each beat as a Remotion component.** It receives:
- its frame `f` (0 to `dur - 1`, never the film frame) and `dur`
- its lines: `[{ id, text, words: [{ w, f0, f1 }] }]`, with word frames relative to the beat
- its props, the look tokens and the brand

How to build them:
- Key every reveal to the frame where its word is spoken. Fall back to an even spread when a word is missing.
- Text defaults to the lines' shown text. Every prop is optional.
- Hold gracefully when the beat is long, compress (never cut text) when it is short, and key exits to `dur`.
- Make it deterministic: no `Math.random`, `Date` or CSS animations; use a seeded random.
- Measure text before drawing anything that covers or hugs it (step 1, "Fonts before measuring"). Lay out a wrapped
  block once, from the full text, so nothing reflows while it types.
- Write moving text as HTML, not SVG `<text>`, under per-frame transforms. Clamp CSS lengths at 0. Pre-scale large
  images to about twice their display size.
- Each beat also returns its sound moments, `[{ frame, kind }]`, using the step 8 kinds (whoosh, swish, pop, tick,
  click, typing start and end, impact, riser end, glitch, chime, shimmer, zoom, paper), computed with the same timing
  code as the animation.

The beats below are a menu of proven designs. Build the ones your plan uses.

**Shared motifs** (build these once and reuse them; they give every ad its own signature):
- **Spark:** a small glowing dot with a light trail, the ad's only "actor". It taps buttons, rides curves, flicks tabs and
  lands where the caret starts. Draw the trail from the dot's real path, sampled a few times per frame so fast moves
  stay smooth. No mascot characters.
- **DotGrid:** a quiet grid of small dots behind the type, drifting very slowly.
- **Horizon:** a flat accent line with a soft glow above it, rising or drawing out from the center.
- **The mark:** the user's logo, or an original fold mark (a square split on its diagonal, with a dot in the fold).

**Statements**
- **WordsLine** (1.2-4 s, light): the verdict line builds word by word on the spoken words, over the DotGrid. The
  accent word lands in the accent and stays, with an underline that draws under it as it lands; the others settle to
  ink. Optional exit: an accent bar wipes up over the measured line in 3 frames.
- **TypeLine** (1.2-8 s, light or dark): a typewriter line. The newest letters are tinted accent and settle; the caret
  is solid while typing and blinks in holds; the letters of word i type while word i is spoken. Optional intro: the
  Spark streaks in on an arc, lands with a small ring and becomes the caret. Start the arc about 5 frames before the
  beat, so frame 0 already shows the Spark mid-flight with its streak: the film's first frame is never bare paper.
  Optional highlight: a solid accent box behind one word.
- **InkWord** (0.8-3 s, light): one big word for the key noun. An accent rule draws across, the letters press up out of
  it one by one with a little overshoot, then an accent fill wipes across them, each letter keeping a slightly offset
  hairline outline, like misregistered print.
- **GiantWordPass** (0.8-2.5 s, light): one word 1.3 to 3 times the frame width slams in with motion blur over a dot
  grid that slides at a slower parallax, drifts, then whips out; it arrives in the accent and settles to ink. In 9:16,
  use 4-5 letter words.
- **SmashWord** (1.7-4.5 s, light): the key word stamps into the center, giant and solid accent, scaling down from 2x
  with a short shake, holds, then shrinks straight into its slot in the line while the other words rise out of masks.
  The last word gets a Spark-led underline.
- **SpringLine** (1.2-4 s, light): a small centered line whose words spring up from below with overshoot; the last word
  in the accent. The quiet hand-over before a showcase.
- **StreakWords** (1-3 s): a short count ("Twelve looks so far.") springs up word by word over a soft tilting light streak.
- **BracketClaim** (0.9-3.5 s, light): "> claim <" in the mono face. The words type between two accent brackets that
  spread just before each word needs the room.
- **WordStack** (1.5-4.5 s, dark): a dark DotGrid with a faint accent wash, a small lead line over big stacked lines
  (one in the accent), and the Spark orbiting the stack. Optional exit: the stack whips up while a Horizon rises.
- **CurveRider** (1.6-4.5 s, light): a graph-editor curve with diamond keys and handles on paper. The Spark rides it and
  draws it solid behind itself while the line's chunks spring in above each key as they are spoken.

**Reveals and transitions**
- **FoldReveal** (1.4-5 s, light or dark): the name or logo reveal and the lock-up. The mark's two triangles fly in from
  opposite corners and close into the square with a small bounce; the Spark pops into the fold as the dot; the
  wordmark types in beside it (below it in 9:16), with up to two words under it. With the user's logo, two triangular
  masks close over the frame and part to reveal it. Keep every sound before the name (start about 0.4 s early).
  Optional exit: the square scales up and its fold opens into the next beat's color.
- **GlitchCut** (0.3-0.6 s): ink and paper frames alternate with horizontal accent slabs, a fold triangle, a dot cluster
  and a Spark streak, generated per frame from a seed. It carries the first words of the next line exactly where the
  next beat will set them.

**Product and UI**
- **TimelineUI** (1.6-4.5 s, light): a readable headline over a paper editor card (ruler, clip blocks, an accent
  waveform, keyframe dots, a playhead). The camera dives into the selected clip until it fills the frame.
- **PlateHeadline** (1.8-6 s): a two-line headline whose words fade up on the narration. Over the user's image or clip,
  it sits at the top with a scrim and a slow push. With no image, it sits centered over a code backdrop (soft accent
  glows, the DotGrid, a Horizon). Optional exit: the picture folds into a dot that leaves as the Spark.
- **StrikeChips** (2-6 s, light): "No editor. No timeline. Just one skill." Each "No X" lands as an app chip (a pill with
  a simple drawn icon and the label X); a marker line led by the Spark strikes it out and it grays; the chips crumple
  away; the positive line lands as a file card dropping into place ("SKILL.md"), with the line above it. In 9:16 keep
  the line within 86 % of the safe width and the card within 90 %, or both touch the edges.
- **ConnectPill** (1.8-5 s, light): a Horizon draws out from the center and a paper pill card (the product mark, a
  label, a status dot) pops onto it. The Spark runs along the line into the pill, the rim turns accent and the dot
  goes green; a cursor clicks it.
- **AgentWindows** (1.8-6 s, light): an accent scan line reveals a paper app window (a terminal, an agent panel or a
  chat); windows swap by lifting out and rising in on their spoken names. Use real product names only where the copy
  is about integration.
- **PromptSend** (3.6-8 s, light): opens close on a chat input that fills most of the frame; a prompt types (a `prompt`
  prop, an example instruction; the narration is not shown); a hand clicks send and the send button releases the
  Spark, which arcs to the center and spins into a loading ring.
- **DockApp** (1.8-6 s, light): a dock of quiet ghost app tiles with one dashed empty slot; the Spark lands in the slot
  and the product's tile springs out of the impact under the headline ("Nothing new to install."). Optional dive into
  the tile as its color floods the frame.
- **TabClose** (2-6 s, light): a paper browser window with the product open; a new tab springs open, the Spark darts in
  and flicks it shut with a small ripple, under the headline ("Your tabs stay shut.").
- **PhoneFan** (3-8 s, voiceless): the proof. 3 to 5 phones fanned in 3D, each playing a different real output; the fan
  opens, the camera dollies across it and one phone at a time comes forward. The phones show what the product really
  made. Give each clip a start time past its own intro and an end time to hold on, because a phone plays for only about
  a second: a clip played from 0 s reads as an empty phone. Pick those times from a frame strip of each clip.
- **OfferCards** (3.5-9 s, light): one to three paper cards slide up (the featured one inverted in ink, with a "Most
  popular" chip). The camera pushes into it, its checks fill with the accent in a cascade on the narration, and the
  Spark taps its button.
- **PhoneEndCard** (5-12 s): the call to action. A large phone stands on paper, drifting slightly, with a real-size post
  inside and a big headline beside it (above it in 9:16).
  - **Organic:** "Comment KEYWORD" with the keyword in an accent chip, readable for at least 1 s. The Spark
    carries the keyword into the comment box, it is posted, a DM banner drops in and opens ("Here it is: {Name}"), then
    "Follow for the next one." and a tap on Follow. After the last tap the Spark keeps idling in a slow figure-eight
    (about 26 by 14 px): the end card finishes its events early and would otherwise hold a still frame for 2 s.
  - **Sponsored:** a sponsored post with a big call-to-action bar the Spark taps; the URL appears on a link sticker.
  - Show no URL in organic mode and no made-up account handles: the post shows the brand mark and "Original audio".

## 7. Voice

- **The sound:** soft, close, almost ASMR. Low energy, a little breath, unhurried, a small smile. Confident, never an
  announcer. Lines end down, except real questions.
- **Never clone or imitate a real narrator**, including the one in an ad you are studying. Audition 3-4 soft voices
  on two lines of the script and let the user pick, or use the user's own voice.
- **One take per line**, with word timestamps. If the provider allows it, pass the neighboring lines as context so
  the prosody flows. Use moderate stability, no added style and normal speed.
- **Prepare each take:**
  - Trim it to its speech. Ignore the last 80 ms of a decoded mp3, where a click can hold the trim open.
  - Tighten any pause inside the take longer than 0.5 s down to about 0.45 s.
  - Split a take that overruns its beat between two beats instead of making a new take.
- **Punctuation drives the pace.** Every inner full stop adds about a second, and commas can slow a soft voice further.
  Over about 4.2 words per second is too fast for this format.
- **Listen to every take.** Make a second take of any line with a brand name or a number. Check the final mix with
  Whisper line by line.

## 8. Sound

**Effects: make a set for this ad.** Generate them with the sound-effects tool the user chose, or pick from a
licensed library. About 20 sounds cover a whole ad:

| Kind | Prompt idea |
|------|-------------|
| whoosh | a fast airy whoosh passing left to right, clean modern transition |
| swish | a tiny soft swish for text appearing on screen |
| pop, tick | a soft round UI pop; a tiny soft UI tick |
| click | a single crisp computer mouse click, close and dry |
| typing | soft fast typing on a low-profile laptop keyboard, close and dry |
| impact + snap | a punchy low thump with a short snap; a very fast whip swish |
| riser | a smooth synth swell that ends at its peak |
| glitch | a short digital glitch zap |
| chime | a glassy two-note notification chime |
| shimmer | soft sparkle particles for a reveal |
| zoom | a fast zoom-in whoosh into a bright flash |
| paper | sheets of paper fluttering; a page peeled and turned |
| blob, pixels, boing, flare, wind | an organic gloop; pixels scattering; a soft cartoon hop; a warm airy swell; gentle wind over grass |

- **Place a sound on every** entrance with energy, transition, click and impact, at the frame the beat reports.
- **Typing sounds** are only for real typing. Letters popping in one by one get soft ticks.
- **Every impact gets a short snap layered on it**: sub-heavy hits vanish on a phone speaker.
- **The same sound twice within 80 ms**: keep the louder one.
- **Warm, never bright**: low-pass effects to about 1.5-3.5 kHz.
- **Voiceless beats**: turn their effects down about 4 dB, since the voice duck is not holding them.
- **Keep hits off names:** a hit on the first sound of a name can mask it, so nudge it before the word.

**Music: one instrumental bed.** Describe the sound, never an artist: "sleek minimal electronic product-launch bed,
warm sub, soft plucks, slow build, a lift at the reveal, no vocals". Generators ignore requested timestamps, so fit
the track instead:
- Find its real downbeats from bar-to-bar energy jumps (beat trackers often run late on generated music).
- Anchor two moments, for example the groove's entry on the reveal and its return on the showcase.
- Time-stretch to fit, keeping the pitch and staying within about 4 %.
- Splice to the track's ending on a downbeat, so it resolves under the last line.

**Mix, voice first.**
- **Voice:** compress lightly so consonants stay off the limiter; set it at about -14 LUFS.
- **Music:** about 20 LU under the voice while it speaks, lifted about 13 dB in gaps and a little more on voiceless
  beats.
- **Effects:** 8-11 LU under the voice overall, ducked about 6 dB under speech, so no effect masks a call to action.
- **Master:** -14 LUFS integrated, sample-peak ceiling about -2.4 dBFS, limiter gain reduction 3 dB or less. AAC
  encoding adds about 0.8 dB, so check the true peak of the final file.
- **First frame:** a cue whose peak would fall before the film starts begins at its onset instead of losing its attack,
  and the master gets a 10 ms fade-in. Otherwise every view opens on a click.

## 9. Render and QA

1. **Render** each aspect without audio. Mux your own mix onto it, trimmed to the exact length (`-t`, never
   `-shortest`), as H.264 at high quality with AAC 320k and `+faststart`. Never trust a renderer's own audio path.
2. **Sync and length:** the frame count matches the plan. Cross-correlate the muxed audio against your mix: the
   offset is 0 ms.
3. **Contact sheets:** one frame per second, selected by frame number (step 5), with the safe box drawn. Look at every
   sheet: no text cut off or under the platform chrome, no empty or black frames.
4. **Determinism:** render about 10 spread frames twice and diff them; they should match.
5. **Loudness:** -14 LUFS integrated, true peak at or below -1 dBTP.
6. **Words:** transcribe the mix line by line with Whisper. A difference on a plain word is a masked or swallowed word;
   brand names may legitimately differ.
7. **Gaps:** no voice gap over 1.0 s outside the voiceless beat, and no still stretch over 1.2 s.
   - To find stills: scale each frame so its short side is 144 px, convert to luma, take the absolute difference with
     the previous frame, blur it 3x3, and take its maximum.
   - Under 12/255 for more than 36 frames is a still. Grain-only frames count as still; a word landing does not.
   - Test the detector once on a clip you know is still, so you know it can fail.

## 10. Traps

| Symptom | Fix |
|---------|-----|
| A few random frames show text at the wrong size | moving text as HTML, not SVG `<text>`, under per-frame transforms |
| A shape keeps a style from an earlier frame | a negative CSS length was rejected: clamp at 0 |
| The ends of a line peek out from a bar that should cover it | measure the text; never estimate width from character count |
| Text measures wrong | measure only after the fonts load, with the same tracking |
| A headline sits off-center in 9:16 | center on the safe box, not the frame |
| The line is unreadable before the next move starts | give the beat the lead or tail its intro and exit need (step 5) |
| Impacts vanish on a phone | layer a short snap on every impact |
| The music's drop lands late | fit by real downbeats and anchors; do not trust requested timestamps |
| Sound drifts against the picture | mux your own mix with `-t` and check the offset by cross-correlation |
| A camera-move clip does not land where the next beat starts | generate between a first and a last frame |
| A clip's own sound leaks into the mix | plates are silent: the mix supplies every sound |
| The screen shows a name spelled as spoken ("Tide-pool") | keep one spoken word per shown word and show the shown spelling |
| A brand name leaks before a late reveal | give every earlier beat a neutral placeholder name |
| A word hides behind the subject of a plate | keep the subject over a gap between words, or put the headline in front |
| The spark's trail shows corners on fast moves | sample its path a few times per frame |

## 11. Deliver

The MP4 for each aspect, a cover frame, and a ready-to-paste caption. For organic posts the caption repeats the
comment keyword and carries no link.
