B-Roll Video Overlay

Broll overlay

by novoads · MIT license · ★ 23 on GitHub

Broll overlay cover

Overlays silent b-roll cutaway clips onto a finished base video — the base audio keeps running underneath while the picture cuts away and returns, and the final duration always equals the base duration. Use when the user asks to add…

---
name: broll-overlay
metadata: {packVersion: 1.3.0}
description: >-
  Overlays silent b-roll cutaway clips onto a finished base video — the base
  audio keeps running underneath while the picture cuts away and returns, and
  the final duration always equals the base duration. Use when the user asks to
  add b-roll, add cutaways, or overlay clips on a video: "add b-roll to this",
  "cut away to a product shot here", "overlay these clips on my UGC ad". Entered
  from an approved base video plus its transcript, which comes from
  POST /v1/transcripts and needs no local install; it never generates the base
  itself and it never extends a video.
---

# B-roll overlay

Lays silent cutaway clips **over** a finished base video: the base audio runs
untouched underneath, the picture cuts away and returns, and the final duration

Overview

Lays silent cutaway clips over a finished base video: the base audio runs untouched underneath, the picture cuts away and returns, and the final duration equals the base duration exactly. That is the whole contract — overlay, never concatenation. A previous run concatenated: 24s for a 15s base, voice dead 12s.

Manual install (npx, ZIP)
Claude Codenpx skills add novoads/agent-skills --skill broll-overlay -g -a claude-code
Claude Code (degit)npx degit novoads/agent-skills/shared/skills/broll-overlay#main ~/.claude/skills/broll-overlay
Claude.ai / desktopZip the folder and upload it under Settings → Capabilities → Skills.
Codex, Cursor, other agentsPoint them at SKILL.md. The other files are plain text.

Connects with Agent Alley MCP · agentalley.io/mcp

Files included

  • SKILL.md9.4 KB
Read SKILL.md here
novoads/main1 file shown
SKILL.md
Show the full text164 lines

B-roll overlay

Lays silent cutaway clips over a finished base video: the base audio runs untouched underneath, the picture cuts away and returns, and the final duration equals the base duration exactly. That is the whole contract — overlay, never concatenation. A previous run concatenated: 24s for a 15s base, voice dead 12s.

Assembly mechanics live entirely in scripts/broll_overlay.py; this file is judgment only — when to enter, where the windows go, what the user sees first.

Entry condition

Two things must already exist. This skill never generates the base — if there isn't one yet, say so and stop.

  1. A finished, approved base video with exactly one audio stream. Approved means the user has watched it and signed off — b-roll is a polish pass over a locked cut. The script stream-copies one voice track under the picture, so a two-stream base is rejected: ffmpeg -i base -map 0:v -map 0:a:0 -c copy.

  2. Its transcript, with timings. One call to POST /v1/transcripts with the base's jobId (or its assetId if it was uploaded). It returns text, word-level words[] and segments[] — timings in SECONDS, which is what the EDL below takes — plus an srt you can ignore here. Price it with the transcript arm of POST /v1/estimates and quote that number, never one from this file. The meter is per minute of source, rounded up from a one-minute minimum, and a repeat of the same source is free, so asking twice costs once. No local install.

    (The captions endpoint still cannot supply this — it burns subtitles into a new MP4 and returns no text or timings, verified 2026-08-04 and re-checked when transcripts shipped. That finding is correct and is kept here so nobody re-discovers it and files a bug against captions.)

    Offline fallback: a local whisper pass (whisper-cli or openai-whisper) still works and is the path when there is no API key or no network. Note whisper reports timings in milliseconds where the API reports seconds, and whisper-cli with no model downloaded returns an EMPTY transcript rather than an error — which reads exactly like a bad render. See README for the model download.

    Placement is read from the transcript, not eyeballed.

REST key required. A Novoads MCP connector is not a substitute. If NOVOADS_API_KEY is missing or still the placeholder, stop before any generation work and tell the user: "Before continuing, create an API key at https://novoads.ai/dashboard/settings?tab=api and paste it into .env." That holds even when mcp__novoads__* tools are connected and authenticated in the session. Never call mcp__novoads__* tools from this repo's workflows: they are a different surface with different behavior, including the units they quote costs in. Repo installs verify with ./scripts/check-novoads-env.sh; a solo install checks NOVOADS_API_KEY in the environment.

Pack version. Every /v1 response carries X-Novoads-Pack-Version; mention a newer pack at https://github.com/novoads/agent-skills only when that header names a version NEWER than this file's metadata.packVersion — equal or older is nothing to say, and it is never a reason to stop.

Workflow

  1. Read the transcript. Note what is said and when — the words drive every decision below.
  2. Generate the b-roll clips, only after base approval. One clip per moment you intend to cover, each rendered silent (audioEnabled: false). Overlay audio is ignored by the script regardless, and generating before approval spends credits on a cut that may still change. Price the set live first — POST /v1/estimates this session, the total shown against the user's balance, an explicit yes. Four cutaways is four charges, and a remembered price is not a price. Cast the base actor in every cutaway that shows a person: pass the same referenceAssetIds the base used — Seedance re-casts every render, and a stranger's hands or skin breaks the ad (observed live 2026-08-04: Black base actor, five white-cast cutaways). With no identity ref, keep people out of frame entirely — objects and environments, not "face out of frame".
  3. Propose an EDL. JSON with base, output, and overlays (file, start, end, covers). covers is mandatory and quotes the spoken line the window illustrates — a window you can't quote is one you're guessing at.
  4. Show the EDL to the user and wait for approval. Rendering before the user has seen the plan is precisely the failure this step prevents.
  5. Render: python3 scripts/broll_overlay.py edl.json
  6. Report the script's verification output verbatim — the measured durations, the audio check and the window count, not a paraphrase. Then offer 2–3 cut variations (different windows, fewer cutaways, a tighter opener) to react to.

Placement judgment

Default cadence, measured 2026-08-04 frame by frame from the reference edit this pack reproduces — ~15.5s, 10–11 shots, a cut every ~1.4s:

  • Alternate A-B-A-B: the face returns between every cutaway. Never two overlay windows back to back; the talking head is the spine.
  • 4–6 windows per 15s, ~1–1.5s each, ~40–45% coverage. Short and frequent. This retires our older "fewer, longer windows" rule — taste, reversed by measurement; our own two renders ran 2 windows of 2.5s/2.0s, ~30% coverage.
  • The b-roll may travel; the base never does. The reference visits 4 distinct b-roll settings across 2–3 rooms; the talking head never moves.
  • Never cover the opening hook beat. The first beat is a face making a claim; cutting away there spends the retention the hook just bought.
  • End on the person, not on b-roll. The closing beat is the verdict, and it only lands if the viewer is looking at whoever delivers it.
  • Put product shots where the product is being spoken about. B-roll that illustrates the current sentence reads as evidence; anything else is filler.

Default shot plan. The reference's five cutaways tell one arc: problem → stress → product macro → dose/usage → relief — 2 product shots to 3 emotional beats. Adapt the imagery to the script, keep the ratio.

Evidence: one measured edit (n=1) — a default, not a law; depart deliberately and say why (evals.md OV3/OV6). Every run prints its own cadence against this envelope; --stats prints it without rendering.

Hard rule: assembly always goes through the script

Never hand-write overlay or concat ffmpeg for this task. broll_overlay.py owns validation, rendering and verification, and it fails loudly on exactly what fails silently by hand: duration drift, re-encoded audio, overlapping or zero-frame windows, a clip shorter than its window, a rotated phone base composited at the wrong geometry, a window that quietly composited nothing. Improvised ffmpeg is how the founding failure happened.

It needs ffmpeg 7.1 or newer. The script scales each overlay against the base branch with scale=w=rw:h=rh, and those reference constants arrived in 7.1. On an older build — Ubuntu 24.04's apt ships 6.1 — the graph does not parse and the error names rw, not a version. Check with ffmpeg -version before blaming the EDL; on Debian/Ubuntu the fix is a static build, not apt install ffmpeg.

Escape hatch: if a request genuinely doesn't fit the EDL model — a speed ramp, a picture-in-picture inset, audio that actually needs editing — say so and ask the user how to proceed. Do not improvise around the script.

Other modes

  • python3 scripts/broll_overlay.py edl.json --dry-run — validate the EDL and print the plan, rendering nothing. Cheap way to check window geometry.
  • python3 scripts/broll_overlay.py edl.json --stats — window count, lengths, coverage, base-return gaps, each marked against the envelope. Never an error.
  • python3 scripts/broll_overlay.py --verify-only FINAL --base BASE [--edl edl.json] — re-check any output against its base, including one from an old session. Pass --edl whenever you have it: without it the check is duration + audio only, which a plain copy of the base also passes; with it each window's midpoint frame is compared against the base, so a window that composited nothing fails. A run without --edl says so out loud.

Exit codes: 2 validation, 3 render, 4 verification. A nonzero exit is a real failure — surface it, don't retry blindly. Renders go to a hidden temp file beside the output, renamed only after verification passes: a failed run never leaves a half-written or unverified file at the output path.

Evals

evals.md defines the six scenarios this skill is held to (OV1–OV6). scripts/test_broll_overlay.py implements the mechanical ones against synthetic fixtures — run it after touching the script.

1---
2name: broll-overlay
3metadata: {packVersion: 1.3.0}
4description: >-
5 Overlays silent b-roll cutaway clips onto a finished base video — the base
6 audio keeps running underneath while the picture cuts away and returns, and
7 the final duration always equals the base duration. Use when the user asks to
8 add b-roll, add cutaways, or overlay clips on a video: "add b-roll to this",
9 "cut away to a product shot here", "overlay these clips on my UGC ad". Entered
10 from an approved base video plus its transcript, which comes from
11 POST /v1/transcripts and needs no local install; it never generates the base
12 itself and it never extends a video.
13---
14 
15# B-roll overlay
16 
17Lays silent cutaway clips **over** a finished base video: the base audio runs
18untouched underneath, the picture cuts away and returns, and the final duration
19equals the base duration exactly. That is the whole contract — overlay, never
20concatenation. A previous run concatenated: 24s for a 15s base, voice dead 12s.
21 
22Assembly mechanics live entirely in `scripts/broll_overlay.py`; this file is
23judgment only — when to enter, where the windows go, what the user sees first.
24 
25## Entry condition
26 
27Two things must already exist. This skill never generates the base — if there
28isn't one yet, say so and stop.
29 
301. **A finished, approved base video with exactly one audio stream.** Approved
31 means the user has watched it and signed off — b-roll is a polish pass over a
32 locked cut. The script stream-copies one voice track under the picture, so a
33 two-stream base is rejected: `ffmpeg -i base -map 0:v -map 0:a:0 -c copy`.
342. **Its transcript, with timings.** One call to **`POST /v1/transcripts`** with
35 the base's `jobId` (or its `assetId` if it was uploaded). It returns `text`,
36 word-level `words[]` and `segments[]` — **timings in SECONDS**, which is what
37 the EDL below takes — plus an `srt` you can ignore here. **Price it with the
38 transcript arm of `POST /v1/estimates` and quote that number**, never one from
39 this file. The meter is per minute of source, rounded up from a one-minute
40 minimum, and **a repeat of the same source is free**, so asking twice costs
41 once. No local install.
42 
43 *(The **captions** endpoint still cannot supply this — it burns subtitles into
44 a new MP4 and returns no text or timings, verified 2026-08-04 and re-checked
45 when transcripts shipped. That finding is correct and is kept here so nobody
46 re-discovers it and files a bug against captions.)*
47 
48 **Offline fallback:** a local whisper pass (`whisper-cli` or `openai-whisper`)
49 still works and is the path when there is no API key or no network. Note
50 whisper reports timings in **milliseconds** where the API reports seconds, and
51 `whisper-cli` with no model downloaded returns an EMPTY transcript rather than
52 an error — which reads exactly like a bad render. See README for the model
53 download.
54 
55 Placement is read from the transcript, not eyeballed.
56 
57> **REST key required. A Novoads MCP connector is not a substitute.** If
58> `NOVOADS_API_KEY` is missing or still the placeholder, stop before any
59> generation work and tell the user: "Before continuing, create an API key at
60> <https://novoads.ai/dashboard/settings?tab=api> and paste it into `.env`."
61> That holds even when `mcp__novoads__*` tools are connected and authenticated in
62> the session. Never call `mcp__novoads__*` tools from this repo's workflows: they
63> are a different surface with different behavior, including the units they quote
64> costs in. Repo installs verify with `./scripts/check-novoads-env.sh`; a solo
65> install checks `NOVOADS_API_KEY` in the environment.
66 
67**Pack version.** Every `/v1` response carries `X-Novoads-Pack-Version`; mention a newer pack at <https://github.com/novoads/agent-skills> only when that header names a version NEWER than this file's `metadata.packVersion` — equal or older is nothing to say, and it is never a reason to stop.
68 
69## Workflow
70 
711. **Read the transcript.** Note what is said and when — the words drive every
72 decision below.
732. **Generate the b-roll clips, only after base approval.** One clip per moment
74 you intend to cover, each rendered silent (`audioEnabled: false`). Overlay
75 audio is ignored by the script regardless, and generating before approval
76 spends credits on a cut that may still change.
77 **Price the set live first — `POST /v1/estimates` this session, the total
78 shown against the user's balance, an explicit yes.** Four cutaways is four
79 charges, and a remembered price is not a price.
80 **Cast the base actor in every cutaway that shows a person:** pass the same
81 `referenceAssetIds` the base used — Seedance re-casts every render, and a
82 stranger's hands or skin breaks the ad (observed live 2026-08-04: Black base
83 actor, five white-cast cutaways). With no identity ref, keep people out of
84 frame entirely — objects and environments, not "face out of frame".
853. **Propose an EDL.** JSON with `base`, `output`, and `overlays` (`file`,
86 `start`, `end`, `covers`). `covers` is mandatory and **quotes the spoken line
87 the window illustrates** — a window you can't quote is one you're guessing at.
884. **Show the EDL to the user and wait for approval.** Rendering before the user
89 has seen the plan is precisely the failure this step prevents.
905. **Render:** `python3 scripts/broll_overlay.py edl.json`
916. **Report the script's verification output verbatim** — the measured durations,
92 the audio check and the window count, not a paraphrase. Then offer 2–3 cut
93 variations (different windows, fewer cutaways, a tighter opener) to react to.
94 
95## Placement judgment
96 
97Default cadence, measured 2026-08-04 frame by frame from the reference edit this
98pack reproduces — ~15.5s, 10–11 shots, a cut every ~1.4s:
99 
100- **Alternate A-B-A-B: the face returns between every cutaway.** Never two
101 overlay windows back to back; the talking head is the spine.
102- **4–6 windows per 15s, ~1–1.5s each, ~40–45% coverage.** Short and frequent.
103 This retires our older "fewer, longer windows" rule — taste, reversed by
104 measurement; our own two renders ran 2 windows of 2.5s/2.0s, ~30% coverage.
105- **The b-roll may travel; the base never does.** The reference visits 4
106 distinct b-roll settings across 2–3 rooms; the talking head never moves.
107- **Never cover the opening hook beat.** The first beat is a face making a
108 claim; cutting away there spends the retention the hook just bought.
109- **End on the person, not on b-roll.** The closing beat is the verdict, and it
110 only lands if the viewer is looking at whoever delivers it.
111- **Put product shots where the product is being spoken about.** B-roll that
112 illustrates the current sentence reads as evidence; anything else is filler.
113 
114**Default shot plan.** The reference's five cutaways tell one arc: problem →
115stress → product macro → dose/usage → relief — 2 product shots to 3 emotional
116beats. Adapt the imagery to the script, keep the ratio.
117 
118Evidence: one measured edit (n=1) — a default, not a law; depart deliberately and
119say why (evals.md OV3/OV6). Every run prints its own cadence against this
120envelope; `--stats` prints it without rendering.
121 
122## Hard rule: assembly always goes through the script
123 
124Never hand-write overlay or concat ffmpeg for this task. `broll_overlay.py` owns
125validation, rendering and verification, and it fails loudly on exactly what
126fails silently by hand: duration drift, re-encoded audio, overlapping or
127zero-frame windows, a clip shorter than its window, a rotated phone base
128composited at the wrong geometry, a window that quietly composited nothing.
129Improvised ffmpeg is how the founding failure happened.
130 
131**It needs ffmpeg 7.1 or newer.** The script scales each overlay against the base
132branch with `scale=w=rw:h=rh`, and those reference constants arrived in 7.1. On an
133older build — Ubuntu 24.04's apt ships 6.1 — the graph does not parse and the
134error names `rw`, not a version. Check with `ffmpeg -version` before blaming the
135EDL; on Debian/Ubuntu the fix is a static build, not `apt install ffmpeg`.
136 
137**Escape hatch:** if a request genuinely doesn't fit the EDL model — a speed
138ramp, a picture-in-picture inset, audio that actually needs editing — say so and
139ask the user how to proceed. Do not improvise around the script.
140 
141## Other modes
142 
143- `python3 scripts/broll_overlay.py edl.json --dry-run` — validate the EDL and
144 print the plan, rendering nothing. Cheap way to check window geometry.
145- `python3 scripts/broll_overlay.py edl.json --stats` — window count, lengths,
146 coverage, base-return gaps, each marked against the envelope. Never an error.
147- `python3 scripts/broll_overlay.py --verify-only FINAL --base BASE [--edl edl.json]`
148 — re-check any output against its base, including one from an old session.
149 **Pass `--edl` whenever you have it:** without it the check is duration +
150 audio only, which a plain copy of the base also passes; with it each window's
151 midpoint frame is compared against the base, so a window that composited
152 nothing fails. A run without `--edl` says so out loud.
153 
154Exit codes: `2` validation, `3` render, `4` verification. A nonzero exit is a
155real failure — surface it, don't retry blindly. Renders go to a hidden temp file
156beside the output, renamed only after verification passes: a failed run never
157leaves a half-written or unverified file at the output path.
158 
159## Evals
160 
161`evals.md` defines the six scenarios this skill is held to (OV1–OV6).
162`scripts/test_broll_overlay.py` implements the mechanical ones against synthetic
163fixtures — run it after touching the script.
164 
View all files on GitHub →

Details

License
MIT
Stars on the repo
★ 23
Checked
Source
novoads/agent-skills ↗
Creator
novoads · 14 listings
View creator

Similar skills

See all →
SkillHiggsfield Social Hookspixelab-ch/higgsfield-skills · by pixelab-chCrafts viral social media hook video prompts for TikTok, Instagram Reels, and YouTube Shorts via Higgsfield. Routes to kling3_0 (primary) or grok_video (fallback). Use when the user wants scroll-stopping hooks, viral short-form video, attention-grabbing openers, TikTok content, Reels content, Shorts content, or any social-media-optimized video.★ 6 GitHub starsSkillGab Video Editorgabrielxreis/ogab · by gabrielxreisGab, o editor de vídeo com IA (comando /ogab). Skill PRINCIPAL para qualquer trabalho de vídeo: criar um vídeo novo (Reels, YouTube Shorts/longo, Meta Ads, anúncio, institucional, vídeo de cliente) OU editar um vídeo/projeto/timeline no DaVinci Resolve (cortar, montar, legendar, colocar música, takes, lettering, motions, cor, áudio, exportar). Leva do roteiro até a timeline pronta no DaVinci: roteiro para aprovação, voz por IA, música, efeitos sonoros, takes de banco ou gerados, lettering animado, motions e gráficos com HyperFrames, legenda com métrica e conferência automática. Use SEMPRE que o usuário pedir para criar/fazer/editar um vídeo, mexer no DaVinci, reels, anúncio, pauta ou roteiro, mesmo sem citar a skill; as outras skills de vídeo (hyperframes, motion-graphics etc.) entram como ferramentas DENTRO deste fluxo. Comando: /ogab <pedido> ou /ogab <subcomando> (ajuda, config, update, pauta, cliente). Também cuida do Instagram: legenda do post, carrossel pronto em imagem (PNG/PDF na marca do cliente), gancho de Reel viral, hashtags, tirar cara de IA do texto, semana de conteúdo, perfil e dados do nicho.★ 1 GitHub starsSkillAI Video Clipping ToolSamurAIGPT/Generative-Media-Skills · by SamurAIGPTTurn a long video into N viral-ready short clips with a single managed API call. Wraps muapi.ai's `/ai-clipping` endpoint, which handles transcription, highlight ranking through a virality framework (hook / emotional peak / opinion bomb / revelation / conflict / quotable / story peak / practical value), overlap dedupe, and vertical face-tracking auto-crop server-side. No local Whisper, no local LLM, no GPU.★ 4.3k GitHub starsSkillYouTube Shorts GeneratorSamurAIGPT/Generative-Media-Skills · by SamurAIGPTAuto-generate viral 9:16 YouTube Shorts (or TikTok / Reels clips) from a long-form video. Thin platform-aware wrapper around the AI Clipping skill — picks sensible defaults for short-form social platforms (9:16, 30–60s sweet spot) and delegates the actual highlight extraction + crop to muapi.ai's `/ai-clipping` endpoint.★ 4.3k GitHub starsSkillVertical Video Editorericosiu/ai-marketing-skills · by ericosiuTurn newly recorded talking-head footage into review-ready vertical video drafts with an explicit edit plan, deterministic FFmpeg rendering, captions, hook cards, audio normalization, and visual QA. Use for original Instagram Reels, TikTok videos, YouTube Shorts, LinkedIn videos, founder-led recordings, multiple takes of a new script or idea card, or requests to automate the first video-editing pass. Do not use to mine clips from long-form source videos.★ 3.6k GitHub starsSkillShort Form Video Pipelineericosiu/ai-marketing-skills · by ericosiupython3 telemetry/versioncheck.py 2>/dev/null || true★ 3.6k GitHub stars

More from novoads

SkillVideo Style Template Reversernovoads/agent-skills · by novoadsAnalyze a reference video and reverse-engineer its style into a reusable Seedance 2.0 prompting template for the Novoads API. The output is a new formula file — like seedance-2-ugc.md — that captures the video's structure, pacing, camera work, edit style and tone so it can be recreated with any product, any person, in any setting. Use this whenever someone provides a video they want to use as a style reference, says "I want to make videos like this", "deconstruct this video", "turn this into a template", "analyze this style", or drops a video file and wants to recreate that format repeatedly.★ 23 GitHub starsSkillVideo Caption Burnernovoads/agent-skills · by novoadsBurn timed, styled captions into a finished video on the local machine, without re-rendering the source. This is the manual fallback to the API's captioning endpoint, POST /v1/captions, which stays the default path: come here when the style the user wants is outside the API's presets, when the wording has to be hand-corrected before it is burned into the pixels, or when the source was rendered with audio disabled and the API refuses it. Transcribes the audio with Whisper, groups words into reading phrases, renders the captions in a real browser via HyperFrames, and composites them over the source with ffmpeg using a real alpha channel. Use when the user has an MP4 with speech and asks to add captions, subtitles, burned-in text, TikTok-style captions or word-by-word text to it, and the API path has been ruled out. Runs out of band, so it costs no credits and works on any video file whoever generated it. Not for generating video (use the video skills) and not for a separate .srt/.vtt sidecar file.★ 23 GitHub starsSkillAI Image Ad Creatornovoads/agent-skills · by novoadsGenerate one or more standalone Meta image-ad creatives via ChatGPT Image 2 (gpt-image-2) through the Novoads API. Locks the model, auto-strips platform chrome, enforces edge-safe layouts and glyph-safety inside body text. Use when the user asks for a "gpt-image-2 ad", "ChatGPT Image ad", "Image 2 ad creative", "make a static image ad with GPT", or anchors on a need for typography-heavy / dense-text / UI-mimicry ad creatives (chat threads, comparison tables, fake search results, iOS dialogs, Slack snapshots, ChatGPT-conversation ads, Apple Notes lists). Does NOT trigger on Nano Banana cues — use nano-banana-image-ad for those.★ 23 GitHub starsSkillVideo Ad Clonernovoads/agent-skills · by novoadsClones a VIDEO ad end to end for a different product or offer, on the Novoads API. The deliverable is a finished rendered MP4 — the WHOLE ad, not its opening, and not a template. Reads the source's style, pacing, camera work, dialogue and tone, adapts it into a Seedance 2.0 prompt, prices it, renders it, files the source beside the clones and diffs each clip's transcript against the approved script. Use for "clone this video ad", recreate this video for my brand", "make this ad but for my product" when the source is a video, "clone my competitors' VIDEO ads", or a video ad handed over with a product photo. **Among cloners the source's medium decides, not the wording**: "clone this ad" plus a video lands here; a still, or nothing attached, is clone-image-ad, and animating a still as-is is image-to-motion. This pack has no hook-only skill: for the opening alone, clone the whole ad and cut. If it does not move, wrong skill.★ 23 GitHub starsSkillImage Ad Clonernovoads/agent-skills · by novoadsClones a STATIC IMAGE ad into finished ads for your own product, into a reusable prompt TEMPLATE, or both — the template is what makes the ads and the ads are what prove the template. Round-trips the frame through gpt-image-2, nano-banana-pro or reve-2.1 until it reproduces, replaces every brand-specific with a {placeholder}, then fills it with your product pinned to a real photo. Use for "clone this ad for my product", "rebuild this competitor's ad for us", "make me ads like this", "reverse engineer this ad", make this ad reusable", "add this to my prompt library", or "clone my competitors ads" with NO file attached — it sources one via spy-competitor-ads rather than asking which. **Among cloners the source's medium decides**: a still, or nothing attached, lands here; "clone this ad" plus a VIDEO is clone-video-ad. NOT for generating an ad from a brief (chatgpt-image-ad, nano-banana-image-ad), nor animating a still as-is (image-to-motion). Refuses to render your product without a real photo of it.★ 23 GitHub starsSkillYouTube Thumbnail Designernovoads/agent-skills · by novoadsGenerate high-CTR YouTube thumbnails using Nano Banana Pro via the Novoads API. Handles reference image upload, character likeness alignment, proven CTR-tested prompt formulas, and bounded batch generation. Use when the user asks to create a YouTube thumbnail, video thumbnail, A/B test thumbnail variations, or refers to thumbnail design with their face, brand assets, or product photos.★ 23 GitHub stars