---
title: "How to add a film burn with Claude (tested prompt and script)"
description: "A flickering band of orange fire with a white-hot core sweeps from the left edge to the right, burning clip A away and leaving clip B behind it. Install one skill and ask Claude Code, or run the Python script we tested yourself."
url: https://www.recharm.com/effects/film-burn
---

# How to add a film burn with Claude

A flickering band of orange fire with a white-hot core sweeps from the left edge to the right, burning clip A away and leaving clip B behind it.

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

## 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

   ```
   Join clipA.mp4 and clipB.mp4 with a film burn
   Heat, colors: deep red, red, orange, amber, near white
   ```

## 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 film burn.

## 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`            | `1.2`                                      | Length of the transition in seconds; the burn peaks halfway through.                                |
| `CUT`          | `0.3`                                      | Share of the transition the picture takes to dissolve from A to B, hidden under the brightest fire. |
| `WIDTH`        | `0.35`                                     | Width of the band of fire that sweeps across, as a share of the frame.                              |
| `FLICKER`      | `0.08`                                     | Seconds between new noise patterns; smaller flickers faster.                                        |
| `HEAT, COLORS` | `deep red, red, orange, amber, near white` | The fire's color at each burn strength from 0 to 1.                                                 |
| `OPACITY`      | `0.95`                                     | How much of the picture the hottest fire covers.                                                    |
| `SEED`         | `7`                                        | Random seed; change it for a different burn.                                                        |

## Without the skill

Don’t want to install the skill? Paste this prompt into Claude Code and Claude writes the script itself.

```
Join clipA.mp4 and clipB.mp4 with a 1.2 second film burn transition that starts 1.2 seconds before the end of A, so the output is 10.8 seconds long. Match B's size to A (scale to cover and center-crop) and output 30fps. Make the burn procedurally with Python, numpy and Pillow (no stock overlay), as an RGBA layer per frame piped to ffmpeg and laid over the picture. For a frame at progress u (0 to 1 through the transition), with x and y as 0-1 fractions of the frame width and height: envelope = sin(pi*u); a diagonal band = exp(-((0.75*x + 0.25*y - (-0.2 + 1.4*u)) / 0.35)^2), so it sweeps from the left edge to the right; noise = 0.5*N(5x9) + 0.3*N(12x20) + 0.2*N(30x52), where N(cols x rows) is a grid of uniform random values upscaled to the frame with bicubic resampling, with a fresh grid every 0.08 seconds and neighboring grids blended with a smoothstep; a per-frame flicker that is a random number between 0.85 and 1.15. heat = clip(envelope * flicker * (0.35 + 0.9*band) * (0.3 + noise), 0, 1). Color the heat by interpolating heat 0, 0.25, 0.5, 0.75, 1 to RGB (90,10,0), (170,30,0), (245,95,10), (255,175,45), (255,240,190), and set alpha to min(0.95, 0.95*heat/0.6)*255. Under the burn, keep A fully on screen until 0.42 seconds into the transition, dissolve to B by 0.78 seconds in (ffmpeg xfade custom), then show B. Outside the 1.2 second window the picture must be untouched. Crossfade the audio over the same 1.2 seconds and keep it. Output H.264 yuv420p, and save it as output.mp4.
```

## Run it without Claude

This is the exact script we tested. Save it as `film-burn.py` and run:

```
python3 film-burn.py clipA.mp4 clipB.mp4 output.mp4
```

```
#!/usr/bin/env python3
"""Film burn: flickering orange flares sweep across the frame and burn clip A out into clip B.

Usage: python3 film-burn.py clipA.mp4 clipB.mp4 output.mp4  (both clips need an audio track)
Needs ffmpeg, numpy and Pillow (pip install numpy pillow). The burns are drawn from random noise, so no stock overlay is needed.
"""
import json
import subprocess
import sys

import numpy as np
from PIL import Image

D = 1.2                  # transition length in seconds; the burn peaks halfway through
CUT = 0.3                # share of the transition the picture takes to dissolve from A to B, hidden under the peak
WIDTH = 0.35             # width of the band of fire that sweeps from the left edge to the right
FLICKER = 0.08           # seconds between new noise patterns (smaller flickers faster)
HEAT = [0, 0.25, 0.5, 0.75, 1.0]                                                    # burn strength...
COLORS = [(90, 10, 0), (170, 30, 0), (245, 95, 10), (255, 175, 45), (255, 240, 190)]  # ...and its color: deep red, red, orange, amber, near white
OPACITY = 0.95           # how much of the picture the hottest fire covers
SEED = 7                 # change for a different burn

def noise(t, cols, rows):
    """Smooth random field in 0-1 at time t: random grids FLICKER seconds apart, blended in time and scaled up to the frame."""
    k = t / FLICKER
    i, f = int(k), k - int(k)
    f = f * f * (3 - 2 * f)
    grid = (1 - f) * grids(cols, rows, i) + f * grids(cols, rows, i + 1)
    return np.asarray(Image.fromarray(grid.astype(np.float32)).resize((w, h), Image.BICUBIC))

def grids(cols, rows, i):
    return np.random.default_rng([SEED, cols, i]).random((rows, cols))

def burn(t):
    """The fire layer at time t (clear outside the transition), as RGBA bytes."""
    u = (t - offset) / D
    if not 0 < u < 1:
        return clear
    envelope = np.sin(np.pi * u)
    center = -0.2 + 1.4 * u                                    # the band crosses the frame diagonally, left to right
    band = np.exp(-((0.75 * xs + 0.25 * ys - center) / WIDTH) ** 2)
    n = 0.5 * noise(t, 5, 9) + 0.3 * noise(t, 12, 20) + 0.2 * noise(t, 30, 52)  # big blooms, flames and fine grain
    flicker = 0.85 + 0.3 * np.random.default_rng([SEED, round(t * fps)]).random()
    heat = np.clip(envelope * flicker * (0.35 + 0.9 * band) * (0.3 + 1.0 * n), 0, 1)
    rgb = [np.interp(heat, HEAT, [c[k] for c in COLORS]) for k in range(3)]
    alpha = 255 * np.clip(OPACITY * heat / 0.6, 0, OPACITY)   # opaque from orange up, so the fire shows on light footage too
    return np.stack(rgb + [alpha], axis=2).astype(np.uint8).tobytes()

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"])

a, b, out = sys.argv[1:4]
w, h, len_a = probe(a)
len_b = probe(b)[2]
fps = 30
offset = len_a - D
ys, xs = np.mgrid[0:h, 0:w] / np.array([h, w]).reshape(2, 1, 1)
clear = bytes(w * h * 4)
# A dissolves into B only in the middle CUT of the transition, while the burn is brightest; P runs 1 -> 0 in xfade
mix = f"clip((P-{0.5 - CUT / 2})/{CUT},0,1)"
ff = subprocess.Popen(["ffmpeg", "-y", "-v", "error", "-i", a, "-i", b,
                       "-f", "rawvideo", "-pix_fmt", "rgba", "-s", f"{w}x{h}", "-r", str(fps), "-i", "-",
                       "-filter_complex",
                       f"[0:v]fps={fps},format=gbrp,setsar=1[a];"
                       f"[1:v]scale={w}:{h}:force_original_aspect_ratio=increase,crop={w}:{h},fps={fps},format=gbrp,setsar=1[b];"
                       f"[a][b]xfade=transition=custom:expr='B+(A-B)*{mix}':duration={D}:offset={offset}[ab];"
                       f"[ab][2:v]overlay=format=gbrp:shortest=1,format=yuv420p[v];"
                       f"[0:a][1:a]acrossfade=d={D}[au]",
                       "-map", "[v]", "-map", "[au]", "-c:v", "libx264", "-crf", "18", "-pix_fmt", "yuv420p", "-c:a", "aac", out],
                      stdin=subprocess.PIPE)
for i in range(round((len_a + len_b - D) * fps)):
    ff.stdin.write(burn(i / fps))
ff.stdin.close()
sys.exit("ffmpeg failed" if ff.wait() else 0)
```

## More transitions

- [Barn door transition **Barn door transition**](https://www.recharm.com/effects/barn-door)
- [Blinds transition **Blinds transition**](https://www.recharm.com/effects/blinds-transition)
- [Block dissolve **Block dissolve**](https://www.recharm.com/effects/block-dissolve)
- [Blur transition **Blur transition**](https://www.recharm.com/effects/blur-transition)
- [Bounce transition **Bounce transition**](https://www.recharm.com/effects/bounce-transition)

## 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)
