
broll
The creator's own B-roll (their clips, screen recordings, photos) turned into a library any agent can search in one grep - scanned once with ffprobe and ffmpeg (length, orientation, date, GPS, one contact sheet per clip), tagged by cheap Haiku sub-agents (title, description, mood, keywords, creator on screen), then placed full screen in a short by short-editing. Use for /broll setup, /broll add, /broll use, /broll search, or when the user says "my B-roll", "add these clips", "put my B-roll on this short", "find me a sunset shot".
- Installs
- 255
- Last 24h
- +20
- Trending rank
- #5908
- Security
- Not audited
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/melvynx/video-agent-skills --skill broll- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads broll automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
SKILL.md
The instructions your agent reads when the skill is triggered.
B-roll
B-roll = the images shown over the creator's voice: their own footage (street, desk at night, sunset, gym, phone in hand), screen recordings, photos. The library is read ONCE, then every edit finds "me at my desk at night" with one grep, without opening a single video.
<their clips folder>/ the files, never moved or edited
video-agent/broll/
├── library.json one entry per clip: file, length, orientation, date, GPS, tags, used in
├── library.md the same, one line per clip, newest first: what agents grep
├── sheets/<id>.jpg 6 frames of the clip in a 3x2 grid (what the taggers and you look at)
└── tags/batch-NN.json what each Haiku tagger wrote
Talk to the creator in their language, short messages, no jargon ("ta bibliothèque de B-roll", never "JSON"). Run every command from the project folder (the one holding video-agent/). Preflight: ffmpeg -version && node -v; missing: /studio-setup tools.
/broll setup
- The folder. Ask in one line where their clips are. Their own folder stays where it is (an external drive works). Clips spread everywhere:
mkdir -p video-agent/broll/clipsand copy them in. - Photos of them (to know which clips show them): their face, well lit, as
video-agent/broll/me.jpg, plus 1 to 3 more asme-2.jpg,me-3.jpg(a close-up, another cap or glasses, a frame of a clip where they surely are): with one photo alone, Haiku misses most of their clips. No photo:is_selfstays false. - The scan (about 1 s per clip). Only new files are read, so the same command adds clips later:
node -e '
const fs=require("fs"),path=require("path"),{execFileSync:x}=require("child_process");
const B="video-agent/broll",L=B+"/library.json",ext=/\.(mp4|mov|m4v|mkv|webm|jpe?g|png)$/i;
fs.mkdirSync(B+"/sheets",{recursive:true});
const lib=fs.existsSync(L)?JSON.parse(fs.readFileSync(L,"utf8")):[],known=new Set(lib.map(c=>c.file));
const walk=d=>fs.readdirSync(d,{withFileTypes:true}).flatMap(e=>e.name.startsWith(".")?[]:e.isDirectory()?walk(path.join(d,e.name)):ext.test(e.name)?[path.resolve(d,e.name)]:[]);
let n=0;
for(const f of process.argv.slice(1).flatMap(a=>fs.statSync(a).isDirectory()?walk(a):[path.resolve(a)])){
if(known.has(f))continue;
try{
const p=JSON.parse(x("ffprobe",["-v","error","-print_format","json","-show_format","-show_streams",f]).toString());
const v=p.streams.find(s=>s.codec_type==="video")||{},t=p.format.tags||{},photo=/\.(jpe?g|png)$/i.test(f);
const turn=Math.abs(+(v.tags?.rotate||(v.side_data_list||[]).find(s=>s.rotation!=null)?.rotation||0))%180===90;
const w=turn?v.height:v.width,h=turn?v.width:v.height,dur=photo?0:+p.format.duration||0;
let id=path.basename(f).replace(/\.[^.]+$/,"").toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")||"clip";
while(lib.some(c=>c.id===id))id+="-2";
const sheet=B+"/sheets/"+id+".jpg";
x("ffmpeg",["-v","error","-y","-i",f,"-vf",photo?"scale=720:-2":"fps=6/"+Math.max(dur,1)+",scale=360:-2,tile=3x2","-frames:v","1",sheet]);
const g=(t["com.apple.quicktime.location.ISO6709"]||t.location||"").match(/([+-][\d.]+)([+-][\d.]+)/);
lib.push({id,file:f,sheet,duration:Math.round(dur*10)/10,width:w,height:h,orientation:w<h?"portrait":w>h?"landscape":"square",
date:t["com.apple.quicktime.creationdate"]||t.creation_time||null,lat:g?+g[1]:null,lon:g?+g[2]:null,place:null,tags:null,used:[],status:"active"});
if(++n%20===0)fs.writeFileSync(L,JSON.stringify(lib,null,1));
}catch(e){console.log("skipped "+f+": "+e.message.split("\n")[0])}
}
fs.writeFileSync(L,JSON.stringify(lib,null,1));
console.log(n+" new, "+lib.length+" in the library, "+lib.filter(c=>!c.tags&&c.status==="active").length+" to tag");
' "<their clips folder>"
Clips with GPS: name the places, one request per distinct spot (rounded to 2 decimals), one per second, then set place ("Lisbon, Portugal") in library.json: curl -s "https://nominatim.openstreetmap.org/reverse?format=json&zoom=10&lat=<lat>&lon=<lon>" -H "User-Agent: video-agent-skills". No GPS = no place, never a guess.
4. The tagging, by Haiku (cheap and fast). Batches of 5 untagged clips; one sub-agent per batch, all launched in ONE message so they run together, 10 at a time (Claude Code: the Agent tool with model: "haiku"). No sub-agents in this tool: tag the batches yourself, same rules. Prompt of each tagger, filled in:
You tag B-roll clips for a video creator's library. Read each contact sheet below (6 frames of one clip, left to right then top to bottom, spread evenly over the clip) and video-agent/broll/me.jpg, me-2.jpg, me-3.jpg (the creator; skip the missing ones). Then Write ONE file, video-agent/broll/tags/batch-<NN>.json, then answer "done". Nothing else.
Clips: <id> (<duration> s) video-agent/broll/sheets/<id>.jpg ; ... (5 of them)
The file is one JSON object keyed by clip id, every id present, this shape:
{"<id>": {"title": "4 to 8 words", "description": "3 plain sentences: what is on screen, what moves, the light",
"setting": "desk|bedroom|kitchen|street|beach|car|gym|cafe|office|city|nature|screen|studio|...",
"subjects": [], "actions": [], "emotions": [{"name": "serenity", "intensity": 0.6}],
"mood": "calm|joyful|melancholic|tense|energetic|contemplative|neutral",
"time_of_day": "dawn|day|golden hour|sunset|evening|night|unknown",
"shot_type": "close-up|medium|wide|screen|aerial", "keywords": ["8 to 15 words someone would search"],
"has_people": true, "is_self": false, "quality_flags": ["blur|shaky|dark|overexposed|watermark"], "best_start": 0}}
Rules: only what is visible, never a place, brand or name you cannot read on screen. Everything in English. emotions 0 to 2, only when the image clearly carries one. is_self: compare every face with the creator photos (face shape, nose, eyebrows, hair, glasses); same person = true, even with another cap, glasses or clothes, in a mirror selfie or small in the frame; an arm's-length selfie is usually them, look twice; hands or back only = false. best_start = the second where the clean part starts (frame k of 6 is at about k/6 of the length), 0 when clean from the start. Valid JSON, no comment.
Then merge every batch and rebuild library.md (also after any change by hand to library.json):
node -e '
const fs=require("fs"),B="video-agent/broll",L=B+"/library.json",lib=JSON.parse(fs.readFileSync(L,"utf8"));
fs.mkdirSync(B+"/tags",{recursive:true});
const T=Object.assign({},...fs.readdirSync(B+"/tags").filter(f=>f.endsWith(".json")).map(f=>JSON.parse(fs.readFileSync(B+"/tags/"+f,"utf8"))));
for(const c of lib)if(T[c.id])c.tags={...(c.tags||{}),...T[c.id]};
fs.writeFileSync(L,JSON.stringify(lib,null,1));
const k=c=>c.tags||{},row=c=>[c.id,c.duration+"s",c.orientation,(c.date||"").slice(0,10),c.place||"",k(c).title||"(untagged)",k(c).mood||"",k(c).time_of_day||"",
[...(k(c).keywords||[]),...(k(c).emotions||[]).map(e=>e.name),k(c).setting||""].join(" "),k(c).is_self?"me":"",(k(c).quality_flags||[]).join(" "),c.used.length?"used "+c.used.length:""].join(" | ");
const on=lib.filter(c=>c.status==="active").sort((a,b)=>(b.date||"").localeCompare(a.date||""));
fs.writeFileSync(B+"/library.md","# B-roll library\n\nid | length | orientation | date | place | title | mood | time | keywords | me | flags | used\n"+on.map(row).join("\n")+"\n");
console.log(on.length+" clips, "+on.filter(c=>!c.tags).length+" untagged, "+on.filter(c=>k(c).is_self).length+" with the creator");
'
A batch file that is not valid JSON or misses an id: run its tagger again. A big library (300+ clips): tag 100 now, say so, the rest in the background or the first time a video needs B-roll.
5. Check, with the creator: 3 searches from their real topics (below), Read the sheets of the hits, show what you found ("pour « bureau la nuit » j'ai ces 3 plans"). A wrong tag: fix it in library.json and rebuild. A clip they never want: reject it.
6. One line to them: "ta bibliothèque est prête : N clips. Dis « ajoute ces vidéos » pour en mettre d'autres, « mets mes B-roll » sur un short."
/broll add
Their files or a folder: copy them into their clips folder (or scan them where they are), then steps 3 and 4 on the new ones only (the scan skips known files, the taggers get only tags: null). Say what came in: "12 clips ajoutés : 4 à Lisbonne en août, 8 au bureau".
/broll search
grep -i -E "sunset|dusk|golden" video-agent/broll/library.md
grep -i "desk" video-agent/broll/library.md | grep -i "night" | grep "| me |"
English words of what the image should show; synonyms joined with |, a second filter with a second grep. Rank the hits yourself: matches the line, then unused, then recent, then the right orientation (portrait for a short; a landscape clip is cropped to fill). Then Read the sheets of the 3 best: the tags help you find, only your eyes validate.
/broll use
The short in progress (video-agent/edits/<slug>/ or named): its B-roll from its words.
- Read the transcript (
files/words.mdof the short, source seconds). Mark the lines that show a moment or a place ("I moved to Lisbon"), a feeling ("I was exhausted"), the creator doing something ("I code at night"), a thing they use. Numbers, ideas and proof stay as boards. - One search per line; Read the sheets. A clip goes in only if the image fits the sentence (a calm line over a calm image), the clean part from
best_startlasts the whole stretch, and nothing is wrong on screen (blur, a stranger's face, a private screen). At most one B-roll every 8 to 15 s, 2 to 5 s each, 5 s of the creator between two. - Name each picked clip in the spec's
media(source/spec.js):<id>: { src: '<file>', from: <best_start>, dur: <s>, fill: true }(fillcrops a landscape clip to 9:16,focus: [x, y]keeps a part of it). - Add them to
brollin the same spec:{ media: '<id>', from: <source s of the first word>, to: <source s of the last word> }(short-editing'sreferences/scene-library.md, "Full-screen B-roll"), thenprepareagain (it extracts the frames). short.mjs stillsin the middle of each stretch, Read them, then the full render (short-editingsteps 5 and 6).- The creator keeps the short: add the slug to each clip's
usedinlibrary.jsonand rebuildlibrary.md, so the next shorts prefer fresh clips.
No good hit = the library lacks that image: keep the creator on screen or a board, never a random clip.
/broll reject
"status": "rejected" on that clip in library.json ("active" brings it back), then rebuild library.md: it never comes up again. The file itself is never deleted: it is the creator's footage.
FAQ
What does the broll skill do?
The creator's own B-roll (their clips, screen recordings, photos) turned into a library any agent can search in one grep - scanned once with ffprobe and ffmpeg (length, orientation, date, GPS, one contact sheet per clip), tagged by cheap Haiku sub-agents (title, description, mood, keywords, creator on screen), then placed full screen in a short by short-editing. Use for /broll setup, /broll add, /broll use, /broll search, or when the user says "my B-roll", "add these clips", "put my B-roll on this short", "find me a sunset shot".
How do I install broll?
Run npx skills add https://github.com/melvynx/video-agent-skills --skill broll in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/broll/ (personal) or .claude/skills/broll/ (project).
Which AI agents can use broll?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is broll safe to install?
No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.
Who maintains broll?
It is published by melvynx in melvynx/video-agent-skills. It has 255 recorded installs.
More from melvynx/video-agent-skills
short-editing
melvynx/video-agent-skills
Edits a talking-head take end to end into a paper-style motion design short (1080x1920, also 1:1 and 16:9) with its own render engine (Node + Chrome + ffmpeg, free, offline). Use when the user says edit, cut, captions, subtitles, motion design, montage, "make it a short", render, or gives a recording from video-agent/takes/. Transcribes locally with word timings (whisper.cpp, or ElevenLabs when a key is set), cuts every silence, lays the boards on a textured paper above the camera card (counters, terminals, logos, trees, real screens, HTML motion components), word-by-word captions, a calm music bed, a few designed hits, -14 LUFS, and writes the mp4, an .srt and the post copy.
studio-script
melvynx/video-agent-skills
The scriptwriter of the creator's videos - short-form scripts (YouTube Shorts, TikTok, Instagram Reels, 30 to 60 s) in their own voice from video-agent/voice.md, each on a concept proven by the niche's outliers, with 3 scored hooks from 22 formulas, a re-hook, triggers, offer proximity, quality gates, timing at their pace and visual notes, then a humanize pass (invisible characters, AI words in English and French, AI sentence shapes, facts kept). Modes - the week (default), one topic, a funnel or divisive script, a making-of, hook printer, rewrite, humanize, and viral (what over-performs in their niche, scored against each account's median, YouTube free with yt-dlp, TikTok and Instagram through Treg, into video-agent/swipe.md). Use when the user asks for scripts, ideas, this week's videos, a funnel or divisive (clivant) script, a making-of, a hook, a better hook, to rewrite a script, what goes viral, viral hooks, what works in my niche, competitor research, swipe file, outliers, or to
codex-images
melvynx/video-agent-skills
Open the skill to read its SKILL.md instructions.
studio-setup
melvynx/video-agent-skills
Open the skill to read its SKILL.md instructions.
steal
melvynx/video-agent-skills
Open the skill to read its SKILL.md instructions.
clips
melvynx/video-agent-skills
Turns one long video (YouTube link, podcast, webinar, livestream, or a local file) into finished vertical shorts. Use when the user says long to short, repurpose, long video to shorts, clips from my video, podcast clips, cut my YouTube video into shorts, or gives a long video link. Finds clips that stand alone (one idea, 20 to 60 seconds), scores them, cuts them and edits each one with short-editing (split-screen paper look, captions, cuts, hook, boards, 1080x1920), and writes new scripts in the studio-script format from the ideas too spread out to clip. Reads YouTube captions and chapters with yt-dlp, or transcribes a local file with the short-editing engine (whisper.cpp, free, offline).
Popular media & creative skills
hyperframes
heygen-com/hyperframes
Read first to make, edit, animate or render any video with HyperFrames (HTML rendered to video), including launch films, explainers, music videos, charts, maps, vertical clips, title cards, captions and overlays. Holds the render contract, the work loop and what each kind of video needs.
media-use
heygen-com/hyperframes
Get or make any media for a HyperFrames video - music, sound effects, images, icons, logos, voiceover, avatar and generated video, transcripts, cutouts, colour grades and looks - with HeyGen or free local tools, and mix placed audio. Also for footage that looks dark, flat or dull, or should be stylized or hidden.
hyperframes-registry
heygen-com/hyperframes
About 450 ready-made HyperFrames blocks and components installed as editable source - transitions, overlays, titles, kinetic type, captions, charts, map overlays, 3D, camera moves. Use it before hand-building any named visual (CRT scanlines, glitch, film grain, a chart); also for hyperframes add and catalog.
hyperframes-creative
heygen-com/hyperframes
Non-animation creative direction for HyperFrames videos. Use for design spec (frame.md / design.md) handling, palettes, typography, narration, beat planning, audio-reactive visuals, composition patterns, and brand / style decisions. For atomic motion patterns and scene blueprints, use hyperframes-animation.
ai-video-generation
101-skills/superpowers
Generate AI videos with Google Veo, Seedance 2.0, HappyHorse, Wan, Grok and 40+ models via inference.sh CLI. Models: Veo 3.1, Veo 3, Seedance 2.0, HappyHorse 1.0, Wan 2.5, Grok Imagine Video, OmniHuman, Fabric, HunyuanVideo. Capabilities: text-to-video, image-to-video, reference-to-video, video editing, lipsync, avatar animation, video upscaling, foley sound. Use for: social media videos, marketing content, explainer videos, product demos, AI avatars. Triggers: video generation, ai video, text to video, image to video, veo, animate image, video from image, ai animation, video generator, generate video, t2v, i2v, ai video maker, create video with ai, runway alternative, pika alternative, sora alternative, kling alternative, seedance, happyhorse
ai-image-generation
101-skills/superpowers
Generate AI images with GPT-Image-2, FLUX, Gemini, Grok, Seedream, Reve and 50+ models via inference.sh CLI. Models: GPT-Image-2, FLUX Dev LoRA, FLUX.2 Klein LoRA, Gemini 3 Pro Image, Grok Imagine, Seedream 4.5, Reve, ImagineArt. Capabilities: text-to-image, image-to-image, inpainting, LoRA, image editing, upscaling, text rendering. Use for: AI art, product mockups, concept art, social media graphics, marketing visuals, illustrations. Triggers: flux, image generation, ai image, text to image, stable diffusion, generate image, ai art, midjourney alternative, dall-e alternative, text2img, t2i, image generator, ai picture, create image with ai, generative ai, ai illustration, grok image, gemini image, gpt image, openai image, chatgpt image