skills/video-relight/SKILL.md
Transform video/image lighting, backgrounds, and environments using Beeble SwitchX API. Use this skill when the user wants to relight a video, replace a video background, improve lighting in footage, make a clip look more cinematic or professional, add studio lighting to a recording, or do any video-to-video visual effects transformation. Also trigger when the user mentions Beeble, SwitchX, or wants VFX on short clips.
npx skillsauth add razbakov/skills video-relightInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Transform lighting, backgrounds, and environments in video clips and images while preserving the original subject. Powered by the Beeble SwitchX API.
BEEBLE_API_KEY environment variable set (get one at developer.beeble.ai)ffmpeg and ffprobe installed (for video inspection and trimming)curl availableBefore anything, check the video specs to know what you're working with:
ffprobe -v quiet -print_format json -show_streams INPUT_FILE | python3 -c "
import json,sys
d=json.load(sys.stdin)
for s in d['streams']:
if s['codec_type']=='video':
fps = s.get('r_frame_rate','?')
dur = s.get('duration','?')
w, h = s.get('width','?'), s.get('height','?')
print(f'Resolution: {w}x{h}, FPS: {fps}, Duration: {dur}s')
"
Calculate total frames: duration * fps. If over 240 frames, you need to trim or split.
SwitchX accepts max 240 frames. Calculate the safe duration: 240 / fps seconds. Then trim:
ffmpeg -y -i INPUT_FILE -t SAFE_DURATION -c copy /tmp/switchx-clip.mp4
For longer videos, split into sequential chunks and process each separately. Reassemble with ffmpeg concat after all jobs complete.
Create a presigned upload URL and upload the file:
# Get upload URL
UPLOAD_RESP=$(curl -s -X POST https://api.beeble.ai/v1/uploads \
-H "x-api-key: $BEEBLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"filename": "clip.mp4"}')
UPLOAD_URL=$(echo "$UPLOAD_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin)['upload_url'])")
BEEBLE_URI=$(echo "$UPLOAD_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin)['beeble_uri'])")
# Upload file
curl -s -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--data-binary @/tmp/switchx-clip.mp4
For images, use the appropriate content type (image/png, image/jpeg).
curl -s -X POST https://api.beeble.ai/v1/switchx/generations \
-H "x-api-key: $BEEBLE_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"generation_type\": \"video\",
\"source_uri\": \"$BEEBLE_URI\",
\"alpha_mode\": \"auto\",
\"max_resolution\": 1080,
\"prompt\": \"YOUR PROMPT HERE\"
}"
Parameters:
| Parameter | Required | Description |
|-----------|----------|-------------|
| generation_type | Yes | "video" or "image" |
| source_uri | Yes | Beeble URI from upload, or a public URL |
| alpha_mode | Yes | How to separate subject from background (see below) |
| max_resolution | No | 720 or 1080 (default varies) |
| prompt | No | Text describing desired output look |
| reference_image_uri | No | Beeble URI or public URL of a reference image for style guidance |
| alpha_uri | No | Required for custom alpha mode |
| callback_url | No | Webhook URL for completion notification |
Alpha modes:
| Mode | When to use |
|------|-------------|
| auto | Default. AI detects and preserves the foreground subject automatically. Best for most cases. |
| fill | Keep everything in the original scene, just transform lighting/style. No background replacement. |
| select | Provide a first-frame mask image; AI propagates it across the video. For precise subject selection. |
| custom | Provide a full frame-by-frame mask video. Maximum control. |
JOB_ID="the id from step 4"
while true; do
RESULT=$(curl -s "https://api.beeble.ai/v1/switchx/generations/$JOB_ID" \
-H "x-api-key: $BEEBLE_API_KEY")
STATUS=$(echo "$RESULT" | python3 -c "import json,sys; print(json.load(sys.stdin)['status'])")
PROGRESS=$(echo "$RESULT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('progress',0))")
echo "Status: $STATUS, Progress: $PROGRESS%"
if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ]; then
echo "$RESULT" | python3 -m json.tool
break
fi
sleep 10
done
A completed job returns three output URLs:
| Output | Description |
|--------|-------------|
| render | The final transformed video — this is what you deliver |
| source | The original re-encoded by Beeble (for comparison) |
| alpha | The mask showing what was kept vs replaced |
OUTPUT_DIR="/path/to/output"
mkdir -p "$OUTPUT_DIR"
RENDER_URL=$(echo "$RESULT" | python3 -c "import json,sys; print(json.load(sys.stdin)['output']['render'])")
SOURCE_URL=$(echo "$RESULT" | python3 -c "import json,sys; print(json.load(sys.stdin)['output']['source'])")
ALPHA_URL=$(echo "$RESULT" | python3 -c "import json,sys; print(json.load(sys.stdin)['output']['alpha'])")
curl -s -o "$OUTPUT_DIR/render.mp4" "$RENDER_URL"
curl -s -o "$OUTPUT_DIR/source.mp4" "$SOURCE_URL"
curl -s -o "$OUTPUT_DIR/alpha.mp4" "$ALPHA_URL"
The prompt describes how you want the output to look. Good prompts are specific about lighting and environment:
Using a reference_image_uri alongside the prompt gives more precise control — upload a photo of the exact look you want.
For videos over 240 frames, split into chunks, process each, then reassemble:
# Split into 8-second chunks (at 30fps = 240 frames)
ffmpeg -i long_video.mp4 -c copy -segment_time 8 -f segment -reset_timestamps 1 /tmp/chunk_%03d.mp4
# Process each chunk through steps 3-6...
# Reassemble (create file list first)
for f in /tmp/output_chunk_*.mp4; do echo "file '$f'"; done > /tmp/chunks.txt
ffmpeg -f concat -safe 0 -i /tmp/chunks.txt -c copy final_output.mp4
Note: chunk boundaries may have visible seams since each is processed independently. For best results, overlap chunks slightly and crossfade.
| Error | Meaning | Fix |
|-------|---------|-----|
| VIDEO_TOO_MANY_FRAMES | Over 240 frames | Trim or split the video |
| SOURCE_TOO_LARGE | File too big | Compress or reduce resolution before upload |
| RATE_LIMIT_EXCEEDED | Over 5 requests/min | Wait and retry with backoff |
| CONCURRENT_LIMIT_EXCEEDED | Over 10 in-flight jobs | Wait for running jobs to finish |
| INSUFFICIENT_BALANCE | Credits depleted | Top up at developer.beeble.ai |
https://api.beeble.ai/v1x-api-key headerhttps://developer.beeble.ai/docshttps://status.beeble.aitools
--- name: handoff description: Get an agent past a browser/UI wall it can't (or must not) cross on its own — a login-gated dashboard, a CAPTCHA, a 2FA prompt, an API that keeps rejecting the write, or an irreversible click that policy says a human must make. This skill is an ESCALATION LADDER, not a first move: it tells you to try the automated browser surfaces FIRST (Chrome-in-Claude, computer-use, an autonomous browser sub-agent) and only fall back to the Handoff app — a wrapper browser that h
documentation
Summarize one or more YouTube videos from their links. Use this whenever the user pastes a youtube.com or youtu.be URL (or several) and wants to know what it's about — phrasings like "summarize to telegram", "tldr these videos", "what do these say", "summary of this talk", or just dropping links with no instruction at all. Fetches each video's real transcript via yt-dlp (not the page text, which never contains the transcript), cleans the captions, and writes a per-video summary. Default delivery is Telegram; honor any other surface the user names ("to my notes", "just here in chat", "email it"). Trigger even when the user only pastes bare links — bare YouTube links almost always mean "tell me what's in these".
data-ai
Daily Digest — Chief-of-Staff role consolidates the six top-managers into one Telegram message to the Commander, instead of six. Implements the protocol from agent-proactivity.md.
development
Seed a new or empty Instagram account with a 9-post grid (3×3) so the profile looks established the moment a new visitor lands. Designed for festivals, new businesses, product launches, conferences, communities — any time an empty IG profile would hurt conversion from external traffic (QR scans, flyer drops, cross-promo). Generates assets via /image-from-gemini (per content-publishing rules — never HTML), writes captions with hashtag sets, and outputs a posting order + cadence plan. Trigger generously: phrases like '9 posts for instagram', 'fill my IG', 'starter grid', 'launch grid', 'instagram seed', '9-post grid', 'IG account not to look empty', 'first instagram posts', 'feed bootstrap', '3x3 grid', 'instagram launch content'. Even if the user mentions only one piece (just the images, just the captions, just the order), use this skill — the grid only works as an integrated bundle.