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.aidevelopment
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.
testing
Translate one English blog post into multiple target languages via parallel sub-agents, preserving frontmatter conventions, hero image, and brand voice. Use when the user shares a published English post URL or markdown path and says 'translate it', 'add other languages', 'publish in DE/ES/RU/UK', 'translate to 5 languages', or asks for localized versions of a specific post.
development
Build a complete press kit for an event, product launch, or campaign — in multiple languages — and publish it as a shareable Google Drive folder ready to send to journalists, partners, or a delegate. Produces press releases (typically DE/EN/ES, or configurable), uploads press photos and flyers, creates an Overview document for at-a-glance briefing, and creates a Handover document with pending tasks, contacts, risks, and decisions so press distribution can be delegated. Use when the user says 'I need a press release', 'create a press kit', 'press release in X languages', 'set up a Drive folder for press', 'handover doc for someone else to run press', or has an upcoming announcement that needs to be sent to media. Trigger generously: even partial requests (just a press release, just a flyer folder) typically evolve into the full kit.
development
Track ticket sales for a live event (concert, festival, conference, workshop) with daily snapshots, generate a burndown chart comparing actual sales to ideal-linear targets and tier-cumulative milestones, and report whether the event is on pace. Use when the user asks how sales are going, wants to know if their event will sell out, asks for a daily sales report, wants to set up sales tracking for an upcoming event, or asks about ticket pace / velocity / projection. Trigger generously: phrases like 'how is concert sales going', 'burndown for my event', 'are we going to sell out', 'sales velocity', 'daily ticket chart', 'how many tickets do we need to sell', or any case where the user has a ticketed event with a fixed sales window and wants visibility on pacing.