| name | create-product-hypermotion-with-specs |
| description | Produce a Product Hypermotion + Kinetic Typography intercut ad (Common Thread Co
"Product Specs" format × Higgsfield "Hyper Motion" treatment). Single Seedance i2v
hypermotion clip cut into 5-6 segments, intercut with 5-7 PIL-rendered kinetic
typography text cards (specs/CTA), capped by a brand-asset end card (real logo
PNG + slam motion blur + inversion flash). 20-30s, 9:16 vertical, music-led, no VO.
Validated on Soundboks GOOSE-1783 (10 iterations, V10 shipped 2026-05-28, $17.43
total spend, $4.99 marginal). Use when brand has industrial/sport/party voice +
hero product + 4-6 hard spec callouts. NOT for UGC, talking-head, or VO-led ads.
|
| status | ACTIVE — validated on 1 brand (Soundboks 2026-05-28). Promote to 2+ brands before locking decision rules. |
create-product-hypermotion-with-specs
Hypermotion + Kinetic Typography intercut = one virtuoso AI-gen product clip,
diced into segments and interleaved with PIL-rendered text cards for spec
callouts, ending with a brand-asset end card. Music-led, silent VO, 9:16
Reels-native. Validated on Soundboks (industrial/party voice) 2026-05-28.
Purpose
Produce a 20-30s 9:16 vertical product ad by:
- Gathering brand assets (real product photos + brand logo PNG + brand color palette)
- Generating ONE 12-15s hypermotion i2v via Seedance 2.0 using a 5-block prompt recipe
- Rendering 5-7 kinetic typography text cards via PIL (italic skew, outline echo,
3D extrusion, slam-with-shake, inversion flash) for spec callouts + CTA
- Rendering 1 brand-asset end card via PIL (real logo PNG + brand-coded BG +
slam motion blur + cascade reveal of subtitle + CTA + inversion flash)
- Cutting the hypermotion into 5-6 segments, intercutting with text cards in a
fixed beat structure, ffmpeg concat + crop to 9:16
- Generating a 124 BPM bass-driven music bed via ElevenLabs Music (fal proxy)
- Mux + self-QC + ship
Use when:
- Brand voice is industrial / sport / party / utility (Soundboks-class)
- Hero product photographs well (real PDP shots available, not AI-gen ex-nihilo)
- Brand has 4-6 hard spec callouts (dB, hours, IP rating, count, etc.)
- Brand has a logo SVG/PNG that can be extracted (most brand SVGs are base64 PNG wrappers)
- Target placement: TikTok / Reels / Stories (9:16 vertical) — works muted
Do NOT use for:
- UGC ads with creator → use
skills/molecules/ugc-ad/*
- VO-driven explainer → use
skills/molecules/explainer-video/*
- Editorial / luxury / wellness brand voices → use
create-vignette-ad (calmer)
- Single static product hero → use
skills/atoms/product-images/*
-
30s long-form — format breaks past 30s (the hypermotion clip is the ceiling)
Inputs
Required:
brand_url — e.g. https://soundboks.com
product_url — PDP URL for the hero product (Shopify or equivalent)
spec_callouts[] — 4-6 short spec strings (e.g. ["126 dB SPL", "40-HOUR BATTERY", "IP65 RATED", "SWAPPABLE BATTERY", "PAIR 5 SPEAKERS"])
brand_voice — one of industrial | sport | party | utility | luxury | editorial | playful
- The first 4 share the same aesthetic palette (black + Space Grotesk + utility orange)
editorial uses cream paper + EB Garamond (Hope-style) — better suited for create-vignette-ad
luxury and playful need different palettes — currently OUT OF SCOPE (single-brand validation)
Optional (with autonomous defaults):
duration_s — default 25.0 (range 20-30)
cta_text — default "Own the party." or "Own the {category}."
intro_text — default "INTRODUCING"
hypermotion_brief — free-text. If omitted, derived from brand category +
product (Soundboks → "beach festival crash-zoom on speaker, lateral orbit,
slow-mo dust"). See references/hypermotion-prompt-recipe.md.
music_brief — default "{BPM} BPM bass-driven electronic banger, no vocals or with a single rallying lyric for end-card sync". BPM default 124 for industrial/party, 100 for sport/utility.
accent_color_hex — default #FF6B1A (utility orange). Override via brand palette scrape.
bg_color_hex — default #0C0C0C (industrial black). Override only if brand requires.
Prerequisites:
FAL_API_KEY in .env at repo root — for Seedance + ElevenLabs Music
ffmpeg + ffprobe installed
- Python 3.10+ with
Pillow and fal_client
- TTF fonts in project
source/fonts/:
SpaceGrotesk-Bold.ttf (static, NOT variable — variable renders as Regular in PIL)
EBGaramond-Italic.ttf (only required for editorial voice)
- Brand logo as PNG (extract from SVG via base64 decode — see
references/brand-asset-extraction.md)
Composed Atoms
source-brand-assets — scrape PDP product photo, brand logo SVG, brand color hex from homepage CSS
remove-backgrounds — strip product PNG to alpha via fal-ai/birefnet/v2 (only needed if hypermotion uses cutout-on-clean-BG style; for in-environment hypermotion, skip — Seedance handles the BG)
create-video-seedance-2-fal — single 12-15s i2v hypermotion call via fal-ai/bytedance/seedance/v2/pro/image-to-video ($0.30/s, supports start_image + audio_off)
create-music-elevenlabs — 25-30s music bed via fal-ai/elevenlabs/music endpoint
add-music-track — ffmpeg mux pass with -map 0:v -map 1:a explicit
stitch-videos-ffmpeg — concat the 12-14 segments (hypermotion cuts + kinetic cards)
- Inline (not yet an atom — see "Back-propagation to atom"): PIL-based
kinetic typography pipeline (11 techniques, see
references/kinetic-typography-pipeline.md). The existing
skills/atoms/motion-graphics/create-kinetic-typography atom outputs
transparent overlays (qtrle .mov); this molecule needs full-frame text cards.
watch — /watch:watch external skill for end-to-end QC on the final mp4
Do NOT use: Klap, captions, Whisper, Soul ID, UGC-creator atoms, Higgsfield
Marketing Studio (validated to not match Hyper Motion brief — Seedance 2.0
beats it for product-as-hero hypermotion).
Workflow
Phase 0 — Brand asset gathering (autonomous, $0)
-
Scrape product hero photo from brand PDP:
curl -sL "${product_url}.json" | jq -r '.product.images[0].src'
Download highest-res (PDP shots typically 1500-2000px). Save to source/scraped-product-images/.
-
Extract brand logo PNG from SVG. Most brand SVGs are wrappers around
base64-encoded PNGs:
import re, base64
svg = open('brand_logo.svg').read()
m = re.search(r'data:img/png;base64,([A-Za-z0-9+/=]+)', svg) or \
re.search(r'data:image/png;base64,([A-Za-z0-9+/=]+)', svg)
open('brand_logo.png', 'wb').write(base64.b64decode(m.group(1)))
Validated on Soundboks (decoded to 865×135 PNG of the actual wordmark). If
SVG is pure vector (rare), use rsvg-convert -w 2400 brand_logo.svg > brand_logo.png.
-
Scrape brand palette from homepage CSS — count #xxxxxx patterns, take
top 5 frequencies. Map dominant accent color → accent_color_hex.
-
Download fonts to source/fonts/:
curl -sSL -o source/fonts/SpaceGrotesk-Bold.ttf \
"https://raw.githubusercontent.com/floriankarsten/space-grotesk/master/fonts/ttf/static/SpaceGrotesk-Bold.ttf"
-
Write brief.md with: PDP photo preview, brand palette swatches, proposed
hypermotion concept + Seedance prompt + spec callouts + estimated spend (~$5).
🚦 HUMAN GATE 1 — Brief approval
Show user: brief.md + hypermotion prompt + 5-7 spec callouts + estimated spend.
User approves OR edits brief.md.
Phase 1 — Hypermotion + music in parallel (~$4.99, ~10 min wallclock)
Run both in parallel via ThreadPoolExecutor or two Bash processes:
-
Fire Seedance i2v hypermotion ($4.54 for 15s):
- Endpoint:
fal-ai/bytedance/seedance/v2/pro/image-to-video
- Input: hero product PNG as
image_url (uploaded via fal_client.upload_file)
- Duration: 15s (max for Seedance Pro)
- Generate audio: false (we use external music bed)
- Resolution: 1080p, aspect 1:1 (will be center-cropped to 9:16 later)
- Prompt: 5-block recipe (see
references/hypermotion-prompt-recipe.md):
- Block 1: STYLE ANCHOR ("hypermotion product film, 124 BPM cuts, ...")
- Block 2: CINEMATOGRAPHY ("ARRI Alexa, 50mm anamorphic, ...")
- Block 3: SUBJECT + ENVIRONMENT ("Soundboks 4 on beach festival deck, ...")
- Block 4: MULTI-SHOT TIMECODES ("0-3s crash zoom, 3-6s lateral orbit, ...")
- Block 5: ABSOLUTE CONSTRAINTS ("no character contact, no multi-product,
no text overlays, label-locked geometry, physics effects in environment
only NOT on product")
- Skip-if-exists guard: if
assets/hypermotion-raw.mp4 exists, skip the call
-
Fire ElevenLabs Music ($0.45 for 30s):
- Endpoint:
fal-ai/elevenlabs/music
- Duration:
duration_s * 1000 ms (generate exact target — Soundboks 25s validated)
- Prompt:
{BPM} BPM bass-driven {brand_voice} banger, with rallying single-lyric ending for end-card sync
output_format: "mp3_44100_192"
- Skip-if-exists guard
Phase 2 — Render kinetic typography cards (autonomous, $0)
Render all text clips at 1080×1920 via PIL frame-by-frame to working/kinetic-frames/<label>/f%04d.png, then ffmpeg-encode each to working/kinetic-movs/<label>.mp4.
Cards to render (defaults — adjust per spec_callouts list):
intro.mp4 (1.0s) — "INTRODUCING" italic + outline echo, BG: brand bg + grain
spec_1.mp4 (1.5s) — Killer-stat slam: 3D extrusion in accent color (the hero spec, e.g. "126 dB SPL")
spec_2.mp4 (1.5s) — italic slam on dark BG (e.g. "40-HOUR BATTERY")
spec_3.mp4 (1.5s) — italic + outline echo on light BG (e.g. "SWAPPABLE BATTERY")
spec_4.mp4 (1.5s) — italic + sparkle accent (e.g. "IP65 RATED")
spec_5.mp4 (1.5s) — italic + shadow stack (e.g. "PAIR 5 SPEAKERS")
cta.mp4 (1.5s) — "OWN THE PARTY" 3D extrusion + accent→black flash
endcard.mp4 (3.5s) — REAL LOGO with slam motion blur, settle, micro-motion, inversion flash at 60% mark, cascade reveal of subtitle ("126 dB · 40 HRS · IP65") + CTA
Use the 11 reusable PIL helpers from references/kinetic-typography-pipeline.md (italic skew, outline echo, 3D extrusion, repetition stack, slam-with-shake, color flash, inversion flash, paper/dark grain BG, rotated text, motion blur, micro-motion).
Reference scripts from Soundboks (copy + adapt):
clients/soundboks/video-02-hypermotion/working/scripts/gen_kinetic_v6.py
clients/soundboks/video-02-hypermotion/working/scripts/gen_endcard_v10.py
Phase 3 — Assemble + mux (autonomous, $0)
-
Center-crop hypermotion from 1:1 (1440×1440 or 1080×1080) to 9:16 (1080×1920):
ffmpeg -i hypermotion-raw.mp4 -vf "scale=-1:1920,crop=1080:1920:(iw-1080)/2:0,fps=30" -c:v libx264 -crf 18 hypermotion-9x16.mp4
Loses ~25% horizontal context but feels Reels-native.
-
Cut hypermotion into 5-6 segments at fixed timecodes via ffmpeg -ss/-t:
Default segments (for 25s ad with 15s hypermotion source):
- Seg A: t=[0.0, 2.5] (2.5s — opener crash-zoom)
- Seg B: t=[2.5, 5.0] (2.5s — lateral orbit)
- Seg C: t=[5.0, 7.0] (2.0s — first slow-mo dust)
- Seg D: t=[7.0, 8.5] (1.5s — second slow-mo dust)
- Seg E: t=[8.5, 10.0] (1.5s — pull-back)
- Seg F: t=[10.0, 11.5] (1.5s — final hero)
-
Concat segments + cards per beat structure (see references/beat-structure.md):
intro → segA → spec_1 → segB → spec_2 → segC → spec_3 → segD → spec_4 → segE → spec_5 → segF → cta → endcard
Use ffmpeg concat demuxer with a concat.txt listing all segment files in order.
-
Mux music as SEPARATE ffmpeg pass per memory feedback_ffmpeg_lcut_endcard_recipe.md:
ffmpeg -y -i master-silent.mp4 -i music.mp3 \
-c:v copy -c:a aac -b:a 192k -ar 44100 \
-map 0:v -map 1:a -shortest \
-movflags +faststart finals/master-v1-9x16.mp4
Verify audio bit_rate ≈ 192000 via ffprobe (NOT 1000 — that's the default-mapping silent bug per feedback_ffmpeg_map_directive.md).
Phase 4 — Self-QC + ship (autonomous, $0)
-
Run /watch:watch finals/master-v1-9x16.mp4 to verify:
- Duration ± 0.5s of target
- Aspect 1080×1920
- All text cards readable, no frame bleed (outline echoes at 1.08x sweet spot)
- Hypermotion segments hold subject identity (no geometry drift)
- End card real logo visible + inversion flash hits at right beat
- Music holds throughout, no decay tail visible
-
Upload to gooseworks for share URL via mcp__gooseworks__get_upload_url + curl PUT.
Output
<project>/
├── brief.md
├── HOW_TO_MAKE_THIS_VIDEO.md
├── source/
│ ├── scraped-product-images/ # raw PDP PNGs
│ ├── logo/
│ │ ├── brand_logo.svg # original
│ │ └── brand_logo_white.png # extracted from SVG
│ ├── fonts/
│ │ ├── SpaceGrotesk-Bold.ttf # static (NOT variable)
│ │ └── EBGaramond-Italic.ttf # only if editorial voice
│ └── brand-palette.json # scraped color hex
├── assets/
│ ├── hypermotion-raw.mp4 # Seedance i2v output (12-15s, 1:1)
│ ├── hypermotion-9x16.mp4 # center-cropped to vertical
│ └── music/
│ └── music_bed.mp3 # 20-30s ElevenLabs Music
├── working/
│ ├── kinetic-frames/ # PIL PNG sequences (intermediate)
│ ├── kinetic-movs/ # encoded kinetic clips
│ ├── segments/ # hypermotion cuts
│ └── scripts/
│ ├── fire_hypermotion.py
│ ├── fire_music.py
│ ├── gen_kinetic_cards.py
│ ├── gen_endcard.py
│ └── assemble.py
└── finals/
└── master-v1-9x16.mp4 # shipping master, ~25s, 1080×1920
Decision Rules
-
One hypermotion call, not many. Generate ONE 12-15s clip and CUT into
5-6 segments via ffmpeg, rather than firing 5-6 separate Seedance calls.
Cheaper ($4.54 vs $22) AND maintains visual consistency across segments
(same camera/grade/subject — what Seedance does well in one call).
-
Center-crop, don't regen for 9:16. Generate Seedance at 1:1 and
center-crop to 9:16 in post. Generating natively 9:16 in Seedance is more
expensive and quality-equivalent. ~25% horizontal context loss is acceptable
for the product-centric framing.
-
Real brand logo > typeset wordmark on end card. Always use the actual
brand SVG/PNG, not typeset text. Per memory feedback_brand_asset_end_card.md
— typeset wordmarks miss distinctive letterforms (Soundboks has custom
italic-slanted glyphs that Space Grotesk Bold can't approximate). See also
LEARNINGS.md #138.
-
Brand voice drives aesthetic palette. Don't apply Hope-style cream
paper + EB Garamond italic to industrial/sport/party brands. Soundboks-class
= black BG + Space Grotesk Bold + utility orange accent. Editorial/literary
brands belong in create-vignette-ad, not here. Per LEARNINGS.md #139.
-
Outline echo at 1.08x is the bleed-safe sweet spot. Larger (1.2x+) reads
as accidental clipping; smaller defeats the ambient-shadow purpose. Validated
on Soundboks V8→V9 bleed audit. Per LEARNINGS.md #140.
-
Never freeze after settle on the wordmark. Continuous ±1% scale pulse +
±3px horizontal drift for the entire 3.5s end card hold. 3+ seconds of
frozen text feels like a JPEG. Per LEARNINGS.md #141.
-
Hypermotion prompt must include ABSOLUTE CONSTRAINTS block. Without it,
Seedance lets geometry drift mid-clip (V2 broke to cowbell shape). Block
must include: "no character contact, no multi-product, label-locked geometry,
physics effects (heat-shimmer, dust) in environment only NOT on product." Per
memory feedback_hypermotion_prompt_recipe.md.
-
ffmpeg mux: ALWAYS explicit -map 0:v -map 1:a + SEPARATE pass from concat.
Default mapping silently produces 1 kbps garbage audio. Per memory
feedback_ffmpeg_map_directive.md + feedback_ffmpeg_lcut_endcard_recipe.md.
-
Use STATIC font TTFs, never variable. PIL doesn't respect variable font
axes — SpaceGrotesk[wght].ttf renders as Regular weight regardless of the
weight axis. Always download single-weight static TTFs (/static/ subfolder
on most font repos).
Quality Checks
Before declaring done, verify the final mp4:
Failure Modes
| Failure | Cause | Recovery |
|---|
| Hypermotion geometry drifts mid-clip (product morphs shape) | Prompt lacks ABSOLUTE CONSTRAINTS block | Add the 5th block per references/hypermotion-prompt-recipe.md. Regen ($4.54). |
| Hypermotion shows character touching product | "Character" entered prompt at all | Strip all human/hand references from prompt. Add "no character contact" to constraints. |
| Text cards bleed off frame | Outline echo scale > 1.08x | Tighten echo to 1.08x. Re-render PIL (free). |
| Fonts render as Regular weight despite Bold being specified | Downloaded variable font TTF | Replace with static TTF from /static/ subfolder of font repo |
| End card wordmark looks generic/wrong | Used typeset font instead of real logo | Extract real logo PNG from brand SVG via base64 decode. Re-render. |
| End card feels frozen after 1s | No micro-motion phase added | Add scale = 1.0 + 0.010*sin(t*1.4); x_off = 3*sin(t*1.1) after settle phase |
| Final mp4 audio is 1 kbps | ffmpeg mux without explicit map | Add -map 0:v -map 1:a per memory feedback_ffmpeg_map_directive.md |
| Music tapers in 2nd half | Known ElevenLabs Music behavior | Generate 20% longer than target + trim. OR loop-and-flatten with acrossfade + acompressor + loudnorm per feedback_elevenlabs_music_decay.md |
| 9:16 crop loses critical product detail | Hypermotion framed product at horizontal edges | Re-generate Seedance with explicit "subject centered, vertical-safe composition" in prompt |
gen_kinetic_cards.py script fails on font load | Wrong font path or font not downloaded | Verify source/fonts/SpaceGrotesk-Bold.ttf exists; re-download from raw.githubusercontent.com/floriankarsten/space-grotesk/master/fonts/ttf/static/ |
| Brand logo SVG isn't a base64 PNG wrapper | Pure vector SVG (rare) | Use rsvg-convert -w 2400 logo.svg > logo.png instead |
| Hypermotion clip is silent but final has music too quiet | Music loudnorm not applied | Add acompressor=threshold=-12dB:ratio=2:attack=20:release=200,loudnorm=I=-14:TP=-1.5:LRA=9 to music before mux |
Spend Reference (validated on Soundboks V10, 2026-05-28)
| Item | Count | Per-unit | Subtotal |
|---|
| Seedance 2.0 i2v 15s (1080p, audio off) | 1 | $4.54 | $4.54 |
| ElevenLabs Music 25s | 1 | $0.45 | $0.45 |
| Brand logo PNG extraction (base64 decode) | 1 | $0.00 | $0.00 |
| PIL kinetic typography rendering (8 clips) | 8 | $0.00 | $0.00 |
| ffmpeg concat + mux + crop | 1 | $0.00 | $0.00 |
| V1 marginal cost (no iteration) | | | ~$4.99 |
For full multi-iteration runs (Soundboks did V1→V10): ~$17.43 total. V10 alone is
$5 to reproduce. Most "iteration cost" is PIL re-renders + ffmpeg = $0.
Sub-Archetypes (none yet)
This molecule has 1 validated sub-archetype: the Soundboks pattern (industrial
voice, single-product hero, 5-7 spec callouts, brand-asset end card).
Future sub-archetypes pending multi-brand validation:
- PH-LUXURY — luxury brand voice (gold + monochrome typography, slower BPM, longer holds)
- PH-SPORT — sport/fitness voice (high-saturation accent, faster BPM ~140, athletic motion verbs)
- PH-PLAYFUL — pop/retail voice (bright color blocks, bold display sans, exaggerated 3D extrusion)
Until validated on N=2+ brands per sub-archetype, treat them as open
questions, not Decision Rules.
Tests
See tests/:
smoke-test.md — structural pass (all required files exist, frontmatter valid)
sample-input.md — Soundboks worked example
expected-output.md — what successful output looks like
human-test.md — manual acceptance criteria
verifier.md — ffmpeg + ffprobe assertions
Related
Originally validated in content-goose at clients/soundboks/video-02-hypermotion/. Adapt paths to your project.
- Reference project:
clients/soundboks/video-02-hypermotion/ — full worked
example with HOW_TO_MAKE_THIS_VIDEO.md (V1→V10 iteration history)
- Reference scripts:
clients/soundboks/video-02-hypermotion/working/scripts/gen_kinetic_v6.py — 8 spec/filler cards
clients/soundboks/video-02-hypermotion/working/scripts/gen_endcard_v10.py — brand-asset end card
clients/soundboks/video-02-hypermotion/working/scripts/assemble_v10.py — concat + mux template
- Related molecules:
skills/molecules/ad-format/create-vignette-ad — for editorial/luxury brand voices
skills/molecules/ad-format/create-value-prop-ad — for VO-led value prop ads
skills/molecules/product-video/create-product-stopmotion-video — for tabletop stop-motion
skills/molecules/ugc-ad/* — for UGC creator ads
- Memory rules to read before running:
reference_kinetic_typography_pipeline.md — full PIL pipeline reference (11 techniques + code)
feedback_brand_asset_end_card.md — real logo > typeset
feedback_hypermotion_prompt_recipe.md — 5-block Seedance prompt template
feedback_ffmpeg_map_directive.md — -map 0:v -map 1:a always
feedback_ffmpeg_lcut_endcard_recipe.md — separate concat + mux passes
feedback_music_with_vocals_default.md — vocals OK for product ads
feedback_elevenlabs_music_decay.md — generate longer + trim
- LEARNINGS.md rules: #137 (PIL kinetic typography supersets atom),
#138 (real brand assets on end cards), #139 (brand aesthetic per voice
register), #140 (outline echo 1.08x sweet spot), #141 (never freeze after settle).
Back-propagation to skill atom (future work)
The existing skills/atoms/motion-graphics/create-kinetic-typography atom
exposes 5 animation_type options. This molecule's PIL pipeline adds 6 more:
italic skew, outline echo, 3D extrusion, repetition stack, mask wipe,
letterbox slide, color flash, inversion flash. Worth extracting these into
the atom as new animation_type options once a 2nd brand validates the
pipeline.
Open Questions (not yet Decision Rules)
These need N=2+ project validations before promoting:
- Optimal segment count per hypermotion clip. Soundboks used 6 segments
from a 15s clip. Would 4 (longer holds) or 8 (faster cuts) be better
defaults?
- Spec callout count. Soundboks used 5 hard specs + 1 intro + 1 CTA + 1 endcard. Is 5 specs the right ceiling? Below 3 may feel sparse; above 6 may feel like a deck.
- Music BPM auto-selection per brand voice. Soundboks 124 BPM worked.
Does sport/luxury need different BPM tables?
- 9:16 vs 1:1 vs 16:9 portability. Soundboks validated 9:16. Does this
molecule produce equally-good 1:1 (Instagram feed) and 16:9 (YouTube) variants
with just a different center-crop?
- Cost of iteration. Soundboks went V1→V10 ($17.43 total). What does the
60th-percentile brand spend look like for a "first ship"?