Beat-Sync Reel Generator
Generates Instagram Reels where product image cuts are synced to audio beats.
How to use it
- Hit Copy SKILL.md — or use the Claude Code line below to get every file.
- Claude: ⋯ → Download .md, then Customize → Skills → Add → Upload skill.
ChatGPT: make a Project and paste it into Instructions.
Neither? Paste it at the top of a new chat — it works for that chat. - Describe your job in plain words. The AI follows the skill from there.
npx degit gooseworks-ai/goose-skills/skills/design/packs/video-production/beat-sync-reel#main ~/.claude/skills/beat-sync-reelFor one project only, change the path to .claude/skills/beat-sync-reel. This skill also uses concat.txt — copying SKILL.md alone won't be enough. See the folder on GitHub.
Not working?
- Check which app you pasted it into — the steps above name the right one.
- Some skills need the paid tier of Claude or ChatGPT.
Paste into Claude, ChatGPT or Cursor.
Show the full text264 lines
Beat-Sync Reel Generator
Takes product images and a trending audio track, detects beats, and produces an Instagram Reel where every image cut lands exactly on a beat. Fast, free (no API credits), and scalable.
Requirements
- Python 3 with
librosaandPillowpackages - FFmpeg installed
- yt-dlp installed (for URL/search audio input)
Input
The user provides:
Audio (required) — one of three formats:
- Local file path — e.g.
/path/to/trending-audio.mp3 - URL — Instagram Reel, TikTok, or YouTube link. Download with:
yt-dlp -x --audio-format mp3 -o "audio.%(ext)s" "<URL>" - Audio name — e.g. "Nashe Si Chadh Gayi". Web search for it, find a YouTube/SoundCloud source, download with yt-dlp.
- Local file path — e.g.
Product images (required) — one of:
- List of image file paths — local JPG/PNG files
- Product page URL — scrape images using these methods in order until one works:
- Shopify JSON — append
.jsonto the product URL and extract image URLs from the response - HTML scraping with referrer —
curlwith-H "Referer: <site-domain>"and a browser user-agent, then parse `` tags - Chrome DevTools — navigate to the page, extract image URLs via JavaScript, download each
- Shopify JSON — append
Audio segment (optional) —
startandendtimestamps in seconds to use a specific portion of the audio. Defaults to 0-15s.Beat frequency (optional) — cut on every Nth beat. Defaults to
2(every 2nd beat, ~1.3s per image at typical tempos). Use1for fast cuts,4for slower.Product info (optional) — brand name, product name, price, CTA URL. Used for end card. If not provided, skip end card.
Style preset (optional) — for end card text. One of:
minimal,luxury,bold,editorial,clean. Defaults toclean. See Style Presets table below for font details.
Pipeline
Step 1: Resolve Audio
Based on input type:
Local file:
# Just verify it exists and get duration
ffprobe -v quiet -print_format json -show_format "audio.mp3"
URL (Instagram/TikTok/YouTube):
yt-dlp -x --audio-format mp3 -o "<workdir>/audio.%(ext)s" "<URL>"
Audio name (search):
- Web search for
"<audio name>" site:youtube.comor"<audio name>" instagram audio - Take the first YouTube/SoundCloud result
- Download:
yt-dlp -x --audio-format mp3 -o "<workdir>/audio.%(ext)s" "<URL>"
Step 2: Detect Beats
import librosa
import numpy as np
y, sr = librosa.load("audio.mp3", sr=None)
tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr)
beat_times = librosa.frames_to_time(beat_frames, sr=sr)
beat_times = [float(t) for t in beat_times]
Select cut points based on beat frequency:
# beat_freq = 2 means every 2nd beat
cut_times = [0.0] + [beat_times[i] for i in range(beat_freq - 1, len(beat_times), beat_freq)]
Trim to audio segment:
start, end = 0.0, 15.0 # or user-provided
cut_times = [t - start for t in cut_times if start <= t < end]
if cut_times[0] != 0.0:
cut_times.insert(0, 0.0)
Typical results by tempo:
| Tempo (BPM) | Beat interval | Every 2nd beat | Cuts in 15s |
|---|---|---|---|
| 80 | 0.75s | 1.5s | ~10 |
| 100 | 0.60s | 1.2s | ~12 |
| 120 | 0.50s | 1.0s | ~15 |
| 140 | 0.43s | 0.86s | ~17 |
If cuts > available images, cycle through images with different Ken Burns effects.
Step 3: Classify & Filter Images
If images were scraped from a product URL, filter out infographics and size charts:
- Skip images with text overlays, size charts, comparison graphics (typically wider aspect ratios, or contain large text blocks)
- Keep model photos, product-only photos, detail shots
Classification heuristic (by position on product page):
| Position | Likely Type |
|---|---|
| Image 1 (first on page) | Hero / front-facing model |
| Image 2 | Alternate angle (side/back) |
| Image 3-4 | Close-up or detail |
| Last image | Size guide or back view |
Model vs product-only detection: If image height > 1.5× width AND file size > 100KB → likely a model photo. Otherwise → product-only photo.
Order images for visual variety: hero → detail → alternate angle → repeat.
Step 4: Create Ken Burns Scenes
For each cut interval, create a Ken Burns clip from the assigned image. Alternate through these effects:
# Zoom in center
ffmpeg -y -loop 1 -i "image.jpg" \
-vf "scale=2160:3840,zoompan=z='1+0.08*in/{frames}':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d={frames}:s=1080x1920:fps=25" \
-t {duration} -c:v libx264 -pix_fmt yuv420p -r 25 scene.mp4
# Zoom out center
zoompan=z='1.15-0.08*in/{frames}':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d={frames}:s=1080x1920:fps=25
# Pan left to right
zoompan=z='1.08':x='(iw-iw/zoom)*in/{frames}':y='ih/2-(ih/zoom/2)':d={frames}:s=1080x1920:fps=25
# Pan right to left
zoompan=z='1.08':x='(iw-iw/zoom)*(1-in/{frames})':y='ih/2-(ih/zoom/2)':d={frames}:s=1080x1920:fps=25
# Zoom in top-center (for torso/face crops)
zoompan=z='1+0.08*in/{frames}':x='iw/2-(iw/zoom/2)':y='ih/4-(ih/zoom/4)':d={frames}:s=1080x1920:fps=25
# Pan up
zoompan=z='1.06':x='iw/2-(iw/zoom/2)':y='(ih-ih/zoom)*(1-in/{frames})':d={frames}:s=1080x1920:fps=25
Where {frames} = int(duration * 25) (25 fps).
Important: Always scale source image to at least 2160x3840 before zoompan so there's enough resolution for the zoom.
Step 5: Create End Card (Optional)
If product info is provided, create a 2-second end card using Pillow:
from PIL import Image, ImageDraw, ImageFont
card = Image.new("RGBA", (1080, 1920), (20, 20, 20, 255))
draw = ImageDraw.Draw(card)
# Brand name (centered, y=750)
# Product name (centered, y=830)
# Price (centered, y=920, accent color)
# CTA (centered, y=1020, muted)
card.save("endcard.png")
Convert to video:
ffmpeg -y -loop 1 -i endcard.png -vf "scale=1080:1920" \
-t 2 -c:v libx264 -pix_fmt yuv420p -r 25 endcard.mp4
Style Presets
Fonts are provided as shared files in the pack's fonts/ directory (copied into each skill on install). Fall back to system fonts if custom fonts are not found.
| Preset | Title Font | Body Font | Text Color | Treatment |
|---|---|---|---|---|
| minimal | Montserrat-Light.ttf | Montserrat-Light.ttf | White (255,255,255) | No background, subtle shadow |
| luxury | System Didot (/System/Library/Fonts/Supplemental/Didot.ttc) | Cormorant-Regular.ttf | Cream (245,235,210) | Thin gold stroke |
| bold | System Futura (/System/Library/Fonts/Supplemental/Futura.ttc) | Montserrat-Bold.ttf | White | Dark backdrop bar, uppercase |
| editorial | Cormorant-Italic.ttf | Cormorant-Regular.ttf | White | Minimal, italic titles |
| clean | System Helvetica (/System/Library/Fonts/Helvetica.ttc) | System Helvetica | White | Simple shadow, professional |
Step 6: Concatenate Scenes
cat > concat.txt << EOF
file 'scene-00.mp4'
file 'scene-01.mp4'
...
file 'endcard.mp4'
EOF
ffmpeg -y -f concat -safe 0 -i concat.txt \
-c:v libx264 -pix_fmt yuv420p -r 25 reel-silent.mp4
Step 7: Add Audio
ffmpeg -y -i reel-silent.mp4 -i audio.mp3 \
-filter_complex "[1:a]atrim={start}:{end},asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5,afade=t=out:st={fade_start}:d=2,volume=0.8[aud]" \
-map 0:v -map "[aud]" \
-c:v copy -c:a aac -shortest output.mp4
Where {start} and {end} are the audio segment timestamps, and {fade_start} = total_duration - 2.0.
Output
Save the final reel to a user-specified directory (or the current working directory).
Output specs:
- Format: MP4 (H.264)
- Resolution: 1080x1920 (9:16 portrait)
- Frame rate: 25fps
- Duration: typically 10-20 seconds (depends on audio segment)
- Audio: AAC
Known Limitations
- No AI video generation — this skill only uses Ken Burns (zoom/pan on stills). For AI-animated clips, use the
product-reel-generatorskill which supports Higgsfield/Kling/Seedance video generation APIs. - Infographic filtering is heuristic — may not catch all non-product images. Agent should visually verify scraped images before using.
- Very fast tempos (>140 BPM) — even with beat_freq=2, cuts may be too rapid (<0.9s). Use beat_freq=4 for high-tempo tracks.
- Audio quality from yt-dlp — depends on source. Instagram/TikTok audio is often 128kbps. YouTube is usually better.
- No drawtext in FFmpeg — many FFmpeg installations lack the drawtext filter. Always use Pillow for text → PNG → overlay.
- Micro-cuts — if beats are unevenly spaced, some scenes may be very short (<0.3s). The agent should check for and merge these.
Cost
Free. No API credits needed. Only uses FFmpeg, librosa, and Pillow — all local processing.
Example Usage
User: "Make a beat-sync reel for this product: https://www.damensch.com/products/full-sleeve-polo
Use this audio: https://www.instagram.com/reels/audio/123456789/
Cut on every 2nd beat, use the first 15 seconds"
Agent:
1. Downloads audio with yt-dlp
2. Scrapes product images from URL
3. Detects beats with librosa
4. Creates Ken Burns clips at beat intervals
5. Adds end card with product info
6. Mixes audio
7. Outputs reel
| 1 | |
| 2 | name beat-sync-reel |
| 3 | description Generates Instagram Reels where product image cuts are synced to audio beats. Accepts audio as a local file, URL, or search query. Uses librosa for beat detection, FFmpeg Ken Burns for scene animation, and Pillow for text overlays. No AI video generation — fully free, fast, and scalable. |
| 4 | user-invocable true |
| 5 | allowed-tools Bash, Read, Write, Edit, Grep, Glob, WebSearch |
| 6 | argument-hint "[product-url-or-image-paths] [audio-source]" |
| 7 | |
| 8 | |
| 9 | # Beat-Sync Reel Generator |
| 10 | |
| 11 | Takes product images and a trending audio track, detects beats, and produces an Instagram Reel where every image cut lands exactly on a beat. Fast, free (no API credits), and scalable. |
| 12 | |
| 13 | |
| 14 | |
| 15 | ## Requirements |
| 16 | |
| 17 | **Python 3** with `librosa` and `Pillow` packages |
| 18 | **FFmpeg** installed |
| 19 | **yt-dlp** installed (for URL/search audio input) |
| 20 | |
| 21 | |
| 22 | |
| 23 | ## Input |
| 24 | |
| 25 | The user provides: |
| 26 | |
| 27 | **Audio** (required) — one of three formats: |
| 28 | **Local file path** — e.g. `/path/to/trending-audio.mp3` |
| 29 | **URL** — Instagram Reel, TikTok, or YouTube link. Download with: `yt-dlp -x --audio-format mp3 -o "audio.%(ext)s" "<URL>"` |
| 30 | **Audio name** — e.g. "Nashe Si Chadh Gayi". Web search for it, find a YouTube/SoundCloud source, download with yt-dlp. |
| 31 | |
| 32 | **Product images** (required) — one of: |
| 33 | **List of image file paths** — local JPG/PNG files |
| 34 | **Product page URL** — scrape images using these methods in order until one works: |
| 35 | **Shopify JSON** — append `.json` to the product URL and extract image URLs from the response |
| 36 | **HTML scraping with referrer** — `curl` with `-H "Referer: <site-domain>"` and a browser user-agent, then parse `<img>` tags |
| 37 | **Chrome DevTools** — navigate to the page, extract image URLs via JavaScript, download each |
| 38 | |
| 39 | **Audio segment** (optional) — `start` and `end` timestamps in seconds to use a specific portion of the audio. Defaults to 0-15s. |
| 40 | |
| 41 | **Beat frequency** (optional) — cut on every Nth beat. Defaults to `2` (every 2nd beat, ~1.3s per image at typical tempos). Use `1` for fast cuts, `4` for slower. |
| 42 | |
| 43 | **Product info** (optional) — brand name, product name, price, CTA URL. Used for end card. If not provided, skip end card. |
| 44 | |
| 45 | **Style preset** (optional) — for end card text. One of: `minimal`, `luxury`, `bold`, `editorial`, `clean`. Defaults to `clean`. See Style Presets table below for font details. |
| 46 | |
| 47 | |
| 48 | |
| 49 | ## Pipeline |
| 50 | |
| 51 | ### Step 1: Resolve Audio |
| 52 | |
| 53 | Based on input type: |
| 54 | |
| 55 | **Local file:** |
| 56 | |
| 57 | # Just verify it exists and get duration |
| 58 | ffprobe -v quiet -print_format json -show_format "audio.mp3" |
| 59 | |
| 60 | |
| 61 | **URL (Instagram/TikTok/YouTube):** |
| 62 | |
| 63 | yt-dlp -x --audio-format mp3 -o "<workdir>/audio.%(ext)s" "<URL>" |
| 64 | |
| 65 | |
| 66 | **Audio name (search):** |
| 67 | Web search for `"<audio name>" site:youtube.com` or `"<audio name>" instagram audio` |
| 68 | Take the first YouTube/SoundCloud result |
| 69 | Download: `yt-dlp -x --audio-format mp3 -o "<workdir>/audio.%(ext)s" "<URL>"` |
| 70 | |
| 71 | ### Step 2: Detect Beats |
| 72 | |
| 73 | |
| 74 | import librosa |
| 75 | import numpy as np |
| 76 | |
| 77 | y, sr = librosa.load("audio.mp3", sr=None) |
| 78 | tempo, beat_frames = librosa.beat.beat_track(y=y, sr=sr) |
| 79 | beat_times = librosa.frames_to_time(beat_frames, sr=sr) |
| 80 | beat_times = [float(t) for t in beat_times] |
| 81 | |
| 82 | |
| 83 | **Select cut points** based on beat frequency: |
| 84 | |
| 85 | # beat_freq = 2 means every 2nd beat |
| 86 | cut_times = [0.0] + [beat_times[i] for i in range(beat_freq - 1, len(beat_times), beat_freq)] |
| 87 | |
| 88 | |
| 89 | **Trim to audio segment:** |
| 90 | |
| 91 | start, end = 0.0, 15.0 # or user-provided |
| 92 | cut_times = [t - start for t in cut_times if start <= t < end] |
| 93 | if cut_times[0] != 0.0: |
| 94 | cut_times.insert(0, 0.0) |
| 95 | |
| 96 | |
| 97 | **Typical results by tempo:** |
| 98 | |
| 99 | | Tempo (BPM) | Beat interval | Every 2nd beat | Cuts in 15s | |
| 100 | |-------------|--------------|----------------|-------------| |
| 101 | | 80 | 0.75s | 1.5s | ~10 | |
| 102 | | 100 | 0.60s | 1.2s | ~12 | |
| 103 | | 120 | 0.50s | 1.0s | ~15 | |
| 104 | | 140 | 0.43s | 0.86s | ~17 | |
| 105 | |
| 106 | If cuts > available images, cycle through images with different Ken Burns effects. |
| 107 | |
| 108 | ### Step 3: Classify & Filter Images |
| 109 | |
| 110 | If images were scraped from a product URL, filter out infographics and size charts: |
| 111 | **Skip** images with text overlays, size charts, comparison graphics (typically wider aspect ratios, or contain large text blocks) |
| 112 | **Keep** model photos, product-only photos, detail shots |
| 113 | |
| 114 | **Classification heuristic (by position on product page):** |
| 115 | |
| 116 | | Position | Likely Type | |
| 117 | |----------|-------------| |
| 118 | | Image 1 (first on page) | Hero / front-facing model | |
| 119 | | Image 2 | Alternate angle (side/back) | |
| 120 | | Image 3-4 | Close-up or detail | |
| 121 | | Last image | Size guide or back view | |
| 122 | |
| 123 | **Model vs product-only detection:** If image height > 1.5× width AND file size > 100KB → likely a model photo. Otherwise → product-only photo. |
| 124 | |
| 125 | Order images for visual variety: hero → detail → alternate angle → repeat. |
| 126 | |
| 127 | ### Step 4: Create Ken Burns Scenes |
| 128 | |
| 129 | For each cut interval, create a Ken Burns clip from the assigned image. Alternate through these effects: |
| 130 | |
| 131 | |
| 132 | # Zoom in center |
| 133 | ffmpeg -y -loop 1 -i "image.jpg" \ |
| 134 | -vf "scale=2160:3840,zoompan=z='1+0.08*in/{frames}':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d={frames}:s=1080x1920:fps=25" \ |
| 135 | -t {duration} -c:v libx264 -pix_fmt yuv420p -r 25 scene.mp4 |
| 136 | |
| 137 | # Zoom out center |
| 138 | zoompan=z='1.15-0.08*in/{frames}':x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':d={frames}:s=1080x1920:fps=25 |
| 139 | |
| 140 | # Pan left to right |
| 141 | zoompan=z='1.08':x='(iw-iw/zoom)*in/{frames}':y='ih/2-(ih/zoom/2)':d={frames}:s=1080x1920:fps=25 |
| 142 | |
| 143 | # Pan right to left |
| 144 | zoompan=z='1.08':x='(iw-iw/zoom)*(1-in/{frames})':y='ih/2-(ih/zoom/2)':d={frames}:s=1080x1920:fps=25 |
| 145 | |
| 146 | # Zoom in top-center (for torso/face crops) |
| 147 | zoompan=z='1+0.08*in/{frames}':x='iw/2-(iw/zoom/2)':y='ih/4-(ih/zoom/4)':d={frames}:s=1080x1920:fps=25 |
| 148 | |
| 149 | # Pan up |
| 150 | zoompan=z='1.06':x='iw/2-(iw/zoom/2)':y='(ih-ih/zoom)*(1-in/{frames})':d={frames}:s=1080x1920:fps=25 |
| 151 | |
| 152 | |
| 153 | Where `{frames} = int(duration * 25)` (25 fps). |
| 154 | |
| 155 | **Important:** Always `scale` source image to at least 2160x3840 before zoompan so there's enough resolution for the zoom. |
| 156 | |
| 157 | ### Step 5: Create End Card (Optional) |
| 158 | |
| 159 | If product info is provided, create a 2-second end card using Pillow: |
| 160 | |
| 161 | |
| 162 | from PIL import Image, ImageDraw, ImageFont |
| 163 | |
| 164 | card = Image.new("RGBA", (1080, 1920), (20, 20, 20, 255)) |
| 165 | draw = ImageDraw.Draw(card) |
| 166 | # Brand name (centered, y=750) |
| 167 | # Product name (centered, y=830) |
| 168 | # Price (centered, y=920, accent color) |
| 169 | # CTA (centered, y=1020, muted) |
| 170 | card.save("endcard.png") |
| 171 | |
| 172 | |
| 173 | Convert to video: |
| 174 | |
| 175 | ffmpeg -y -loop 1 -i endcard.png -vf "scale=1080:1920" \ |
| 176 | -t 2 -c:v libx264 -pix_fmt yuv420p -r 25 endcard.mp4 |
| 177 | |
| 178 | |
| 179 | #### Style Presets |
| 180 | |
| 181 | Fonts are provided as shared files in the pack's `fonts/` directory (copied into each skill on install). Fall back to system fonts if custom fonts are not found. |
| 182 | |
| 183 | | Preset | Title Font | Body Font | Text Color | Treatment | |
| 184 | |--------|-----------|-----------|------------|-----------| |
| 185 | | **minimal** | Montserrat-Light.ttf | Montserrat-Light.ttf | White (255,255,255) | No background, subtle shadow | |
| 186 | | **luxury** | System Didot (/System/Library/Fonts/Supplemental/Didot.ttc) | Cormorant-Regular.ttf | Cream (245,235,210) | Thin gold stroke | |
| 187 | | **bold** | System Futura (/System/Library/Fonts/Supplemental/Futura.ttc) | Montserrat-Bold.ttf | White | Dark backdrop bar, uppercase | |
| 188 | | **editorial** | Cormorant-Italic.ttf | Cormorant-Regular.ttf | White | Minimal, italic titles | |
| 189 | | **clean** | System Helvetica (/System/Library/Fonts/Helvetica.ttc) | System Helvetica | White | Simple shadow, professional | |
| 190 | |
| 191 | ### Step 6: Concatenate Scenes |
| 192 | |
| 193 | |
| 194 | cat > concat.txt << EOF |
| 195 | file 'scene-00.mp4' |
| 196 | file 'scene-01.mp4' |
| 197 | ... |
| 198 | file 'endcard.mp4' |
| 199 | EOF |
| 200 | |
| 201 | ffmpeg -y -f concat -safe 0 -i concat.txt \ |
| 202 | -c:v libx264 -pix_fmt yuv420p -r 25 reel-silent.mp4 |
| 203 | |
| 204 | |
| 205 | ### Step 7: Add Audio |
| 206 | |
| 207 | |
| 208 | ffmpeg -y -i reel-silent.mp4 -i audio.mp3 \ |
| 209 | -filter_complex "[1:a]atrim={start}:{end},asetpts=PTS-STARTPTS,afade=t=in:st=0:d=0.5,afade=t=out:st={fade_start}:d=2,volume=0.8[aud]" \ |
| 210 | -map 0:v -map "[aud]" \ |
| 211 | -c:v copy -c:a aac -shortest output.mp4 |
| 212 | |
| 213 | |
| 214 | Where `{start}` and `{end}` are the audio segment timestamps, and `{fade_start} = total_duration - 2.0`. |
| 215 | |
| 216 | |
| 217 | |
| 218 | ## Output |
| 219 | |
| 220 | Save the final reel to a user-specified directory (or the current working directory). |
| 221 | |
| 222 | **Output specs:** |
| 223 | Format: MP4 (H.264) |
| 224 | Resolution: 1080x1920 (9:16 portrait) |
| 225 | Frame rate: 25fps |
| 226 | Duration: typically 10-20 seconds (depends on audio segment) |
| 227 | Audio: AAC |
| 228 | |
| 229 | |
| 230 | |
| 231 | ## Known Limitations |
| 232 | |
| 233 | **No AI video generation** — this skill only uses Ken Burns (zoom/pan on stills). For AI-animated clips, use the [`product-reel-generator`] skill which supports Higgsfield/Kling/Seedance video generation APIs. |
| 234 | **Infographic filtering is heuristic** — may not catch all non-product images. Agent should visually verify scraped images before using. |
| 235 | **Very fast tempos (>140 BPM)** — even with beat_freq=2, cuts may be too rapid (<0.9s). Use beat_freq=4 for high-tempo tracks. |
| 236 | **Audio quality from yt-dlp** — depends on source. Instagram/TikTok audio is often 128kbps. YouTube is usually better. |
| 237 | **No drawtext in FFmpeg** — many FFmpeg installations lack the drawtext filter. Always use Pillow for text → PNG → overlay. |
| 238 | **Micro-cuts** — if beats are unevenly spaced, some scenes may be very short (<0.3s). The agent should check for and merge these. |
| 239 | |
| 240 | |
| 241 | |
| 242 | ## Cost |
| 243 | |
| 244 | **Free.** No API credits needed. Only uses FFmpeg, librosa, and Pillow — all local processing. |
| 245 | |
| 246 | |
| 247 | |
| 248 | ## Example Usage |
| 249 | |
| 250 | |
| 251 | User: "Make a beat-sync reel for this product: https://www.damensch.com/products/full-sleeve-polo |
| 252 | Use this audio: https://www.instagram.com/reels/audio/123456789/ |
| 253 | Cut on every 2nd beat, use the first 15 seconds" |
| 254 | |
| 255 | Agent: |
| 256 | 1. Downloads audio with yt-dlp |
| 257 | 2. Scrapes product images from URL |
| 258 | 3. Detects beats with librosa |
| 259 | 4. Creates Ken Burns clips at beat intervals |
| 260 | 5. Adds end card with product info |
| 261 | 6. Mixes audio |
| 262 | 7. Outputs reel |
| 263 | |
| 264 |