Turn a voiceover script into a polished 9:16 motion-graphics ad. This is NOT plain kinetic text —
it layers real footage + animated objects + refined type with depth. Learned across the Ahmad /
Muahib "3 signs your business is invisible" build. Companion skills: use frontend-design and
ui-design-system for design polish, modern-css for CSS. See also the video-ad-concept-editor
skill for the ffmpeg/clip-cutting fundamentals.
Non-negotiable design system (derived from @divyansh.fx_)
| token |
value |
| background |
pure white #ffffff, with faint drifting green rings + green bokeh particles |
| accent |
ONE grass green #16c000 — never a second accent color |
| ink |
#0c0c0d |
| statement type |
heavy grotesque (Segoe UI Black / 900) |
| emphasis type |
italic serif (Georgia italic) on the ONE key word per line, with a green glow (text-shadow:0 0 44px rgba(22,192,0,.5)) |
| motifs |
numbered chips, kinetic word pop-ins (back-ease overshoot), objects that argue the line, hand-drawn ellipse highlight, callback (problems→green checks), brand end card |
The rules that make it look pro (all hard-won from user feedback)
- Objects over text. For each VO line ask "what object shows this?" — a map with your pin missing,
a browser aging into a CLOSED sign, followers-up vs customers-flat. Text = only the emphasis word.
- Cast for the audience. Nigerian client → Nigerian faces. Free green-screen of Black
businesspeople is scarce; reuse the client's own Veo clips as footage layers instead.
- Never a hard cutout. Blend every keyed/framed edge: despill → erode → feather → contact shadow →
(on white) a white light-wrap. The element must SIT in the frame, not on it.
- Never let one clip carry a scene. Multiple assets moving; something always changing.
- Depth + parallax. Layers back→front: rings/glow → blurred footage wash → sharp hero (rises
sharp, recedes+blurs on exit) → bokeh → type. Each layer moves at a different rate.
- Deliberate, UNIFORM composition. Same skeleton every scene (e.g. text top-left, framed
presenter top-right, scene object across the bottom). Respect 9:16 safe margins.
- QC frame-by-frame before shipping (§QC). Every element in-box, no overflow, circle where it
belongs, footage fades when the HTML says so.
Pipeline (local, no network)
tools/html2mp4/render.mjs <html> <out> <frames> <fps> — opaque render (footage inside HTML).
tools/html2mp4/render_alpha.mjs … — transparent render (graphics to overlay on footage). Both
step window.seek(t) per frame and await optional window.__assetsReady.
- Architecture that scales: footage layers in ffmpeg, graphics rendered TRANSPARENT and overlaid
last. One
*_fg.html (transparent: objects+type+frame-ring+bokeh) per scene → render_alpha →
ffmpeg composite white bg + footage wash + framed inset + [alpha graphics] → concat + VO.
- Deterministic HTML: drive everything from
t; no CSS animations / Date.now; call seek(0) at end.
Footage as a layer (two ways)
- Green-screen → key:
chromakey=0xGREEN:0.13:0.05,despill=type=green:mix=0.4,format=yuva420p,split[c0][c1];[c1]alphaextract,erosion,erosion,gblur=sigma=1.1[a];[c0][a]alphamerge then contact shadow alphaextract→gblur=9→black→colorchannelmixer=aa=0.38.
- Non-green client clip (e.g. Veo): crop ABOVE the ✦ watermark (
crop=720:994:0:40), scale, round
with a PIL rounded-rect mask + alphamerge, add contact shadow, overlay; HTML draws a refined frame
ring on top. Also make a blurred wash: boxblur=42,eq=brightness=0.15:saturation=0.5,colorchannelmixer=aa=0.14 so white brand shows through.
Refined framed-inset CSS (premium, not rough)
White 7px border, radius 44 (match the mask), layered shadow with a faint green cast, a top gloss
highlight, a bottom dark scrim gradient for a clean caption (green dot + tracked label). NOT a thick
inset border + muddy gradient bar. Grade the footage eq=brightness=0.02:contrast=1.05:saturation=1.06.
Audio (social spec, verified)
highpass=f=85,afftdn=nr=12:nf=-30,deesser=i=0.4,loudnorm=I=-14:TP=-1.5:LRA=11,alimiter=limit=0.84:level=disabled
(alimiter MUST have level=disabled or it re-normalizes hot). Per-scene VO padded to that scene's exact
video length so audio+graphics stay block-locked. Encode: libx264 crf 17-18, yuv420p, +faststart; aac 192k 48k.
QC — do this every time before calling it done
Extract ~5 frames per scene at the moment each element is fully on; check EACH for: text overflowing
its box (auto-width box x+width must be ≤1080), missing headline (breaks uniformity), an emphasis
circle/underline offset to the wrong place (SVG child positioned relative to its text, not 300px away),
and footage insets that must fade with the HTML (ffmpeg-composited video ignores HTML fades — fade it
in ffmpeg too). Re-transcribe the render; confirm -14 LUFS, A/V drift <2 frames.
Runtime math (say it out loud)
N seconds of VO ≈ N seconds of ad. Hitting a shorter target (e.g. 33s from 41s) means CUTTING spoken
lines and re-timing those scenes' animations — it is a content decision, not a silent speed-up.
1---2name: kinetic-motion-ad3description: Build premium white-background, single-green-accent kinetic-typography motion ads (9:16) with real footage layered behind HTML type — the divyansh.fx_ style. Use when the user wants a "motion graphics ad", "kinetic typography video", "text animation ad", or to turn a voiceover script into a faceless/objects-driven social ad in the workspace under C:\Users\user\Desktop\video-ad. Composites keyed or framed footage (green-screen OR their own Veo clips) with animated HTML/SVG objects, one green accent, italic-serif emphasis, depth/parallax, and a brand end card.4---56Turn a voiceover script into a polished 9:16 motion-graphics ad. This is NOT plain kinetic text —7it layers **real footage + animated objects + refined type** with depth. Learned across the Ahmad /8Muahib "3 signs your business is invisible" build. Companion skills: use `frontend-design` and9`ui-design-system` for design polish, `modern-css` for CSS. See also the `video-ad-concept-editor`10skill for the ffmpeg/clip-cutting fundamentals.1112## Non-negotiable design system (derived from @divyansh.fx_)13| token | value |14|---|---|15| background | pure white `#ffffff`, with faint drifting green **rings** + green **bokeh** particles |16| accent | ONE grass green `#16c000` — never a second accent color |17| ink | `#0c0c0d` |18| statement type | heavy grotesque (Segoe UI Black / 900) |19| emphasis type | **italic serif** (Georgia italic) on the ONE key word per line, with a green **glow** (`text-shadow:0 0 44px rgba(22,192,0,.5)`) |20| motifs | numbered chips, kinetic word pop-ins (back-ease overshoot), objects that *argue* the line, hand-drawn ellipse highlight, callback (problems→green checks), brand end card |2122## The rules that make it look pro (all hard-won from user feedback)231. **Objects over text.** For each VO line ask "what object shows this?" — a map with your pin missing,24 a browser aging into a CLOSED sign, followers-up vs customers-flat. Text = only the emphasis word.252. **Cast for the audience.** Nigerian client → Nigerian faces. Free green-screen of Black26 businesspeople is scarce; **reuse the client's own Veo clips** as footage layers instead.273. **Never a hard cutout.** Blend every keyed/framed edge: despill → erode → feather → contact shadow →28 (on white) a white light-wrap. The element must SIT in the frame, not on it.294. **Never let one clip carry a scene.** Multiple assets moving; something always changing.305. **Depth + parallax.** Layers back→front: rings/glow → blurred footage wash → sharp hero (rises31 sharp, recedes+blurs on exit) → bokeh → type. Each layer moves at a different rate.326. **Deliberate, UNIFORM composition.** Same skeleton every scene (e.g. text top-left, framed33 presenter top-right, scene object across the bottom). Respect 9:16 safe margins.347. **QC frame-by-frame before shipping** (§QC). Every element in-box, no overflow, circle where it35 belongs, footage fades when the HTML says so.3637## Pipeline (local, no network)38- `tools/html2mp4/render.mjs <html> <out> <frames> <fps>` — opaque render (footage inside HTML).39- `tools/html2mp4/render_alpha.mjs …` — **transparent** render (graphics to overlay on footage). Both40 step `window.seek(t)` per frame and await optional `window.__assetsReady`.41- **Architecture that scales:** footage layers in ffmpeg, graphics rendered TRANSPARENT and overlaid42 last. One `*_fg.html` (transparent: objects+type+frame-ring+bokeh) per scene → `render_alpha` →43 ffmpeg composite `white bg + footage wash + framed inset + [alpha graphics]` → concat + VO.44- Deterministic HTML: drive everything from `t`; no CSS animations / Date.now; call `seek(0)` at end.4546## Footage as a layer (two ways)47- **Green-screen → key:** `chromakey=0xGREEN:0.13:0.05,despill=type=green:mix=0.4,format=yuva420p,split[c0][c1];[c1]alphaextract,erosion,erosion,gblur=sigma=1.1[a];[c0][a]alphamerge` then contact shadow `alphaextract→gblur=9→black→colorchannelmixer=aa=0.38`.48- **Non-green client clip (e.g. Veo):** crop ABOVE the ✦ watermark (`crop=720:994:0:40`), scale, round49 with a PIL rounded-rect mask + `alphamerge`, add contact shadow, overlay; HTML draws a refined frame50 ring on top. Also make a **blurred wash**: `boxblur=42,eq=brightness=0.15:saturation=0.5,colorchannelmixer=aa=0.14` so white brand shows through.5152### Refined framed-inset CSS (premium, not rough)53White 7px border, radius 44 (match the mask), layered shadow with a faint green cast, a top gloss54highlight, a bottom dark scrim gradient for a clean caption (green dot + tracked label). NOT a thick55inset border + muddy gradient bar. Grade the footage `eq=brightness=0.02:contrast=1.05:saturation=1.06`.5657## Audio (social spec, verified)58`highpass=f=85,afftdn=nr=12:nf=-30,deesser=i=0.4,loudnorm=I=-14:TP=-1.5:LRA=11,alimiter=limit=0.84:level=disabled`59(alimiter MUST have `level=disabled` or it re-normalizes hot). Per-scene VO padded to that scene's exact60video length so audio+graphics stay block-locked. Encode: libx264 crf 17-18, yuv420p, +faststart; aac 192k 48k.6162## QC — do this every time before calling it done63Extract ~5 frames per scene at the moment each element is fully on; check EACH for: text overflowing64its box (auto-width box x+width must be ≤1080), missing headline (breaks uniformity), an emphasis65circle/underline offset to the wrong place (SVG child positioned relative to its text, not 300px away),66and footage insets that must fade with the HTML (ffmpeg-composited video ignores HTML fades — fade it67in ffmpeg too). Re-transcribe the render; confirm -14 LUFS, A/V drift <2 frames.6869## Runtime math (say it out loud)70N seconds of VO ≈ N seconds of ad. Hitting a shorter target (e.g. 33s from 41s) means CUTTING spoken71lines and re-timing those scenes' animations — it is a content decision, not a silent speed-up.