$npx -y skills add gooseworks-ai/goose-skills --skill render-editorial-motion-podcastAssemble an editorial-motion podcast-clip ad from a config — a real clipped podcast MP3 carries the narrative while N flat 2-tone editorial-illustration keyframes are animated NOT by generative i2v but by DETERMINISTIC ffmpeg ken-burns (zoompan) + hard cuts (no crossfades, which
| 1 | # render-editorial-motion-podcast |
| 2 | |
| 3 | Assemble an **editorial-motion podcast-clip** ad from a config: a real clipped podcast audio |
| 4 | line carries the whole narrative and every visual beat is timed to the sentence it describes, |
| 5 | in a bold flat 2-tone editorial-illustration look ("a New Yorker spot-illustration that |
| 6 | moves"). The motion is **not generative video** but deterministic ffmpeg ken-burns on static |
| 7 | keyframes, so it reads as a printed page that moves. This capability is that **FREE, |
| 8 | deterministic assembly** — the ffmpeg motion, hard-concat, audio mux, caption burn, and PIL |
| 9 | end card. |
| 10 | |
| 11 | `scripts/config.example.json` is the worked example (Klarify "Rat Park", ~40.8s 1080×1920 |
| 12 | 9:16, 6 beats); `scripts/PIPELINE.md` maps every config block to its source step and |
| 13 | `scripts/README.md` documents the free assembly. |
| 14 | |
| 15 | ## Run |
| 16 | |
| 17 | This is the **FREE, deterministic** assembly stage — it spends nothing on the motion layer. |
| 18 | The paid inputs are separate: the real podcast MP3 is clipped from source (free ffmpeg) with |
| 19 | its Whisper word timings, and one editorial-illustration keyframe per beat (chained ref images |
| 20 | so cage/character geometry holds) comes from `create-image-fal` (Nano Banana). Given the |
| 21 | clipped audio + `words.json` + the per-beat keyframes + the real brand wordmark PNG, |
| 22 | `render-editorial-motion-podcast` renders each keyframe as a ken-burns segment, hard-concats |
| 23 | on the beat, muxes the real audio, burns the mid-sentence captions, and composites the PIL end |
| 24 | card → the master. Re-cuts reuse the existing audio / keyframes and cost **$0**. |
| 25 | |
| 26 | ## Contract (the free assembly) |
| 27 | |
| 28 | - **A spoken narration carries the whole spot — no generated SONG.** Mux the provided |
| 29 | narration MP3 (`-map 0:v:0 -map 1:a:0`) — a real clipped podcast line (preferred) OR an |
| 30 | approved generated VO (`create-vo-elevenlabs`). Never a sung/generated track. (Clip-vs-generate |
| 31 | is the recipe's STEP-0 intake decision — if no source episode is supplied, ASK the user.) |
| 32 | - **NO generative i2v — deterministic ffmpeg ken-burns only.** Animate each static keyframe |
| 33 | with `zoompan` (push-in / pull-back, 1.0→~1.06×, 24fps); Seedance/Kling are photoreal-trained |
| 34 | and invent naturalistic middle states that collapse the 2-tone look. Never `-loop 1` with |
| 35 | `zoompan d=N` (it balloons the duration); feed a single image and clamp with `-t` + `trim`. |
| 36 | - **Hard cuts on the beat — no crossfades.** Crossfades ghost two drifting cages through each |
| 37 | other; hard-concat each beat's segments and split long beats into micro-cuts (target 8–10 |
| 38 | distinct visual moments). Each beat's visual STARTS within ~0.5s of its spoken line. |
| 39 | - **Captions from Whisper word-timestamps, ON only mid-sentence.** Burn `frosted-subtle` |
| 40 | captions while the speaker talks; leave silent/reflective beats and the end card uncaptioned. |
| 41 | THREE mandatory rules (each bit us in prod — bake them in): |
| 42 | 1. **NON-OVERLAP** — clamp every line to END before the next STARTS |
| 43 | (`end = min(last_word_end + ~0.15, next_start - 0.03)`). Two boxes must never stack at the |
| 44 | same spot; an end-tail bleeding into the next window is the #1 caption bug. |
| 45 | 2. **SAFE AREA** — captions sit in the lower third, so the keyframe's subject must stay in the |
| 46 | upper ~75% (see the recipe's `look_pack.caption_safe_area`). If a finished keyframe's subject |
| 47 | intrudes into the caption band, deterministically **shift the subject UP** into the empty top |
| 48 | space (PIL: paste up ~0.24H onto a canvas pre-filled with the exact paper color from a clean |
| 49 | corner) — never let the box sit on the subject. |
| 50 | 3. **BURN ENGINE** — prefer libass (`ass`/`subtitles` filter), but **check `ffmpeg -filters` |
| 51 | first**: many builds (Homebrew) lack libass/drawtext. If absent, use the deterministic |
| 52 | **overlay fallback** — render each line as a transparent PNG (frosted rounded box + white |
| 53 | text, PIL) and composite via the ffmpeg `overlay` filter with timed |
| 54 | `enable='between(t,st,en)'` windows. Same look, no libass. |
| 55 | - **End card via PIL from the real wordmark PNG — never AI-render brand text.** The lockup is |
| 56 | composited deterministically (stretched-gradient bg + feathered mascot crop + wordmark + |
| 57 | tagline with a system font); a diffusion model garbles a wordmark |