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 falling leaves to input.mp4 Second the first leaves appear at the top edge: 0.3 Number of leaves: 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 falling leaves 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.3 | Second the first leaves appear at the top edge. |
COUNT | 30 | Number of leaves. |
SIZE | (44, 76) | Smallest and largest leaf, in pixels across. |
SPEED | (0.16, 0.26) | Fall speed range, in frame heights per second. |
SWAY | 40 | Side-to-side swing, in pixels. |
SPIN | 70 | How far a leaf rocks either way as it swings, in degrees. |
COLORS | [(232, 110, 24), (196, 38, 28), (238, 176, 32)] | Leaf colors: orange, red and gold. |
SEED | 5 | Change for a different fall of leaves. |
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 falling autumn leaves to input.mp4 (540x960). Draw a maple leaf with Pillow: a polygon whose right half runs, in units of half the leaf's width with the tip at the top, through (0, -1), (0.14, -0.72), (0.32, -0.82), (0.26, -0.44), (0.64, -0.64), (0.58, -0.38), (0.94, -0.30), (0.72, -0.10), (0.84, 0.08), (0.44, 0.10), (0.52, 0.38), (0.14, 0.24), (0.05, 0.50), mirrored for the left half, with a stem and five veins from a point just below the middle drawn in the fill color at 60% brightness. Make 30 leaves, cycling through orange (232, 110, 24), red (196, 38, 28) and gold (238, 176, 32), each 44 to 76 pixels across (random), placed at a random 4% to 96% across and 5% to 80% of the frame height above the top edge. From 0.3 seconds each leaf falls at a steady random 0.16 to 0.26 frame heights per second, swings 40 pixels side to side once every 2.2 to 3.6 seconds while rocking up to 70 degrees with the swing, and tumbles by squashing its width with the absolute cosine of a 1.5 to 3 second cycle (never below 20%); half the leaves hang upside down. A leaf that falls off the bottom comes back in above the top, so leaves keep falling to the end. Leave the frames before 0.3 seconds untouched. Use Python with Pillow and numpy, compositing onto the video frames with ffmpeg (don't use ffmpeg's drawtext filter, draw any text with Pillow), keep the audio, and save it as output.mp4.Run it without Claude
This is the exact script we tested. Save it as falling-leaves.py and run:
python3 falling-leaves.py input.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""Falling leaves: orange, red and gold maple leaves tumble down the frame, spinning and swaying as they fall.
Usage: python3 falling-leaves.py input.mp4 output.mp4
Needs ffmpeg, Pillow and numpy (pip install pillow numpy).
"""
import json
import math
import subprocess
import sys
import numpy as np
from PIL import Image, ImageDraw
START = 0.3 # second the first leaves appear at the top edge
COUNT = 30 # number of leaves
SIZE = (44, 76) # smallest and largest leaf, in pixels across
SPEED = (0.16, 0.26) # fall speed range, in frame heights per second
SWAY = 40 # side-to-side swing, in pixels
SPIN = 70 # how far a leaf rocks either way as it swings, in degrees
COLORS = [(232, 110, 24), (196, 38, 28), (238, 176, 32)] # leaf colors: orange, red and gold
SEED = 5 # change for a different fall of leaves
# one half of a maple leaf, tip at the top and stem at the bottom, in units of half the leaf's width
HALF_LEAF = [(0, -1.0), (0.14, -0.72), (0.32, -0.82), (0.26, -0.44), (0.64, -0.64), (0.58, -0.38),
(0.94, -0.30), (0.72, -0.10), (0.84, 0.08), (0.44, 0.10), (0.52, 0.38), (0.14, 0.24), (0.05, 0.50)]
def leaf(color, size=160):
"""A flat maple leaf with a darker stem and veins, drawn large so it stays smooth when scaled down."""
outline = HALF_LEAF + [(-x, y) for x, y in reversed(HALF_LEAF)]
c = size / 2
img = Image.new("RGBA", (size, size), (0, 0, 0, 0))
draw = ImageDraw.Draw(img)
draw.polygon([(c + x * c * 0.95, c + y * c * 0.95) for x, y in outline], fill=color + (255,))
vein = tuple(round(v * 0.6) for v in color) + (255,)
base = (c, c + 0.42 * c)
for x, y in [(0, -0.9), (0.6, -0.55), (-0.6, -0.55), (0.75, 0.0), (-0.75, 0.0)]:
draw.line([base, (c + x * c * 0.95, c + y * c * 0.95)], fill=vein, width=max(2, size // 60))
draw.line([base, (c, size - 1)], fill=vein, width=max(3, size // 40))
return img.crop(img.getbbox())
def probe(path):
info = json.loads(subprocess.check_output(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
"stream=width,height,r_frame_rate:format=duration", "-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), float(info["format"]["duration"])
src, out = sys.argv[1:3]
w, h, rate, fps, duration = probe(src)
rng = np.random.default_rng(SEED)
sprites = [leaf(c) for c in COLORS]
leaves = [{"sprite": sprites[k % len(sprites)], "size": rng.uniform(*SIZE), "x": rng.uniform(0.04, 0.96) * w,
"y": -rng.uniform(0.05, 0.8) * h, "speed": rng.uniform(*SPEED) * h, "swing": rng.uniform(2.2, 3.6),
"flip": rng.uniform(1.5, 3.0), "phase": rng.uniform(0, 2 * math.pi)}
for k in range(COUNT)]
def layer(t):
"""Every leaf at time t on a transparent frame."""
canvas = Image.new("RGBA", (w, h), (0, 0, 0, 0))
age = t - START
span = h * 1.15 # a leaf that falls off the bottom comes back in at the top
for p in leaves:
y = p["y"] + p["speed"] * age
if y > h * 1.07:
y = (y + 0.08 * h) % span - 0.08 * h
swing = math.sin(2 * math.pi * age / p["swing"] + p["phase"])
x = p["x"] + SWAY * swing
turn = abs(math.cos(2 * math.pi * age / p["flip"] + p["phase"])) # tumbling: seen edge-on now and then
s = p["size"] / p["sprite"].width
sprite = p["sprite"].resize((max(2, round(p["sprite"].width * s * max(turn, 0.2))),
max(2, round(p["sprite"].height * s))), Image.LANCZOS)
sprite = sprite.rotate(SPIN * swing + 180 * (p["phase"] > math.pi), expand=True, resample=Image.BICUBIC)
canvas.paste(sprite, (round(x - sprite.width / 2), round(y - sprite.height / 2)), sprite)
return canvas
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):
t = i / fps
if t >= START:
img = Image.frombytes("RGB", (w, h), raw).convert("RGBA")
img.alpha_composite(layer(t))
raw = img.convert("RGB").tobytes()
writer.stdin.write(raw)
i += 1
writer.stdin.close()
if reader.wait() or writer.wait():
sys.exit("ffmpeg failed")





