answer-ads-questions
Answer questions about a brand's Meta ads (spend, results, which ad is winning, is it paused,…
Render a 'hand-swipe flavor listicle' video from a config — the brand's REAL product cutouts each float on a flat flavor-matched color field under a persistent title and slide RIGHT-TO-LEFT one to the next like a phone-feed scroll, while a green-screen hand clip (back of hand
$ npx -y skills add gooseworks-ai/goose-skills --skill render-hand-swipe-flavor-listicle --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/render-hand-swipe-flavor-listicleContext preview
The summary Claude sees to decide when to auto-load this skill.
Render a 'hand-swipe flavor listicle' video from a config — the brand's REAL product cutouts each float on a flat flavor-matched color field under a persistent title and slide RIGHT-TO-LEFT one to the next like a phone-feed scroll, while a green-screen hand clip (back of hand
name: render-hand-swipe-flavor-listicle description: Render a 'hand-swipe flavor listicle' video from a config — the brand's REAL product cutouts each float on a flat flavor-matched color field under a persistent title and slide RIGHT-TO-LEFT one to the next like a phone-feed scroll, while a green-screen hand clip (back of hand toward camera, index finger up) is trimmed to its clean finger-up window, looped once per flavor, keyed with a green-dominance alpha key, scaled down and anchored at the bottom, with an optional end card and an optional instrumental music bed — deterministic PIL plus FFmpeg assembly, FREE (the hand clip comes from create-video-fal and the bed from create-music-elevenlabs), so labels stay pixel-crisp. Use for the hand-swipe-flavor-listicle format. status: active
Render the **hand-swipe-flavor-listicle** format from a config: a short vertical (1080×1920, 30fps, ~7.5s) "N flavors of <Brand>" listicle. Each flavor is a card — a flat, saturated color field + a persistent title + the brand's REAL product cutout with a soft contact shadow. Cards change by sliding **right-to-left** (a phone-feed scroll), while a real-looking hand sweeps at the bottom of the frame. Music-only, no VO.
This capability is the **FREE, deterministic assembly** ($0, no keys). It never generates or edits the product — the cutouts are composited as-is, so labels stay crisp. It needs four kinds of input, gathered first (see **Getting the inputs**): product cutouts, a title TTF, a green-screen hand clip, and (optionally) a music bed.
S=/tmp/gooseworks-scripts/render-hand-swipe-flavor-listicle/scripts # after `gooseworks fetch render-hand-swipe-flavor-listicle` python3 $S/build_hand_swipe_listicle.py config.json # writes config "output" python3 $S/build_hand_swipe_listicle.py config.json --out final.mp4 # override the output python3 $S/build_hand_swipe_listicle.py config.json --stills cards/ # one PNG per card, no video python3 $S/build_hand_swipe_listicle.py config.json --work work/ # keep the intermediates in work/
Relative paths in `config.json` resolve against the config file's own folder. Render `--stills` first: it is instant and shows the title, colors and cutouts before the full render.
**Prereqs:** `python3` with Pillow, and `ffmpeg` + `ffprobe` on PATH. Nothing else.
| Input | Free route | Paid route (gated: confirm with the user first) | |---|---|---| | Product cutouts | The brand's transparent PNGs (PDP/press kit). | A brand-site photo is usually NOT a cutout. Remove its background with `create-image-fal`, model `fal-ai/birefnet/v2` (see below). | | Title TTF | Download a TTF matching `choices.title_style` (table below). | — | | Hand clip | The bundled clip (one woman's hand): `curl -fL -o hand-swipe-greenscreen.mp4 https://d2m0qbg34x1ii2.cloudfront.net/ads/samples/455dc125-e41c-46dc-9fa6-9ae125e9b6bf/media-hand-swipe-greenscreen.mp4` (also in the recipe's `config.hand.bundled_clip_url`). | A new clip via `create-video-fal` (see **Making the hand clip**). | | Music bed | None (`"music": null`, a silent cut). | `create-music-elevenlabs` (see **Making the music bed**). |
**Cutouts.** The renderer warns when an image has no transparent pixels: it would render as a white box with a rectangular shadow. Fix it before rendering, never by AI-regenerating the product. The cutout route is `create-image-fal` with model `fal-ai/birefnet/v2` (paid, gated), payload `{"image_url": "<public url of the product photo>"}`, the same route `render-vignette` uses. **Known gap:** birefnet returns `image`, not `images[]`, and `create-image-fal`'s `gen_image.py` currently reads only `images[]`, so check that capability's notes before relying on it. If no cutout route works, ask the user for transparent PNGs.
**Title font.** Always pass `title_font`. Without it the renderer falls back to whatever the machine has (Brush Script on macOS, DejaVu Sans Bold on Linux), so the same config renders a different title style on different machines. Free TTFs from Google Fonts, one per `title_style`:
| `choices.title_style` | Download | |---|---| | cursive / script | `curl -fL -o fonts/title.ttf https://github.com/google/fonts/raw/main/ofl/pacifico/Pacifico-Regular.ttf` | | bold condensed sans | `curl -fL -o fonts/title.ttf https://github.com/google/fonts/raw/main/ofl/anton/Anton-Regular.ttf` | | elegant serif | `curl -fL -o fonts/title.ttf https://github.com/google/fonts/raw/main/ofl/dmserifdisplay/DMSerifDisplay-Regular.ttf` | | hand-drawn marker | `curl -fL -o fonts/title.ttf https://github.com/google/fonts/raw/main/apache/permanentmarker/PermanentMarker-Regular.ttf` | | the brand's own display font | The brand's TTF/OTF file if you have it; otherwise the closest row above. |
The title is auto-shrunk (with a warning) until it fits 88% of the frame width, and the underline follows the drawn text, so long brand names never clip on the edges.
`scripts/config.example.json` is the worked example (Lucky Energy "5 Flavors of Lucky"). Copy its structure, never its creative values.
| Field | What it is | |---|---| | `title` | The persistent header line (required). | | `title_font` | A TTF in the style from `choices.title_style` (see **Title font**). Missing → a warned, machine-dependent fallback. | | `title_size`, `title_y`, `title_color`, `title_underline` | Title layout (defaults 118, 200, white, true). `title_size` is a maximum: a too-wide title is shrunk to fit. | | `flavors[]` | `{ "bg": "#hex", "can": "cutout.png" }` per flavor, in play order (required, ≥2). `image` is accepted as an alias for `can`. Cutouts must be transparent PNGs. | | `can_height`, `can_center_y` | Product size + vertical center (defaults 950, 940). | | `slide.frames` | Frames per slide (default 12). `slide.direction` is fixed: always right-to-left (any other value is ignored with a warning). | | `hand_clip` | The green-screen h
Put your AI agent on the growth team. Research customers and competitors, analyze what is working, create the next campaign, and learn from the result.
Repo: gooseworks-ai/goose-skills
Answer questions about a brand's Meta ads (spend, results, which ad is winning, is it paused,…
Burned-in captions for a finished vertical video, three kinds. transcribe.py gets word…
Composite a generated creator track into a product layer, per beat — in the creator's zone on…
Generate an AI creator talking to camera, saying an approved script, as one continuous track…
Generate or edit an image via any FAL image model (nano-banana edit, gpt-image, flux, ...),…
Generate a single photoreal or designed image with OpenAI gpt-image via fal.ai. Supports…