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 a warp speed to input.mp4 Color the picture fades to: (2, 4, 18) How far toward the void it fades (1 = the video is gone): 0.9
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 a warp speed 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 |
|---|---|---|
VOID | (2, 4, 18) | Color the picture fades to. |
DARK | 0.9 | How far toward the void it fades (1 = the video is gone). |
STARS_FROM | 1.0 | Second the stars appear, as still dots. |
STARS | 450 | Stars in the field. More reads as denser space. |
SPEED | (0.12, 2.6) | Star speed at the start and at full warp. |
RAMP | (1.4, 2.9) | Seconds the stars speed up between. |
TRAIL | 0.12 | Streak length, in seconds of travel. Raise it for longer streaks. |
GLOW | (120, 170, 255) | Color of the glow around the streaks. |
FLASH | (3.1, 3.4, 3.8) | White flash: when it starts, peaks and has faded back to the video. |
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 a warp speed (hyperspace) effect to input.mp4. From 0.8s to 1.1s, fade the picture 90% of the way to a dark blue void (2, 4, 18) with a smooth ease. From 1.0s, draw a 3D star field over it with Python, numpy and Pillow: 450 stars, each at a random x within ±60% of the frame width and y within ±60% of the frame height (pixels, as seen at depth 1) and a random depth z from 0.15 to 1.0, shown on screen at (width/2 + x/z, height/2 + y/z). Each frame, move every star toward the viewer by speed/30 in z; a star whose z drops below 0.05 respawns at a new random x, y with z = 1. The speed is 0.12 per second until 1.4s, then eases (smoothstep) up to 2.6 per second by 2.9s. Draw each star as a pure white (255, 255, 255) line from where it was 0.12 seconds of travel ago (z + speed x 0.12, capped at 1) to where it is now, with a round dot at the head, 1 pixel wide for the far stars and up to 3.5 pixels for near ones, brightness from 35% for far stars to 100% for near ones, so they start as dots and become long streaks rushing out from the center. Fade the stars in over 0.2s from 1.0s. Add a pale blue (120, 170, 255) glow: the white layer blurred with a Gaussian radius of 4, times 2.5, used as the blend amount toward the glow color, capped at 80%. From 3.1s to 3.4s, ease the whole frame to pure white; at 3.4s drop the void and stars, then ease the white back out to the untouched video by 3.8s. Before 0.8s and from 3.8s on the video must be unchanged. Don't use ffmpeg's drawtext filter. Keep the size, 30fps, length and audio, and save it as output.mp4.Run it without Claude
This is the exact script we tested. Save it as warp-speed.py and run:
python3 warp-speed.py input.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""Warp speed: the shot goes dark, white stars stretch into streaks rushing out from the center, then a flash lands back on the video.
Usage: python3 warp-speed.py input.mp4 output.mp4
Needs ffmpeg, numpy and Pillow (pip install numpy pillow).
"""
import json
import subprocess
import sys
import numpy as np
from PIL import Image, ImageDraw, ImageFilter
VOID = (2, 4, 18) # deep blue-black the picture fades to
DARK = 0.9 # how far toward VOID it fades (1 = the video is gone)
DARK_IN = (0.8, 1.1) # seconds the picture fades to the void
STARS_FROM = 1.0 # second the stars appear, as still dots
STARS = 450 # stars in the field
SPEED = (0.12, 2.6) # star speed at the start and at full warp (share of the depth crossed per second)
RAMP = (1.4, 2.9) # seconds the stars speed up between
TRAIL = 0.12 # streak length, in seconds of travel: longer streaks the faster they go
GLOW = (120, 170, 255) # pale blue glow around the streaks
FLASH = (3.1, 3.4, 3.8) # white flash: starts, peaks (stars and void gone), fades back to the video
SEED = 5 # change for a different star field
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 ramp(t, a, b):
"""0 before a, 1 after b, a smooth ease in between."""
p = min(max((t - a) / (b - a), 0), 1)
return p * p * (3 - 2 * p)
def speed(t):
return SPEED[0] + (SPEED[1] - SPEED[0]) * ramp(t, *RAMP)
def project(x, y, z):
"""Screen position of a star at depth z (1 = far, near 0 = right at the viewer)."""
return w / 2 + x / z, h / 2 + y / z
def starfield(t):
"""White streak layer (0-1) for time t: each star drawn from where it was TRAIL seconds ago to where it is now."""
layer = Image.new("L", (w, h))
draw = ImageDraw.Draw(layer)
z_then = np.minimum(z + speed(t) * TRAIL, 1.0)
x0, y0 = project(x, y, z_then)
x1, y1 = project(x, y, z)
near = 1 - z # nearer stars are brighter and thicker
fade = ramp(t, STARS_FROM, STARS_FROM + 0.2)
for i in range(STARS):
level = round(255 * fade * min(1, 0.35 + near[i] * 1.2))
size = 1 + 2.5 * near[i]
draw.line([(x0[i], y0[i]), (x1[i], y1[i])], fill=level, width=round(size))
draw.ellipse([x1[i] - size / 2, y1[i] - size / 2, x1[i] + size / 2, y1[i] + size / 2], fill=level)
return layer
def frame_at(img, t):
flash = ramp(t, FLASH[0], FLASH[1]) if t < FLASH[1] else 1 - ramp(t, FLASH[1], FLASH[2])
if t >= FLASH[1]: # after the peak the video comes back clean
out = img
else:
dark = DARK * ramp(t, *DARK_IN)
out = img * (1 - dark) + np.array(VOID, np.float32) * dark
if t >= STARS_FROM:
core = starfield(t)
glow = np.asarray(core.filter(ImageFilter.GaussianBlur(4)), np.float32)[..., None] / 255 * 2.5
core = np.asarray(core, np.float32)[..., None] / 255
out = out + (np.array(GLOW, np.float32) - out) * np.clip(glow, 0, 0.8)
out = out + (255 - out) * core
out = out + (255 - out) * flash
return out.clip(0, 255).astype(np.uint8)
src, out = sys.argv[1:3]
w, h, rate, fps = probe(src)
rng = np.random.default_rng(SEED)
x = rng.uniform(-w * 0.6, w * 0.6, STARS) # star positions, in pixels as seen at depth 1
y = rng.uniform(-h * 0.6, h * 0.6, STARS)
z = rng.uniform(0.15, 1.0, STARS)
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", "16", "-pix_fmt", "yuv420p", "-c:a", "copy", "-shortest", out],
stdin=subprocess.PIPE)
i = 0
while raw := reader.stdout.read(w * h * 3):
t = i / fps
img = np.frombuffer(raw, np.uint8).reshape(h, w, 3).astype(np.float32)
writer.stdin.write(frame_at(img, t).tobytes())
if t >= STARS_FROM: # move the stars toward the viewer; respawn the ones that pass
z -= speed(t) / fps
gone = z < 0.05
x[gone] = rng.uniform(-w * 0.6, w * 0.6, gone.sum())
y[gone] = rng.uniform(-h * 0.6, h * 0.6, gone.sum())
z[gone] = 1.0
i += 1
writer.stdin.close()
if reader.wait() or writer.wait():
sys.exit("ffmpeg failed")





