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
Join clipA.mp4 and clipB.mp4 with a stretch transition Length of the transition in seconds: half smearing A away, half snapping B in: 0.6 Share of the frame width at the edge that gets stretched into streaks: 0.05
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.
Put a sale badge on @clip1.mp4, give @clip2.mp4 a VHS look, then join them with a stretch transition.
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 |
|---|---|---|
D | 0.6 | Length of the transition in seconds: half smearing A away, half snapping B in. |
EDGE | 0.05 | Share of the frame width at the edge that gets stretched into streaks. |
FPS | 30 | Output frame rate. |
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
Join clipA.mp4 and clipB.mp4 with a 0.6 second stretch transition that starts 0.6 seconds before A ends (the result is 11.4 seconds). Use progress p = frame index / 18 over the 18 transition frames. For p < 0.5, take A's frame, slide it left by s = 540*(2p)^2 pixels, and fill the gap on the right by stretching A's rightmost 27 pixel columns (5% of the width) horizontally across the gap plus their own width, so the right edge smears into flat horizontal streaks. At p = 0.5 the whole frame is streaks. For p >= 0.5, do the mirror image with B's frame: B sits shifted right by s = 540*(2-2p)^2 pixels and its leftmost 27 columns are stretched across the gap on the left, so B slides in from the right out of streaks and slows as it lands. No fade, blur or black. Before the transition A plays normally and B continues full frame afterwards. Crossfade the audio over the same 0.6 seconds. Fit B to A's size first. Output 540x960, 30fps, H.264 yuv420p. Use ffmpeg with Python and numpy for the per-frame column remapping, keep the audio and save it as output.mp4.Run it without Claude
This is the exact script we tested. Save it as stretch-transition.py and run:
python3 stretch-transition.py clipA.mp4 clipB.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""Stretch transition: clip A slides off to the left while its right edge smears into long streaks, then clip B snaps in out of streaks from its own left edge.
Usage: python3 stretch-transition.py clipA.mp4 clipB.mp4 output.mp4 (both clips need an audio track)
Needs ffmpeg and numpy (pip install numpy).
"""
import json
import subprocess
import sys
from itertools import islice
import numpy as np
D = 0.6 # transition length in seconds: half smearing A away, half snapping B in
EDGE = 0.05 # share of the frame width at the edge that gets stretched into streaks
FPS = 30 # output frame rate
def probe(path):
info = json.loads(subprocess.check_output(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
"stream=width,height:format=duration", "-of", "json", path]))
return info["streams"][0]["width"], info["streams"][0]["height"], float(info["format"]["duration"])
def frames(path):
"""Decode a clip as w x h RGB frames at FPS, cropping it to fill the frame if its shape differs."""
ff = subprocess.Popen(["ffmpeg", "-v", "error", "-i", path, "-vf",
f"scale={w}:{h}:force_original_aspect_ratio=increase,crop={w}:{h},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 np.frombuffer(data, np.uint8).reshape(h, w, 3)
def smear(img, shift):
"""Slide the picture `shift` pixels left and stretch its rightmost EDGE strip across the gap it leaves."""
edge = round(w * EDGE)
start = w - shift - edge # output column where the stretched strip begins
x = np.arange(w)
src = np.where(x < start, x + shift, (w - edge) + (x - start) * edge / (shift + edge))
return img[:, np.minimum(src.astype(int), w - 1)]
def stretch(a, b, p):
"""One transition frame at progress p (0-1): A smears away until the frame is all streaks, then B snaps back."""
if p < 0.5:
return smear(a, round(w * (2 * p) ** 2)) # speeds up as it leaves
return smear(b[:, ::-1], round(w * (2 - 2 * p) ** 2))[:, ::-1] # mirrored: B's left edge, slowing as it lands
A, B, out = sys.argv[1:4]
w, h, length = probe(A)
cut_in = round((length - D) * FPS) # first frame of the transition
n = round(D * FPS) # frames in the transition
enc = subprocess.Popen(["ffmpeg", "-y", "-v", "error", "-f", "rawvideo", "-pix_fmt", "rgb24", "-s", f"{w}x{h}",
"-r", str(FPS), "-i", "-", "-i", A, "-i", B,
"-filter_complex", f"[1:a][2:a]acrossfade=d={D}[au]", "-map", "0:v", "-map", "[au]",
"-c:v", "libx264", "-crf", "18", "-pix_fmt", "yuv420p", "-c:a", "aac", out],
stdin=subprocess.PIPE)
clip_a, clip_b = frames(A), frames(B)
for a in islice(clip_a, cut_in):
enc.stdin.write(a.tobytes())
for i, (a, b) in enumerate(zip(islice(clip_a, n), islice(clip_b, n))):
enc.stdin.write(np.ascontiguousarray(stretch(a, b, i / n)).tobytes())
for b in clip_b:
enc.stdin.write(b.tobytes())
enc.stdin.close()
if enc.wait():
sys.exit("ffmpeg failed")





