Get this effect
Switch to Code in your Claude Desktop App
Install the skill (once)
Show the prompt
Install the Recharm video effects skill: download https://recharm-growth-staging.s3.us-east-2.amazonaws.com/website/downloads/recharm-video-effects.zip and unzip it into ~/.claude/skillsAsk for the effect
Add bokeh lights to input.mp4 Second the lights start to fade in, and how many seconds the fade takes: 0.5, 0.6 Number of circles: 24
Several videos, several effects, one ask
Put your clips in the folder, mention them with @, and ask for everything at once. Claude runs one tested script after another on each clip, then joins them.
Add bokeh lights to @clip1.mp4, put a sale badge on @clip2.mp4, give @clip3.mp4 a VHS look, then join all three with crossfades.
Settings you can change
Ask Claude to change any of these, or edit them at the top of the script.
| Setting | Default | What it does |
|---|---|---|
START, FADE | 0.5, 0.6 | Second the lights start to fade in, and how many seconds the fade takes. |
COUNT | 24 | Number of circles. |
RADIUS | (20, 72) | Smallest and largest circle radius, in pixels. |
RISE | (25, 70) | Slowest and fastest upward drift, in pixels per second. |
OPACITY | (0.3, 0.65) | How solid the faintest and strongest circles are (0-1). |
COLORS | (255, 185, 60), (255, 110, 170), (255, 215, 120) | The colors the circles cycle through. |
SEED | 7 | Change for a different arrangement of circles. |
Without the skill
Don’t want to install the skill? Paste this prompt into Claude Code and Claude writes the script itself.
Show the prompt
Add bokeh lights to input.mp4: 24 soft, see-through circles of light with radii between 20 and 72 pixels, cycling through three colors: gold (255, 185, 60), pink (255, 110, 170) and pale gold (255, 215, 120). Give each circle an opacity between 0.3 and 0.65, even across its middle, rising to 1.0x that opacity at the rim from 0.7x at the center (like a lens), fading out over the outer 20% of the radius, with a faint glow (0.25x the opacity) just outside the edge. Scatter them over the whole frame and blend them over the video normally (not added or screened). Each drifts upward at its own speed between 25 and 70 pixels per second, wrapping round from the top to the bottom, sways 20 pixels side to side over 3 to 6 seconds, and twinkles between 60% and 100% of its opacity every 1.7 seconds. Leave the frames before 0.5 seconds untouched, then fade the lights in from 0.5 to 1.1 seconds and keep them to the end. Use Python with numpy to draw and blend the circles and ffmpeg to read and write the video, keep the audio, and save it as output.mp4.Run it without Claude
This is the exact script we tested. Save it as bokeh-lights.py and run:
python3 bokeh-lights.py input.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""Bokeh lights: soft out-of-focus circles of warm gold and pink light fade in and drift slowly up the frame.
Usage: python3 bokeh-lights.py input.mp4 output.mp4
Needs ffmpeg and numpy (pip install numpy).
"""
import json
import subprocess
import sys
import numpy as np
START = 0.5 # second the lights start to fade in
FADE = 0.6 # seconds the fade-in takes
COUNT = 24 # number of circles
RADIUS = (20, 72) # smallest and largest circle radius, in pixels
RISE = (25, 70) # slowest and fastest upward drift, in pixels per second
OPACITY = (0.3, 0.65) # how solid the faintest and strongest circles are (0-1)
COLORS = [(255, 185, 60), (255, 110, 170), (255, 215, 120)] # warm gold, pink, pale gold
SEED = 7 # change for a different arrangement
def probe(path):
info = json.loads(subprocess.check_output(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
"stream=width,height,r_frame_rate", "-of", "json", path]))
s = info["streams"][0]
num, den = s["r_frame_rate"].split("/")
return s["width"], s["height"], s["r_frame_rate"], float(num) / float(den)
def disc(r, opacity):
"""How solid one bokeh circle is at each pixel (0-1): even inside, a stronger rim, a soft edge and a faint
glow around it. The sprite reaches 1.5 radii out from the center, to leave room for the glow."""
g = round(1.5 * r)
y, x = np.mgrid[-g:g + 1, -g:g + 1].astype(np.float32)
d = np.hypot(x, y) / r
edge = np.clip((1 - d) / 0.2, 0, 1) # fades out over the outer 20% of the radius
body = 0.7 + 0.3 * np.minimum(d, 1) ** 4 # rim a little stronger than the middle, like a lens
glow = 0.25 * np.exp(-((d - 0.9) / 0.3) ** 2)
return (np.maximum(edge * body, glow) * opacity)[..., None]
def lights(t):
"""The light layer at time t: its color and how solid it is at each pixel, or None before START."""
color = np.zeros((h, w, 3), np.float32)
alpha = np.zeros((h, w, 1), np.float32)
fade = np.clip((t - START) / FADE, 0, 1)
if fade == 0:
return None
for c in circles:
r = c["sprite"].shape[0] // 2
cx = round(c["x"] + 20 * np.sin(2 * np.pi * t / c["sway"] + c["phase"]))
cy = round((c["y"] - c["rise"] * t) % (h + 2 * r) - r) # wraps from the top back to the bottom
twinkle = 0.8 + 0.2 * np.sin(2 * np.pi * t / 1.7 + c["phase"])
x0, y0, x1, y1 = max(cx - r, 0), max(cy - r, 0), min(cx + r + 1, w), min(cy + r + 1, h)
if x0 < x1 and y0 < y1:
a = c["sprite"][y0 - (cy - r):y1 - (cy - r), x0 - (cx - r):x1 - (cx - r)] * twinkle
color[y0:y1, x0:x1] = color[y0:y1, x0:x1] * (1 - a) + c["color"] * a # premultiplied "over"
alpha[y0:y1, x0:x1] = alpha[y0:y1, x0:x1] * (1 - a) + a
return color * fade, alpha * fade
src, out = sys.argv[1:3]
w, h, rate, fps = probe(src)
rng = np.random.default_rng(SEED)
circles = []
for i in range(COUNT):
r = int(rng.uniform(*RADIUS))
circles.append({"x": rng.uniform(0, w), "y": rng.uniform(0, h + 2 * r), "rise": rng.uniform(*RISE),
"sway": rng.uniform(3, 6), "phase": rng.uniform(0, 2 * np.pi),
"color": np.array(COLORS[i % len(COLORS)], np.float32), "sprite": disc(r, rng.uniform(*OPACITY))})
reader = subprocess.Popen(["ffmpeg", "-v", "error", "-i", src, "-f", "rawvideo", "-pix_fmt", "rgb24", "-"],
stdout=subprocess.PIPE)
writer = subprocess.Popen(["ffmpeg", "-y", "-v", "error", "-f", "rawvideo", "-pix_fmt", "rgb24", "-s", f"{w}x{h}",
"-r", rate, "-i", "-", "-i", src, "-map", "0:v", "-map", "1:a?",
"-c:v", "libx264", "-crf", "18", "-pix_fmt", "yuv420p", "-c:a", "copy", "-shortest", out],
stdin=subprocess.PIPE)
i = 0
while raw := reader.stdout.read(w * h * 3):
img = np.frombuffer(raw, np.uint8).reshape(h, w, 3)
layer = lights(i / fps)
if layer is not None:
color, alpha = layer
img = (img * (1 - alpha) + color).astype(np.uint8)
writer.stdin.write(img.tobytes())
i += 1
writer.stdin.close()
if reader.wait() or writer.wait():
sys.exit("ffmpeg failed")





