---
title: "How to add a super 8 film with Claude (tested prompt and script)"
description: "The silvery backdrop turns honey-gold and soft under heavy grain, the brightness pulses unevenly from frame to frame and the picture sits inside a black border with rounded corners, like a home movie on a projector. Install one skill and ask Claude Code, or run the Python script we tested yourself."
url: https://www.recharm.com/effects/super-8-film
---

# How to add a super 8 film with Claude

The silvery backdrop turns honey-gold and soft under heavy grain, the brightness pulses unevenly from frame to frame and the picture sits inside a black border with rounded corners, like a home movie on a projector.

Made by the script on this page, from our own test clip.

## Get this effect

1. ### Switch to Code in your [Claude Desktop App](https://claude.com/download)

2. ### Install the skill (once)

   ```
   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/skills
   ```

3. ### Ask 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.

```
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.mp4
```

```
#!/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)
```

## More retro and film

- [1950s color film look **1950s color film look**](https://www.recharm.com/effects/1950s-color-film-look)
- [35mm film look **35mm film look**](https://www.recharm.com/effects/35mm-film-look)
- [70s film look **70s film look**](https://www.recharm.com/effects/70s-film-look)
- [Camcorder date stamp **Camcorder date stamp**](https://www.recharm.com/effects/camcorder-date-stamp)
- [Camcorder viewfinder **Camcorder viewfinder**](https://www.recharm.com/effects/camcorder-viewfinder)

## Find 3x _winning ads_

Recharm cuts your ad footage into tagged, searchable clips: hooks, testimonials, product shots. Find the shots that win, add the effect with Claude, and ship 3x more ad edits.

[Start 14-day free trial](https://www.recharm.com/get-started)
