stock-footage-reel: Real Footage Reel
2026-10-11 Merge Note: For real footage reels with voiceover, this skill remains canonical. OpenMontage's documentary-montage is used only for montages without or with minimal narration. See the decision table in
<SKILLS_DIR>/INDEX.mdfor the division of responsibilities.
- For more footage sources (NASA, Library of Congress LOC, NARA, Archive.org, Wikimedia): use
python3 <SKILLS_DIR>/openmontage-house/scripts/om_clips.py --query "..." --out $D/work/om_clips, it will printpick: {"source":"file",...}entries that can be directly pasted into shots.json. Verify each license before including it in credits.json.- Current voiceover setup: Chinese uses your own ElevenLabs voice "<YOUR_VOICE_NAME>" (
<YOUR_ELEVENLABS_VOICE_ID>); English uses Sarah Explains (Nhs7eitvQWFTQBsf0yiT). Traditional Chinese main subtitles with smaller English. See EP.07 for the English voiceover process:<YOUR_WORKSPACE>/media-team/03-drafts/grokbot-team-reel/(script_en.txt, work/shots.json usessubs_zh+en, timing and editing use mktiming.py and build_custom.py from work/). Step 2 below selects the voice based on language.
Designed for Josh's (IG/Threads @bounce12340, AI entrepreneur, AI Agent, solo founder, Taiwan) content team. Follow this process; both Claude Code and the content bot can produce the final video. This skill only produces drafts; it does not post. All posting is handled by the main bot and only after Josh's confirmation.
Scripts are located at <SKILLS_DIR>/stock-footage-reel/scripts/ (abbreviated as $S). Examples in examples/, license verification in references/licenses.md.
Reference output: <YOUR_WORKSPACE>/media-team/03-drafts/stock-footage-test/test.mp4.
Content Rules (Must Follow)
- Be faithful to the original: every sentence must be traceable back to the original source. Do not fabricate numbers or citations; do not write what the original did not say as if it did. Use "summarized from" when paraphrasing.
- Credit the original author: the upper-left title must include the source author and original title; credit must be given in the end card and post description.
- Completeness over brevity: cover key points fully; do not sacrifice crucial arguments for shortness. However, keep the total video under 3 minutes.
- Natural voiceover pace; do not speed up to cram in more words. If there are too many words, split into two videos or delete secondary sentences.
- Traditional Chinese, Taiwanese usage (software, data, video, internet, quality…). Use 「」for quotation marks; do not use dashes (——); use commas or periods.
- English subtitles are our translations, not original quotes; unless the original is English and verbatim, do not enclose them in quotation marks.
- Use only footage with clear, commercial-use licenses; see
references/licenses.md. Do not log into any website, use paid sources, or bypass website restrictions.
Environment
- Pexels:
PEXELS_API_KEYis already set as an environment variable (do not print it out). Pixabay requiresPIXABAY_API_KEY(currently not available). - ASR timing:
uv run --with faster-whisper(downloads packages on first run, cached afterwards). - Fonts: Noto Sans TC / Noto Serif TC from
<YOUR_WORKSPACE>/media-team/00-profile/covers/fonts/. English uses Noto Sans. - Footage cache:
$S/../stock-footage-reel/cache/(the same footage will not be downloaded twice).
Workflow
0. Create working directory
D=<YOUR_WORKSPACE>/media-team/03-drafts/<topic>-reel ; mkdir -p $D/work ; cd $D/work
1. Write script.txt (one line = one shot)
Each line is one sentence of voiceover, optionally with [1] format. Each line should be 1 to 3 clauses, ideally 5 to 9 seconds.
2. Voiceover (ElevenLabs, via MCP; scripts cannot call MCP directly)
- Select voice by language: Chinese uses "<YOUR_VOICE_NAME>", voice_id
<YOUR_ELEVENLABS_VOICE_ID>; English uses Sarah Explains, voice_idNhs7eitvQWFTQBsf0yiT. Useuser-Elevenlabs'screative_list_voicesto verify the name before sending; do not change IDs from memory. creative_generate_speech:voice_id,model_id: "eleven_multilingual_v2",generations_count: 1(default is 4, which uses 4x credits),promptshould be the entire script (with blank lines between lines for natural pauses; do not include[1]numbers). Do not resend the same request, as it will double deduct credits.- Use
creative_get_flow_run_status(flow_id, session_ids) to poll untilall_completed, getmedia[0].url, thencurl -o vo.mp3 '<url>'(URL valid for 2 hours). - The sent text must match script.txt exactly (used for timing alignment).
Fallback: When ElevenLabs is unavailable, use
bash $S/scripts/tts_edge.sh script.txt vo.mp3(edge-tts zh-TW-HsiaoChenNeural), and changevoice.providerin shots.json to"Edge TTS (zh-TW-HsiaoChenNeural)", so the end card correctly credits it.
3. Timing alignment
uv run -q --with faster-whisper --with numpy python $S/scripts/align.py --audio vo.mp3 --script script.txt --out timing.json
This will print the start and end times of each shot and the alignment rate (over 80% is normal). Shot cuts are automatically placed at the midpoint of pauses between sentences.
4. Write shots.json (example: examples/satya_test.shots.json; the // comments below are just explanation, actual file must not contain comments)
{
"format": "1080x1920",
"title_zh": "Microsoft CEO Satya Nadella Long Essay",
"title_en": "Satya Nadella · \"Models as Insider Risks in the Super Intelligence Era\"",
"max_cut": 4.5,
"voice": {"provider": "ElevenLabs", "voice": "<YOUR_VOICE_NAME> (<YOUR_ELEVENLABS_VOICE_ID>)", "model": "eleven_multilingual_v2"},
"music": "synth",
"music_db": -17,
"shots": [
{"keywords": ["server room", "data center"], "highlight": ["internal risks"],
"en": ["Microsoft CEO Satya Nadella, in a new long essay,", "argues AI models should be managed as an internal risk."]},
{"keywords": ["computer operators"], "archival": true, "highlight": ["separation of controls"], "en": ["..."],
"pick": {"source": "archive", "id": "OnGuard1956", "starts": [630, 300]}}
],
"end_card": {"zh": ["The most trustworthy system", "[[is the one that least requires trust in the model.]]"], "en": "...", "by": "-- Summarized from Satya Nadella's 〈...〉", "dur": 4.0, "bg_shot": 2},
"cover": {"ep": "EP.05", "kicker": "Satya Nadella Long Essay", "title": "Managing AI as [[Internal Risks]]", "subtitle": "...", "clip_credit": "Footage: ...", "frame_shot": 3}
}
Key fields:
keywords: English search terms, tried in order. Write concrete visuals ("security camera", "typing keyboard close up", "server rack lights"), not abstract concepts.archival: true: This shot uses Prelinger archive footage, automatically applying magenta grade and grain. AYi's approach: use archive footage when talking about "history, past, tradition, 1970s" or metaphors like "control, permissions, surveillance"; use modern footage otherwise. Include at least one or two archive shots per video to establish the style.highlight: Words to turn gold in this shot (must exactly match the subtitle text). You can also use[[ ]]inend_card.zhto mark gold text.en: List of English subtitles; the count must equal the number of subtitle segments for that shot. First runbuild.py --planto see the auto-split segments, then write English per segment. If the count is wrong, the entire English text will be displayed on every segment.pick: Manually specify footage. Formats:{"source":"archive","id":"<identifier>","starts":[seconds,...]},{"source":"mixkit","id":"23215"},{"source":"commons","title":"File:xxx.webm","start":12},{"source":"file","path":"/abs.mp4","license":"...","author":"..."},{"source":"synth","kind":"code|terminal|grid"}.- Other:
grade("archival"/"modern"/"none"),focus_x(0 to 1, horizontal center for vertical crop),cuts(fixed number of segments for this shot). cover.frame_shot: Which shot to use for the cover clipping (take the original horizontal frame); defaults to the first archive shot.epcontinues from Josh's episode numbering.
5. Fetch footage
python3 $S/scripts/fetch_footage.py --shots shots.json --work . --timing timing.json
- Normal shot order: Pexels (with key) → Pixabay (with key) → Mixkit (only Free License) → Wikimedia Commons (PD/CC0/CC BY) → local synth fallback.
- Archival shots: Internet Archive Prelinger (only entries with metadata marked public domain) → Commons.
- Results written into
footage.jsonandcredits.json(URL, author, license for each clip). Lines starting withnote:are skipped clips and the reason. - Selecting archive segments: Automatic selection avoids opening credits and duplicate segments, but it's best to review manually:
python3 $S/scripts/fetch_footage.py --sheet archive:OnGuard1956 --work .→ generatessheet_*.jpg(one frame every 15 seconds, with seconds shown in the top-left corner). Use Read to view the images, pick timestamps, write them intopick.starts, then re-fetch that shot with--only <shot_number> --refresh. - Useful Prelinger computer topics:
OnGuard1956(IBM SAGE air defense computer, 1956: console 120s, operator 240s/300s, switches 330s/600s, "RESTRICTED AREA" door 630s, control room 660s). Other searches:computer,automation,electronic. - To change footage: modify shots.json and run
--only N --refresh.
6. Build video
python3 $S/scripts/build.py --shots shots.json --work . --out .. --name reel --plan # First check subtitle segments
python3 $S/scripts/build.py --shots shots.json --work . --out .. --name reel
Outputs (in --out): reel.mp4 (H.264/AAC, 30fps; if over 45 MB, automatically reduces bitrate and re-encodes), contact_sheet.jpg (one frame from the middle of each segment plus the end card), credits.json (contains credit_line and caption_credits for the post), cover_reel.png, cover_post.png (Vox-style clipping via <YOUR_WORKSPACE>/media-team/00-profile/covers/render.py).
Visual specifications (based on analysis of AYi's original videos):
- Hard cuts, each segment 2 to 4.5 seconds, slow horizontal pan. Archive: magenta cast, soft focus, grain, vignette. Modern: darkened, blue-cyan tint, desaturated, vignette.
- Fixed upper-left title: branding mark "●○○○ Josh | AI Solo Founder" + source Chinese title + original English title.
- Subtitles: left-aligned, maximum two lines for Chinese (Noto Sans TC Bold), with smaller English below; key terms in gold #E9A44A. Vertical version subtitle bottom at y=1490 to avoid Instagram's description area and right-side buttons.
- End card: footage darkened and blurred, serif large-font quote (second line gold), English, "-- Summarized from …", branding mark, @bounce12340, a single line of small credit text at the bottom (e.g., "Archival: Prelinger Archives (Public Domain) • Footage: Pexels • Voice: ElevenLabs").
- Audio: voiceover + sidechain compression on music (music automatically ducks during speech), 2.5-second fade-out at the end, overall loudness approximately -14 to -16 LUFS.
7. Self-check before handoff
- Use Read to view
contact_sheet.jpg: check if each frame matches its spoken sentence, if subtitles break at odd places (e.g., inside a person's name), or if any part risks being covered by Instagram's UI. - Footage must not contain: close-ups of someone else's trademark, identifiable faces in negative contexts, imagery contradicting the narrative, or watermarks.
- Every piece of footage in
credits.jsonmust have a URL and license; for CC BY, the post description must include thecaption_creditslines. - Check video length and file size (
ffprobe). - Place the final output in
<YOUR_WORKSPACE>/media-team/03-drafts/<topic>-reel/and report to the main bot: duration, size, footage sources, and any decisions that need Josh's input. Do not post.
Known Limitations
- Most current free-to-download videos on Mixkit are Restricted (personal non-commercial only); the script will skip them automatically; using them requires Josh's approval.
- archive.org occasionally is slow or returns blank; the script retries three times; on failure, that shot falls back to synth; check the
note:message and re-fetch if needed. - Prelinger archive videos are mostly 4:3, 480p; cropping to vertical significantly enlarges them; rely on soft focus and grain to mask imperfections; prefer shots with simple composition and the subject centered.
- This machine has no GPU; a 30-second video takes about 1 minute to render, a 3-minute video about 5 to 8 minutes.