Internal Playbook · v1.0

Building a Cinematic AI‑Avatar Promo — end to end, for any client

A step‑by‑step operating manual written for an AI agent. Feed this to a capable agent with tool access and it should reproduce the entire pipeline — script → cloned voice → talking mascot → b‑roll → logo sting → final edit — on the first pass, avoiding every mistake we made learning it the hard way.

Generation: Higgsfield Voice: seed_speech clone Lip‑sync: Wan 2.7 B‑roll: Nano Banana → Kling 3.0 Editor: FFmpeg (100% scriptable) Output: ~50–60s, 1280×720, 30fps

Worked example throughout: Etari Digitals (Google‑Ads agency; mascot “Leo” the lion in the founder’s cloned voice). Replace every [BRACKET] with the new client’s details.

Contents

  1. How to use this document
  2. The Golden Rules (read first)
  3. The Mistake Log
  4. Pipeline overview & the 4‑layer method
  5. Tool stack & model IDs
  6. Phase 1 — Discovery & the script
  7. Phase 2 — Mascot & reusable Element
  8. Phase 3 — Clone the founder’s voice
  9. Phase 4 — Generate the VO
  10. Phase 5 — Talking mascot (lip‑sync)
  11. Phase 6 — B‑roll (dashboards, website, scenes)
  12. Phase 7 — Logo animation
  13. Phase 8 — Master the audio
  14. Phase 9 — THE EDIT, in FFmpeg
  15. Phase 10 — Captions, QA & delivery
  16. Credit budget & cost
  17. Troubleshooting quick‑reference

1 · How to use this document

You are an AI agent with tool access (a Higgsfield connector or equivalent generation API, a shell with ffmpeg/ffprobe/curl, and the ability to view images). Your job: produce one finished promo video for [CLIENT].

Why FFmpeg is the editor The original build used DaVinci Resolve driven over an MCP bridge. It fought us constantly: it needs the desktop app running, macOS permission dialogs silently hang it, and the “current project” kept switching out from under us (New Project 6/8/9…), losing the edit. None of that can happen with FFmpeg. It is a pure command‑line tool: deterministic, no GUI, no app state, no permissions, runs anywhere. An AI can express the entire edit as text and reproduce it byte‑for‑byte. That is exactly what you want. (If you later need fancy animated captions/charts, render those in Remotion — React‑as‑video — and composite with FFmpeg; but the core edit below is 100% FFmpeg.)

2 · The Golden Rules

R1 The VO audio is the master clock. Everything is built to the voice and cut on top of a single continuous voice track. Generate video to fit audio — never try to stretch/re‑time audio to fit a video.
R2 The lip‑sync model degrades audio. Use its video only. Wan 2.7 bakes a hissy re‑synthesised audio track (a noise band ~12–17 kHz + a raised floor). Take the picture from Wan and keep the clean generated VO as your audio. Never ship Wan’s audio.
R3 AI can’t spell. Keep text out of the model, or use the real thing. Generated dashboards/websites produce gibberish text. For dashboards use few, big, legible numbers (Nano Banana Pro handles a handful). For the client’s website use real screenshots animated with an FFmpeg push‑in, never an AI re‑draw.
R4 Always force -ar 48000 on any FFmpeg audio step. loudnorm silently resamples to 96 kHz internally and, if you don’t pin the rate, you get click/glitch artifacts downstream. 48 kHz everywhere.
R5 Get the real logo from the client’s site, not a re‑draw. Recreating a brand mark with a generator changes it (wrong leaf, wrong shape). Pull the actual asset file (e.g. /assets/logo-mark.png) and upscale it.
R6 Decline the preset hijack. Kling/Wan prompts that mention “dark” or “render” get auto‑swapped to a marketplace preset (“IN THE DARK”, “3D RENDER”). Pass declined_preset_id to generate your literal prompt.
R7 Look at every asset before you use it. View one frame of every clip; measure every audio file. This single habit would have caught 80% of our reworks.
R8 30 fps, 1280×720, everywhere. Every generated clip, every render. Mixed frame rates and resolutions cause sync drift and scaling mush.

3 · The Mistake Log

Every one of these cost us time on the Etari build. The rules above exist because of them. Read them so you don’t repeat them.

What we did wrongSymptomDo this instead
Used ElevenLabs / seed_audio for the founder VOVoice sounded flat/robotic; lost the founder’s charactertext2speech_v2 + variant seed_speech with an element (cloned) voice. Nothing else.
Used Wan 2.7’s output audio in the cutHissy, “glitchy/distorted” voice on the timeline; clean render only proved the source was fineUse Wan clips video‑only; lay the clean generated VO underneath.
Generated a text‑heavy dashboard / website with the modelGibberish numbers and warped wordsDashboards: 3 big legible KPIs max. Website: real screenshot + FFmpeg push‑in.
Ran loudnorm without pinning sample rateClicks/pops after import; audio silently at 96 kHzAlways end audio filters with -ar 48000.
Let Kling auto‑apply a presetVideo came out as an unrelated “3D render in the dark”Pass declined_preset_id from the recommendation notice.
Re‑drew the client logo with a generatorClose but wrong — altered leaf/shape; not brand‑exactDownload the real logo-mark.png from the site; upscale to 4K.
Padded a composited logo with a guessed background colourVisible seam/rectangle around the logoSample the exact bg pixel and pad with that hex.
Tried to re‑sync a fresh continuous VO read to existing lipsImpossible to line up word‑for‑word; drift everywhereEither regenerate the mascot to the new audio (Wan), or restore the original synced audio in place. Don’t fight two different takes.
Assumed a clip’s duration = its video lengthBeats had video = N.0s but audio = N.1s (a 0.1s tail)Confirm both streams with ffprobe. The tail is silence — safe to truncate.
Inferred generation cost from the credit ledgerEstimates off by 3×Use the get_cost preflight; it’s free and exact.
Drove the edit through DaVinci over MCPApp hung on permission dialogs; the “current project” switched away and lost workEdit in FFmpeg. No app, no state, deterministic.

4 · Pipeline overview & the 4‑layer method

You are producing a ~50–60 second promo: a branded mascot (in the founder’s real cloned voice) delivers a tight 6‑beat pitch, and you cut fast (every ~2–3s) between the talking mascot and supporting visuals. You do not generate 2–3s clips. You generate a few longer pieces and cut between them in the edit, with the VO running continuously underneath. Four layers stack on the voice:

LayerWhatMade with
BASEMascot talking — one clip per script beat, lip‑synced to the founder’s voiceWan 2.7 (video) + seed_speech VO
B‑ROLLGrounded scenes: results dashboard, the client’s website, “work happening”Nano Banana Pro keyframe → Kling 3.0; real screenshots via FFmpeg
MOTION GFXOptional: animated numbers, labels, lower‑thirds, captionsFFmpeg drawtext / burned subtitles (or Remotion for fancy)
LOGOA premium logo sting (intro or outro)Real logo → 4K upscale → Kling 3.0

The 6‑beat script skeleton (proven structure): 1) HOOK — a sharp reframe of the problem · 2) PROBLEM — the pain, concretely · 3) SOLUTION — how [CLIENT] is different · 4) PROOF — the dashboard / results · 5) ALT‑OFFER — a secondary path (e.g. DIY) · 6) CTA — the ask + where to go.

5 · Tool stack & model IDs

JobModel / toolNotes
Character & b‑roll keyframesnano_banana_2 (Nano Banana Pro)~1.5–2 cr/image. Best at legible text. Restate the design every prompt.
Reusable characterElement (workspace reference)Create once; embed as <<<element_id>>> in prompts for consistency.
Voice clonetext2speech_v2, variant seed_speech, voice_type:elementThe only acceptable VO path. Outputs 24 kHz mono (fine for speech).
Talking mascot (lip‑sync)wan2_7, 720p~1.5 cr/sec. start_image=keyframe, audio_references=VO. Duration = audio length (max 15s/clip).
B‑roll motionkling3_0, 720p~10 cr / 5s. Image‑to‑video. Pass declined_preset_id.
Upscale (logo)upscale_image (bytedance), 4KFlat cost. Requires source width/height.
Assemble / audio / captionsFFmpeg + FFprobeThe editor. 100% scriptable.
Fetch real assets (logo, screenshots)Headless browser (Playwright)Read the DOM to find the true asset URLs; screenshot at device scale.

6 · Phase 1 — Discovery & the script

Gather (real data only)

Write the 6‑beat script

Tight, spoken, ~50–55s total. Short sentences. One idea per beat. Write it as 6 blocks; each block becomes one VO generation and one BASE mascot clip. Example (Etari):

1 HOOK     "Most businesses don't have an ad problem. They have an agency problem."
2 PROBLEM  "You pay an agency, your account lands on a junior's desk, and once a month you get a pretty PDF."
3 SOLUTION "At Etari Digitals, we do it differently. Every account is run by a founder. No juniors, no handoffs. Google Ads and SEO built as one system, so your ad spend stops being a cost and starts being an asset."
4 PROOF    "And you're never left guessing. Every client gets a live dashboard: spend, revenue, ROAS, profit, all in one place, in real time. No black box."
5 ALT      "Prefer to run it yourself? Our DIY package hands you the exact systems we use internally. Same playbook, your hands on the wheel."
6 CTA      "Want to know what's leaking in your account? We'll audit it free, within 48 hours. Check out the website, link in our bio."
QA gate 1 Read the script aloud (or TTS a throwaway pass). If any beat runs over ~14s, split it — Wan caps a single lip‑sync clip at 15s.

7 · Phase 2 — Mascot & reusable Element

Design the mascot once, lock it forever

Write a canonical design sentence and reuse it verbatim in every prompt. Example: “Anthropomorphic muscular lion, golden‑tan fur, teal‑and‑green mane with a green leaf tuft on top; wears a dark navy athletic polo with thin gold trim and NO text; flat 2D cartoon, bold black line art, cel‑shaded.”

  1. Generate the mascot head‑on keyframe with nano_banana_2 using the canonical sentence.
  2. Create an Element from that image (a workspace “reference character”). You now have an element_id.
  3. In every later prompt, embed the mascot as <<<element_id>>> and still restate the design sentence — belt and suspenders keep it on‑model.
  4. Generate the mascot’s set/environment keyframe (the “studio”). For Etari: a dark broadcast studio — charcoal acoustic panels, two vertical white LED strips, a glossy white desk. Save this frame; it is your consistency anchor.
Consistency trick To make new angles that match an existing shot’s environment, pass a frame from the actual video as a reference image and prompt “keep the exact same set/lighting/character, only change the camera angle.” This is how you get true side/close‑up shots in the same studio instead of a random office.

8 · Phase 3 — Clone the founder’s voice

Hard rule The voice is the single most important authenticity asset. Founder‑led promos live and die on it being the founder’s actual voice. Use only the path below.
  1. Upload the founder’s clean voice sample.
  2. Create a voice element (clone) from it. You get a voice_id (element).
  3. Do a 5–10 word test generation and listen. If it’s muddy, re‑clone from a cleaner/denoised sample.

The exact VO call (do not deviate)

generate_audio(
  model      = "text2speech_v2",
  variant    = "seed_speech",          # NOT elevenlabs, NOT seed_audio, NOT vibe_voice
  voice_type = "element",
  voice_id   = "[FOUNDER_VOICE_ELEMENT_ID]",
  prompt     = "<the beat's text>"
)
VariantVerdict
seed_speechUSE THIS. Preserves the voiceprint. 24 kHz mono — perfectly fine for speech (telephone is 8 kHz; broadcast ~16–24 kHz).
elevenlabs❌ Flattens the founder’s voice. Rejected.
seed_audio❌ 24 kHz “robotic”. Rejected.
voice_change (post‑hoc)❌ Glitchy. Rejected.

9 · Phase 4 — Generate the VO

QA gate 4 Listen to all 6. Confirm it’s the founder and the delivery is right before you spend credits animating them.

10 · Phase 5 — Talking mascot (lip‑sync)

For each beat: animate the mascot keyframe to that beat’s VO with Wan 2.7. The mouth is driven by the audio’s phonemes → real lip‑sync.

The Wan call

generate_video(
  model      = "wan2_7",
  resolution = "720p",
  duration   = <seconds of that beat's VO>,     # 2–15
  aspect_ratio = "16:9",
  medias = [
     { value: "[MASCOT_KEYFRAME_ID]",  role: "start_image" },
     { value: "[BEAT_VO_MEDIA_ID]",    role: "audio_references" }
  ],
  declined_preset_id = "[the id from the preset notice, if any]",
  prompt = "The character speaks to camera, natural mouth movements lip-synced to the audio, subtle head/shoulder motion, staying in the same set. Keep the exact character, framing, lighting. Do not distort."
)
Critical (R2) Wan’s output contains audio, and that audio is degraded (a re‑synth noise band ~12–17 kHz + a raised floor). Discard it. When you edit, take Wan clips as video‑only and lay your mastered VO underneath. Proof for yourself: render a spectrogram of a Wan clip’s audio vs the raw VO — you’ll see the noise band.
ffmpeg -i beat3_wan.mp4 -lavfi showspectrumpic=s=1000x400:legend=1 spec_wan.png
ffmpeg -i vo/raw_beat3.mp3 -lavfi showspectrumpic=s=1000x400:legend=1 spec_raw.png
# open both; the Wan one has a hazy 12-17kHz band the raw one doesn't.

You now have 6 BASE clips (mascot talking, video‑only usable). Optionally generate 1–2 alternate angles (a tighter dead‑on close‑up, a true side profile) using the “same set, change the angle” trick — these give you free cutaways/jump‑cuts in the edit.

11 · Phase 6 — B‑roll

A) Results dashboard (the PROOF beat)

Generate a photorealistic, minimal dashboard with only a few big, legible KPIs. Fewer elements = zero gibberish. Blur/redact any client name.

generate_image(
  model="nano_banana_2", aspect_ratio="16:9", count=2,
  prompt="Photorealistic clean MINIMAL marketing results dashboard on a monitor in a bright modern office.
          Only THREE big bold legible KPI cards: 'ROAS 6.4x', 'Revenue EUR 41,900', 'Leads +228%',
          and one simple upward green line chart. No tiny cluttered text anywhere.
          The account name at the top is hidden behind a solid grey privacy blur bar. Crisp, credible."
)
Client names The dashboard must never show a real, identifiable client. Use a blur bar or “[CONFIDENTIAL]”. Verify by viewing the frame.

Then animate the keyframe (subtle push‑in) with Kling — the on‑screen numbers must stay static/legible:

generate_video(model="kling3_0", duration=5, aspect_ratio="16:9",
  declined_preset_id="[preset id if notice fires]",
  medias=[{value:"[DASH_KEYFRAME_ID]", role:"start_image"}],
  prompt="Subtle slow cinematic push-in on the monitor. Dashboard numbers/chart stay perfectly static and legible. Gentle camera drift, soft background office movement.")

B) The client’s website (real screenshot + FFmpeg push‑in)

Never AI‑redraw a website The pricing/nav text will warp. Use the real page.
  1. Open the site in a headless browser; screenshot the relevant section at device scale (or zoom the element up first for a crisp capture). Save a tall PNG.
  2. Animate it with a pure‑FFmpeg push‑in (Ken Burns). Text stays pixel‑perfect:
# slow 5s push-in on a cropped 16:9 region of the screenshot, 720p
ffmpeg -loop 1 -i site_packages.png -t 5 -r 30 \
  -vf "crop=1920:1080:0:400,scale=3840:2160,\
zoompan=z='min(zoom+0.0007,1.11)':d=150:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=1280x720:fps=30,\
format=yuv420p" \
  -c:v libx264 -crf 18 -pix_fmt yuv420p broll/web_packages.mp4

C) Scene b‑roll (people/work)

Grounded, believable scenes (someone reviewing dashboards, a team at a desk). Nano Banana keyframe → Kling motion, sound:off. Keep it bright and real — not dark/surreal.

QA gate 6 View a mid‑frame of every b‑roll clip. Check: numbers legible, no gibberish, no warped text, no real client name, 1280×720, 30 fps.

12 · Phase 7 — Logo animation

  1. Get the REAL logo (R5). Open the site in a headless browser and read the DOM for the true asset URL — usually something like /assets/logo-mark.png — and download it. Also capture the wordmark: it’s often live HTML text, so zoom the header element up (e.g. transform:scale(6)) and screenshot at device scale for a razor‑sharp wordmark.
  2. Upscale the mark to 4K (upscale_image, provide source w/h).
  3. Compose a seamless 16:9 frame. Sample the exact background pixel and pad with that hex (R‑“seam”). Center the lockup:
# sample the exact bg colour from a corner, then pad with it (no seam)
read R G B < <(ffmpeg -i logo_4k.png -vf "crop=8:8:2:2,scale=1:1,format=rgb24" -f rawvideo - 2>/dev/null | od -An -tu1 | awk '{print $1,$2,$3}')
HEX=$(printf "0x%02X%02X%02X" "$R" "$G" "$B")
ffmpeg -i logo_4k.png -vf "crop=W:H:X:Y,scale=1560:-1,pad=1920:1080:(ow-iw)/2:(oh-ih)/2:color=$HEX,format=rgb24" logo/logo_frame.png
  1. Animate with Kling — insist the logo stays crisp and un‑warped:
generate_video(model="kling3_0", duration=5, aspect_ratio="16:9",
  declined_preset_id="[preset id — the word 'dark' triggers 'IN THE DARK']",
  medias=[{value:"[LOGO_FRAME_ID]", role:"start_image"}],
  prompt="Elegant premium logo sting. The logo (emblem + wordmark) stays perfectly sharp, centered, undistorted.
          Subtle only: a soft golden light-glint sweeps left to right, a gentle glow pulse, faint drifting particles, a very slow zoom-in.
          The logo and text must NOT warp, morph, or change shape.")
QA gate 7 View start/mid/end frames. Confirm the mark and wordmark are intact through the whole clip.

13 · Phase 8 — Master the audio

Build ONE continuous VO track from the 6 raw beat clips, then master it. This mastered track is the audio bed for the whole film.

# 1) concat the 6 raw VO clips in order (they are the clean source)
printf "file '%s'\n" vo/raw_beat1.wav vo/raw_beat2.wav ... > vo/list.txt
ffmpeg -f concat -safe 0 -i vo/list.txt -c:a pcm_s24le -ar 48000 -ac 2 vo/bed_raw.wav

# 2) master it — the proven chain. ALWAYS end with -ar 48000 (R4).
ffmpeg -i vo/bed_raw.wav \
  -af "highpass=f=75,equalizer=f=2800:width_type=q:width=1:g=2,\
equalizer=f=10000:width_type=q:width=1:g=4,deesser,\
acompressor=threshold=-18dB:ratio=2:attack=5:release=50,\
loudnorm=I=-16:TP=-1.5:LRA=11" \
  -ar 48000 -ac 2 -c:a pcm_s24le vo/bed_master.wav
If you must clean a degraded voice track (e.g. you already baked Wan audio somewhere and can’t regenerate): low‑pass out the noise band, gentle denoise, de‑ess — timing is preserved so sync is untouched:
ffmpeg -i dirty.wav -af "highpass=f=75,lowpass=f=12000,afftdn=nr=12:nf=-30,deesser" -ar 48000 -ac 2 -c:a pcm_s24le clean.wav
Verify by comparing spectrograms before/after — the >12 kHz haze should be gone and the gaps darker.

14 · Phase 9 — THE EDIT, in FFmpeg

This is the part DaVinci made miserable. In FFmpeg it is a deterministic script. The model: V1 = the 6 BASE mascot clips concatenated end‑to‑end (video‑only); b‑roll overlays on top at chosen times with crossfades; the mastered VO is the audio. Cut ≈ every 2.5s by choosing when b‑roll covers the mascot.

Step 1 — normalise every clip to 1280×720 / 30fps, video‑only

norm(){ ffmpeg -y -i "$1" -an -r 30 -vf "scale=1280:720:force_original_aspect_ratio=increase,crop=1280:720,format=yuv420p" -c:v libx264 -crf 18 "$2"; }
norm leo/01_beat1.mp4 work/b1.mp4   # ... repeat for all beats and all b-roll

Step 2 — build the BASE spine (concat the beats)

printf "file '%s'\n" work/b1.mp4 work/b2.mp4 work/b3.mp4 work/b4.mp4 work/b5.mp4 work/b6.mp4 > work/base.txt
ffmpeg -f concat -safe 0 -i work/base.txt -c copy work/base.mp4   # this is the mascot, continuous

Step 3 — overlay b‑roll with smooth crossfades

Decide a cut map: for each b‑roll clip, a start second and a duration on the timeline. Overlay each on top of BASE with a short alpha fade in/out so cuts dissolve. Pattern for one overlay (repeat/chain per clip, or script it):

# overlay web_packages from t=22s for 4s, with 8-frame dissolves
ffmpeg -i work/base.mp4 -i work/web_packages.mp4 -filter_complex "\
 [1:v]trim=0:4,setpts=PTS-STARTPTS,fade=t=in:st=0:d=0.27:alpha=1,fade=t=out:st=3.73:d=0.27:alpha=1[ov];\
 [0:v][ov]overlay=enable='between(t,22,26)':x=0:y=0[v]" \
 -map "[v]" -c:v libx264 -crf 18 -pix_fmt yuv420p work/base_1.mp4
# chain the next overlay onto work/base_1.mp4, and so on.

For many overlays, generate this chain programmatically from a cut‑map array (each entry: file, t_start, dur). Keep the VO’s beat boundaries in mind so b‑roll lands on the right words.

Step 4 — lay the mastered VO + optional music, and mux

# video = the fully overlaid picture; audio = mastered VO (+ ducked music bed if you have one)
ffmpeg -i work/picture.mp4 -i vo/bed_master.wav -i music.mp3 -filter_complex "\
 [2:a]volume=0.12,afade=t=out:st=52:d=3[mus];\
 [1:a][mus]amix=inputs=2:duration=first:dropout_transition=0[a]" \
 -map 0:v -map "[a]" -c:v copy -c:a aac -b:a 256k -ar 48000 -shortest out/promo_v1.mp4
Why this is bulletproof Every operation is text. Re‑running the script reproduces the exact film. There is no “current project”, no app, nothing to lose. To revise, change one number in the cut‑map and re‑run.

15 · Phase 10 — Captions, QA & delivery

Burned captions (optional, cheap, high‑impact)

You already have the exact script per beat and each beat’s start time. Emit an .srt from those, then burn it:

ffmpeg -i out/promo_v1.mp4 -vf "subtitles=captions.srt:force_style='Fontname=Arial,Fontsize=22,Bold=1,PrimaryColour=&Hffffff&,Outline=2,Shadow=0,MarginV=48'" -c:a copy out/promo_captioned.mp4

For word‑by‑word / animated captions, render them in Remotion and overlay the transparent caption layer with FFmpeg.

Final QA gate (do all of these)

# safe delivery encode
ffmpeg -i out/promo_captioned.mp4 -c:v libx264 -profile:v high -pix_fmt yuv420p -crf 19 -c:a aac -b:a 256k -ar 48000 -movflags +faststart out/FINAL_[CLIENT]_promo.mp4

16 · Credit budget & cost

On the plan we used, credits cost about $0.05 each (a 1,000‑credit top‑up was $49; auto‑refill runs 18 credits/$1). The entire Etari build — including all the failed experiments while learning — came to ~860 credits ≈ $43. A clean first‑go run following this guide should be well under half that.

ItemQty~Credits
Mascot + set keyframes~4~8
Voice clone (element)1~40
seed_speech VO (6 beats)6~2
Wan lip‑sync BASE clips~7~85
B‑roll keyframes + Kling motion~8~55
Logo: upscale + Kling sting2~12
Website / real footage / FFmpeg edit0
Clean‑run total~200 (≈ $10)
Credit safety Preflight every paid gen with the cost tool (free, exact — don’t infer from the ledger). If the balance nears the auto‑refill threshold (~300 on our account) it will charge automatically (~$21). Watch it.

17 · Troubleshooting quick‑reference

SymptomCauseFix
Voice sounds flat / not the founderWrong variantOnly text2speech_v2 + seed_speech + element voice.
Voice hissy/“distorted” on the timelineUsing Wan’s baked audioUse Wan video‑only; lay the mastered VO under it.
Clicks/pops in exported audioloudnorm resampled to 96 kHzEnd every audio step with -ar 48000.
Dashboard/site text is gibberishModel can’t spell dense text≤3 big KPIs; real screenshots for websites.
Video came out as a random “3D render / in the dark”Preset auto‑appliedPass declined_preset_id.
Logo looks “close but wrong”AI re‑drawDownload the real asset; upscale it.
Rectangle/seam around composited logoGuessed pad colourSample the exact bg pixel; pad with that hex.
Lips don’t match a new VO readTwo different takesRegenerate mascot to the new audio (Wan), or keep the original synced audio. Don’t re‑time a different read.
Delivered file won’t open on a normal PCExotic codec (YUV 422 10‑bit in MP4)Deliver H.264/AAC MP4.
Sync drifts across the filmMixed fps/resNormalise everything to 1280×720 / 30 fps first.
The one‑paragraph version Write a 6‑beat script → clone the founder’s voice with seed_speech → generate 6 VO clips → animate the mascot to each with Wan (keep video only) → make b‑roll (few‑number dashboards, real‑screenshot websites, grounded scenes) → get the real logo, upscale, animate → master ONE continuous VO with the fixed FFmpeg chain (-ar 48000!) → in FFmpeg, concat the mascot beats, overlay b‑roll with crossfades, lay the VO, burn captions → export H.264. Look at and listen to everything before you use it. Decline the presets. That’s the whole film.