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 an infinite zoom to input.mp4 Second the zoom starts: 1.0 How many copies the camera flies into: 4
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 an infinite zoom 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 | 1.0 | Second the zoom starts. The copies fade in just before. |
LOOPS | 4 | How many copies the camera flies into. |
LOOP_TIME | 1.0 | Seconds to zoom from one copy to the next. Smaller is faster. |
FADE | 0.2 | Seconds the copies take to fade in and out. |
SCALE | 0.5 | Size of each copy as a share of the one around it. |
DEPTH | 6 | How many copies are nested inside each other. |
BORDER | 4 | Width of the frame round each copy, in pixels at full size. 0 hides it. |
BORDER_COLOR | (245, 245, 245) | Color of the frame round each copy. |
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 an infinite zoom (Droste effect) to input.mp4 with Python and Pillow, decoding and encoding the frames with ffmpeg. For each frame F (540x960), build a nested picture D: start with F, then 6 times paste the current picture, shrunk to half size (270x480, Lanczos), centered on a fresh copy of F, after first filling a rectangle 4 px larger on every side with (245, 245, 245) as a border. Between 1.0s and 5.0s, zoom into the center with zoom z = 2^frac((t - 1) / 1.0), where t is the time in seconds, so z goes 1 -> 2 once a second (4 loops). Each output frame is F scaled up z times about its center and cropped back to 540x960 (bicubic), with D shrunk to (0.5 x z) of the frame size pasted in the center inside a border of 4 x z px of (245, 245, 245). At z = 2 the copy fills the screen and looks exactly like z = 1, so the loop has no seam. Fade the copies (border included) in from 0.8s to 1.0s and out from 5.0s to 5.2s by blending with the plain frame; before 0.8s and after 5.2s the frames are untouched. 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 infinite-zoom.py and run:
python3 infinite-zoom.py input.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""Infinite zoom: a framed copy of the shot appears in its own center, and the camera zooms into it copy after copy.
Usage: python3 infinite-zoom.py input.mp4 output.mp4
Needs ffmpeg and Pillow (pip install pillow).
"""
import json
import subprocess
import sys
from PIL import Image, ImageDraw
START = 1.0 # second the zoom starts (the copies fade in just before)
LOOPS = 4 # how many copies the camera flies into
LOOP_TIME = 1.0 # seconds to zoom from one copy to the next
FADE = 0.2 # seconds the copies take to fade in before START and out after the last loop
SCALE = 0.5 # size of each copy, as a share of the one around it
DEPTH = 6 # how many copies are nested inside each other
BORDER = 4 # frame round each copy, in pixels at full size
BORDER_COLOR = (245, 245, 245)
FPS = 30 # output frame rate
END = START + LOOPS * LOOP_TIME
def probe(path):
info = json.loads(subprocess.check_output(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
"stream=width,height", "-of", "json", path]))
return info["streams"][0]["width"], info["streams"][0]["height"]
def frames(path):
"""Decode a clip as RGB frames at FPS."""
ff = subprocess.Popen(["ffmpeg", "-v", "error", "-i", path, "-vf", f"fps={FPS}",
"-f", "rawvideo", "-pix_fmt", "rgb24", "-"], stdout=subprocess.PIPE)
while True:
data = ff.stdout.read(w * h * 3)
if len(data) < w * h * 3:
return
yield Image.frombytes("RGB", (w, h), data)
def framed_copy(base, inner, scale, alpha=1.0):
"""base with inner shrunk to `scale` of the frame in its center, inside a thin border."""
cw, ch = round(w * scale), round(h * scale)
x0, y0 = (w - cw) // 2, (h - ch) // 2
b = max(1, round(BORDER * scale / SCALE))
out = base.copy()
ImageDraw.Draw(out).rectangle([x0 - b, y0 - b, x0 + cw + b - 1, y0 + ch + b - 1], fill=BORDER_COLOR)
out.paste(inner.resize((cw, ch), Image.LANCZOS), (x0, y0))
return Image.blend(base, out, alpha) if alpha < 1 else out
def nested(frame):
"""The frame with DEPTH copies of itself, each inside the last."""
img = frame
for _ in range(DEPTH):
img = framed_copy(frame, img, SCALE)
return img
def zoomed(img, z):
"""img scaled up z times about its center, cropped back to the frame size."""
cw, ch = w / z, h / z
box = ((w - cw) / 2, (h - ch) / 2, (w + cw) / 2, (h + ch) / 2)
return img.resize((w, h), Image.BICUBIC, box=box)
def infinite_zoom(frame, t):
"""Zoom z runs from 1 to 1/SCALE once per loop: by then the first copy fills the screen and looks exactly
like the start, so the loop repeats without a seam. The copy is drawn at its on-screen size to stay sharp."""
alpha = min(max((t - START + FADE) / FADE, 0), max((END + FADE - t) / FADE, 0), 1)
if alpha == 0:
return frame
loop = min(max(t - START, 0), END - START) / LOOP_TIME % 1
z = (1 / SCALE) ** loop
return framed_copy(zoomed(frame, z), nested(frame), SCALE * z, alpha)
src, out = sys.argv[1:3]
w, h = probe(src)
enc = subprocess.Popen(["ffmpeg", "-y", "-v", "error", "-f", "rawvideo", "-pix_fmt", "rgb24", "-s", f"{w}x{h}",
"-r", str(FPS), "-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)
for i, frame in enumerate(frames(src)):
enc.stdin.write(infinite_zoom(frame, i / FPS).tobytes())
enc.stdin.close()
if enc.wait():
sys.exit("ffmpeg failed")





