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 super 8 film to input.mp4 Moving film grain: 14 The picture is shrunk by this much and scaled back up, so it looks soft like 8mm: 2
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 super 8 film 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 |
|---|---|---|
GRAIN | 14 | Moving film grain. 0 turns it off; 25 looks like old, pushed stock. |
SOFTNESS | 2 | The picture is shrunk by this much and scaled back up, so it looks soft like 8mm. 1 keeps it sharp. |
FLICKER | 0.07 | How far the brightness swings either way. 0.07 is up to 7% brighter or darker; 0 turns the flicker off. |
WEAVE | 2 | Pixels the picture drifts side to side and up and down, like film wobbling in the gate. 0 holds it still. |
INSET | 0.03 | The black border around the picture, as a share of the frame width. |
RADIUS | 0.09 | How round the border's corners are, as a share of the frame width. |
EDGE_BLUR | 4 | Pixels of softening on the border's edge. 0 gives a hard edge. |
VIGNETTE | 0.5 | Corner darkening inside the border, as an angle in radians. 0 turns it off. |
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
Make input.mp4 look like Super 8 home-movie film from the first frame to the last. 1) With ffmpeg, grade it warm: per-channel tone curves (input/output points, 0-1) red 0/0.06 0.5/0.60 1/0.97, green 0/0.04 0.5/0.50 1/0.90, blue 0/0.03 0.5/0.36 1/0.72 (curves=r='0/0.06 0.5/0.60 1/0.97':g='0/0.04 0.5/0.50 1/0.90':b='0/0.03 0.5/0.36 1/0.72'), then eq=saturation=1.15, soften it by scaling down to half size and back up to 540x960 with bicubic, add vignette=angle=0.5 and moving grain noise=alls=14:allf=t+u. 2) Then, per frame with numpy (frame n, t = n/30 seconds): multiply the brightness by a flicker gain of 1 + 0.07 * (0.6*sin(2*pi*4.7*t) + 0.4*sin(2*pi*11.3*t + 1.0)), so frames are up to 7% brighter or darker; shift the picture by dx = round(2*sin(2*pi*1.3*t)) and dy = round(2*sin(2*pi*0.9*t + 2.0)) pixels for a gate wobble; and multiply it by a gate mask: a white rounded rectangle on black drawn with Pillow, inset 16 pixels from every edge (3% of the width), corner radius 49 pixels (9% of the width), blurred with a 4 pixel Gaussian blur, so the picture sits in a black border with rounded corners. The cool blue-white backdrop (around RGB 192, 203, 216) should come out honey-gold (around RGB 157, 148, 110), and the frame corners pure black. Don't add any text (if you ever do, draw it with Pillow, not ffmpeg's drawtext). Keep the size (540x960), 30fps, the 6 second length and the audio. Encode H.264 yuv420p and save it as output.mp4.Run it without Claude
This is the exact script we tested. Save it as super-8-film.py and run:
python3 super-8-film.py input.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""Super 8 film: warm, soft, grainy footage that flickers and wobbles inside a black gate with rounded corners.
Usage: python3 super-8-film.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
GRAIN = 14 # moving film grain; 0 turns it off, 25 looks like old, pushed stock
SOFTNESS = 2 # the picture is shrunk by this much and scaled back up, so it looks soft like 8mm
FLICKER = 0.07 # how far the brightness swings either way (0.07 = up to 7% brighter or darker)
WEAVE = 2 # pixels the picture drifts side to side and up and down as the film wobbles in the gate
INSET = 0.03 # black gate border as a share of the frame width
RADIUS = 0.09 # gate corner radius as a share of the frame width
EDGE_BLUR = 4 # pixels of softening on the gate's edge
VIGNETTE = 0.5 # corner darkening inside the gate, as an angle in radians; 0 turns it off
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 gate():
"""Opacity of the picture: 1 inside a rounded rectangle, falling to 0 in the black border."""
pad, r = round(w * INSET), round(w * RADIUS)
mask = Image.new("L", (w, h), 0)
ImageDraw.Draw(mask).rounded_rectangle([pad, pad, w - 1 - pad, h - 1 - pad], radius=r, fill=255)
return np.asarray(mask.filter(ImageFilter.GaussianBlur(EDGE_BLUR)), np.float32)[:, :, None] / 255
def flicker(t):
"""Brightness gain at time t: two sine waves at unrelated speeds, so the pulsing never looks regular."""
return 1 + FLICKER * (0.6 * np.sin(2 * np.pi * 4.7 * t) + 0.4 * np.sin(2 * np.pi * 11.3 * t + 1.0))
def weave(t):
"""How far the picture has drifted (dx, dy) in pixels at time t."""
return round(WEAVE * np.sin(2 * np.pi * 1.3 * t)), round(WEAVE * np.sin(2 * np.pi * 0.9 * t + 2.0))
def render(src, out):
# Warm Kodachrome-style curves: red lifted, blue pulled down, blacks lifted a little so shadows go brown;
# then a little more color, the softening, a vignette and grain that changes every frame.
grade = (f"fps=30,curves=r='0/0.06 0.5/0.60 1/0.97':g='0/0.04 0.5/0.50 1/0.90':b='0/0.03 0.5/0.36 1/0.72',"
f"eq=saturation=1.15,scale=iw/{SOFTNESS}:-2,scale={w}:{h}:flags=bicubic,"
f"vignette=angle={VIGNETTE},noise=alls={GRAIN}:allf=t+u")
reader = subprocess.Popen(["ffmpeg", "-v", "error", "-i", src, "-vf", grade,
"-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", "30", "-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)
mask, i = gate(), 0
while raw := reader.stdout.read(w * h * 3):
t = i / 30
dx, dy = weave(t)
img = np.roll(np.frombuffer(raw, np.uint8).reshape(h, w, 3), (dy, dx), axis=(0, 1)).astype(np.float32)
writer.stdin.write(np.clip(img * flicker(t) * mask, 0, 255).astype(np.uint8).tobytes())
i += 1
writer.stdin.close()
if reader.wait() or writer.wait():
sys.exit("ffmpeg failed")
src, out = sys.argv[1:3]
w, h = probe(src)
render(src, out)





