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 window and leaf shadows to input.mp4 Second the shadows fade in: 0.5 Tilt of the blind stripes in degrees: 30
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 window and leaf shadows 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 | 0.5 | Second the shadows fade in. |
ANGLE | 30 | Tilt of the blind stripes in degrees. |
PITCH | 0.26 | Spacing of the slat shadows as a share of the frame width. Lower gives more, thinner stripes. |
SLAT | 0.45 | Share of each stripe that is shadow. |
LEAVES | 9 | Pairs of leaves along the branch. |
SWAY | 4 | Degrees the leafy branch swings either way. |
SOFTNESS | 0.012 | Blur on the shadow edges as a share of the frame width. |
SHADE, SUN | (0.45, 0.48, 0.58), (1.10, 1.03, 0.92) | What shadows and sunlit areas multiply each color channel by: cool shade, warm sun. |
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 window blind and leaf shadows to input.mp4 with Python, numpy and Pillow, reading and writing frames with ffmpeg (no stock overlay). Build a light mask from 0 (shadow) to 1 (sun). Blinds: parallel shadow stripes rotated 30 degrees counterclockwise (rising to the right), one every 26% of the frame width (140 px on a 540 px frame), each shadow taking 45% of that spacing, edges blurred with a Gaussian of radius 1.2% of the frame width; draw them on an oversized canvas so they can slide 4% of the frame width to the left over 6 seconds. Leaves: a branch silhouette hanging in from the top-right corner, a stem 5 px wide along the curve x = (1.05 - 0.75 s) x width, y = (-0.02 + 0.42 s + 0.08 sin(3 s)) x height for s from 0 to 1, with a pair of pointed leaves at s = 0.1, 0.2 ... 0.9, one on each side angled 50 degrees off the stem's direction, each (22% - 7% x s) of the frame width long and about half as wide (an outline whose half-width is 0.24 x length x sin(pi u) at fraction u along it); sway the whole branch about its top-right anchor by 4 degrees x sin(2 pi t / 2.4) plus 1.2 degrees x sin(2 pi t / 0.9), and blur it like the stripes. The light mask is the stripes' light times (1 - leaf). Multiply each pixel's RGB by SHADE + (SUN - SHADE) x light, with SHADE = (0.45, 0.48, 0.58) for cool shadows and SUN = (1.10, 1.03, 0.92) for warm sunlight. Leave the frame untouched before 0.5 seconds and fade the shadows in from 0.5 to 1.1 seconds, then keep them to the end. This effect has no text (any text would be drawn with Pillow, not ffmpeg's drawtext filter). Keep the size, 30fps and the audio, and save it as output.mp4.Run it without Claude
This is the exact script we tested. Save it as window-and-leaf-shadows.py and run:
python3 window-and-leaf-shadows.py input.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""Window and leaf shadows: slanted blind stripes and a swaying leafy branch cast soft shadows across the shot.
Usage: python3 window-and-leaf-shadows.py input.mp4 output.mp4
Needs ffmpeg, numpy and Pillow (pip install numpy pillow).
"""
import json
import math
import subprocess
import sys
import numpy as np
from PIL import Image, ImageDraw, ImageFilter
START = 0.5 # second the shadows fade in
FADE = 0.6 # seconds the fade-in takes
ANGLE = 30 # tilt of the blind stripes, degrees (they rise to the right)
PITCH = 0.26 # distance from one slat shadow to the next, as a share of the frame width
SLAT = 0.45 # share of each stripe that is shadow
DRIFT = 0.04 # how far the stripes slide over 6 seconds, as a share of the frame width
LEAVES = 9 # pairs of leaves along the branch
SWAY = 4 # degrees the branch swings either way
SWAY_PERIOD = 2.4 # seconds per swing
SOFTNESS = 0.012 # shadow edge blur, as a share of the frame width
SHADE = (0.45, 0.48, 0.58) # what the shadows multiply each channel by: dark and a little cool
SUN = (1.10, 1.03, 0.92) # what the lit areas multiply each channel by: a warm sunlight tint
def blinds():
"""Stripes of slat shadow (0) and light (1), drawn larger than the frame and tilted, so they can slide."""
side = round(math.hypot(w, h) * 1.3)
img = Image.new("L", (side, side), 255)
draw = ImageDraw.Draw(img)
pitch = w * PITCH
for k in range(int(side / pitch) + 1):
draw.rectangle([0, k * pitch, side, k * pitch + pitch * SLAT], fill=0)
return img.rotate(ANGLE, resample=Image.BICUBIC).filter(ImageFilter.GaussianBlur(w * SOFTNESS))
def branch():
"""A leafy branch hanging in from the top-right corner, as a shadow mask (255 = leaf)."""
img = Image.new("L", (w, h), 0)
draw = ImageDraw.Draw(img)
draw.line([stem(s) for s in np.linspace(0, 1, 40)], fill=255, width=max(3, w // 110))
for k in range(1, LEAVES + 1):
s = k / (LEAVES + 1)
(x0, y0), (x1, y1) = stem(s), stem(s + 0.01)
along = math.atan2(y1 - y0, x1 - x0)
for side in (-1, 1):
draw.polygon(leaf(x0, y0, along + side * math.radians(50), w * (0.22 - 0.07 * s)), fill=255)
return img
def stem(s):
"""Point s (0 at the corner, 1 at the tip) along the branch's curved stem."""
return w * (1.05 - 0.75 * s), h * (-0.02 + 0.42 * s + 0.08 * math.sin(3 * s))
def leaf(x, y, a, length):
"""A pointed leaf outline, about half as wide as it is long, from (x, y) along angle a."""
edge = [(length * u, length * 0.24 * math.sin(math.pi * u)) for u in np.linspace(0, 1, 12)]
outline = edge + [(px, -py) for px, py in reversed(edge)]
c, s = math.cos(a), math.sin(a)
return [(x + px * c - py * s, y + px * s + py * c) for px, py in outline]
def light(t):
"""How lit each pixel is at time t, 0 (full shadow) to 1 (full sun), shape (h, w, 1)."""
shift = w * DRIFT * t / 6
ox, oy = (stripes.width - w) / 2 + shift, (stripes.height - h) / 2
window = stripes.transform((w, h), Image.AFFINE, (1, 0, ox, 0, 1, oy), resample=Image.BILINEAR)
swing = SWAY * math.sin(2 * math.pi * t / SWAY_PERIOD) + SWAY * 0.3 * math.sin(2 * math.pi * t / 0.9)
leaves = leaf_mask.rotate(swing, resample=Image.BICUBIC, center=(w * 1.05, -h * 0.02))
leaves = leaves.filter(ImageFilter.GaussianBlur(w * SOFTNESS))
lit = np.asarray(window, np.float32) / 255 * (1 - np.asarray(leaves, np.float32) / 255)
return lit[..., None]
def cast(frame, t):
amount = np.clip((t - START) / FADE, 0, 1)
if amount == 0:
return frame
lit = light(t)
gain = np.array(SHADE) + (np.array(SUN) - np.array(SHADE)) * lit
gain = 1 + (gain - 1) * amount
return (frame * gain).round().clip(0, 255).astype(np.uint8)
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)
src, out = sys.argv[1:3]
w, h, rate, fps = probe(src)
stripes = blinds()
leaf_mask = branch()
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 True:
raw = reader.stdout.read(w * h * 3)
if len(raw) < w * h * 3:
break
frame = np.frombuffer(raw, np.uint8).reshape(h, w, 3)
writer.stdin.write(cast(frame, i / fps).tobytes())
i += 1
writer.stdin.close()
if reader.wait() or writer.wait():
sys.exit("ffmpeg failed")





