Loading...
Loading...
This skill should be used when the user asks to "make a video ad", "create an animated ad", "build a performance/UGC-style ad", "batch-produce ad creative variations", "generate ad variants for A/B testing", "swap headline/offer/CTA across many ad versions", or "export one ad in multiple aspect ratios for Meta/TikTok/Reels". Covers ad hook structures, hook→CTA message-match, data-driven variant generation (1 template × CSV = N ads), multi-aspect export, and platform specs.
npx skill4agent add iart-ai/ad-video-skills ad-creative-video| Beat | Job | Budget |
|---|---|---|
| Hook (0–3s) | Stop the scroll; state the problem or pattern-interrupt | 0–3s |
| Context | Make the viewer feel the problem / agitate | 3–8s |
| Payoff | Show the product as the solution, one clear benefit | 8–18s |
| Proof | One concrete number, demo, or result | 18–25s |
| CTA (last 3s) | Single action, message-matched to the hook | hold ≥2s |
| Hook type | Template | When it wins |
|---|---|---|
| Problem-first | "I didn't realize how much X was costing me until…" | pain is felt but unnamed |
| Pattern interrupt | "This is going to sound controversial, but…" | crowded feed, generic category |
| Curiosity gap | "Nobody talks about the one thing that…" | educated, skeptical audience |
| Immediate benefit | "Cut your X in half in 7 days" | clear, quantifiable outcome |
| Direct callout | "If you do X every morning, stop." | sharp audience segment |
variantuseCurrentFrame()import {useCurrentFrame, interpolate, AbsoluteFill, useVideoConfig} from "remotion";
type Variant = {hook: string; benefit: string; proof: string; cta: string; bg: string; accent: string};
export const AdTemplate: React.FC<{v: Variant}> = ({v}) => {
const frame = useCurrentFrame(); const {fps} = useVideoConfig();
const hookIn = interpolate(frame, [0, 8], [40, 0], {extrapolateRight: "clamp"});
const ctaIn = interpolate(frame, [fps * 22, fps * 23], [0, 1], {extrapolateLeft: "clamp", extrapolateRight: "clamp"});
return (
<AbsoluteFill style={{background: v.bg, fontFamily: "Inter, sans-serif"}}>
<h1 style={{transform: `translateY(${hookIn}px)`, opacity: interpolate(frame,[0,8],[0,1])}}>{v.hook}</h1>
{frame > fps * 8 && <p>{v.benefit}</p>}
{frame > fps * 18 && <strong>{v.proof}</strong>}
<button style={{opacity: ctaIn, background: v.accent}}>{v.cta}</button>
</AbsoluteFill>
);
};references/batch-ad-pipeline.md# variants.csv: id,hook,benefit,proof,cta,bg,accent → one MP4 per row
node csv-to-props.js variants.csv ./props # writes props/<id>.json per row
for f in props/*.json; do
id=$(basename "$f" .json)
npx remotion render AdTemplate "out/${id}.mp4" --props="$f"
donereferences/batch-ad-pipeline.md| Aspect | Placements | Resolution | Keep-clear safe zone |
|---|---|---|---|
| 9:16 | Reels, Stories, TikTok In-Feed | 1080×1920 | top ~14%, bottom ~20–35% (UI/caption), sides ~6% |
| 4:5 | Meta Feed (best feed real estate) | 1080×1350 | center 90%; CTA out of bottom 10% |
| 1:1 | Feed, broad reach | 1080×1080 | center square survives every crop |
| 16:9 | YouTube, in-stream | 1920×1080 | center 90% |
for ar in 9x16 4x5 1x1; do
npx remotion render AdTemplate "out/${id}-${ar}.mp4" --props="props/${id}.json" \
--props-merge="{\"aspect\":\"${ar}\"}"
donereferences/platform-specs.mduseCurrentFrame()Packaged helper (): tile your stills withscripts/, then assert the encode withscripts/contact-sheet.sh sheet.png f-hook.png f-mid.png f-end.png. Seescripts/probe-mp4.sh out.mp4 [WxH] [fps].scripts/README.md
<Composition>schemadefaultPropsDate.now()Math.random()out/*.mp4defaultProps# Frame-exact stills across the hook→CTA arc, with a real variant's props
npx remotion still AdTemplate out/f-hook.png --frame=12 --props=props/v1.json # hook readable < 2s
npx remotion still AdTemplate out/f-mid.png --frame=300 --props=props/v1.json # benefit/proof
npx remotion still AdTemplate out/f-cta.png --frame=689 --props=props/v1.json # CTA, message-matched
# inspect each: fidelity (hook / offer / proof / CTA text exact, brand bg+accent right)
# AND artifacts (text overflow, off-canvas, CTA inside the 9:16 bottom third, missing font, wrong row binding)for ar in 9x16 4x5 1x1; do # one representative variant, every target aspect
npx remotion still AdTemplate "out/v1-${ar}.png" --frame=300 \
--props=props/v1.json --props-merge="{\"aspect\":\"${ar}\"}"
done
# stills clean in all aspects? → then batch-render every row × aspect:
for f in props/*.json; do id=$(basename "$f" .json); for ar in 9x16 4x5 1x1; do
npx remotion render AdTemplate "out/${id}-${ar}.mp4" --props="$f" --props-merge="{\"aspect\":\"${ar}\"}"
done; done
npx remotion render AdTemplate out/demo.gif --codec=gif --props=props/v1.json # README demonpx remotion stillDate.now()Math.random()defaultPropsreferences/batch-ad-pipeline.mdreferences/platform-specs.md