---
title: "How to add a burning paper transition with Claude (tested prompt and script)"
description: "A hole burns open in the middle of clip A and spreads outward on a ragged, glowing orange edge ringed with scorched brown paper, until clip B fills the frame. Install one skill and ask Claude Code, or run the Python script we tested yourself."
url: https://www.recharm.com/effects/burning-paper-transition
---

# How to add a burning paper transition with Claude

A hole burns open in the middle of clip A and spreads outward on a ragged, glowing orange edge ringed with scorched brown paper, until clip B fills the frame.

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 burning paper transition
   Ember colors: near white, orange, dark red
   ```

## 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 burning paper 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`            | `1.5`                          | Length of the transition in seconds.                                               |
| `CENTER`       | `(0.5, 0.5)`                   | Where the hole starts, as fractions across and down the frame.                     |
| `RAGGED`       | `0.12`                         | How far the noise pushes the burn edge in and out, as a share of the frame height. |
| `EMBER`        | `0.014`                        | Width of the glowing edge, as a share of the frame height.                         |
| `CHAR`         | `0.045`                        | Width of the scorched brown band just outside the glowing edge.                    |
| `GLOW`         | `0.03`                         | How far the orange glow reaches either side of the edge.                           |
| `EMBER_COLORS` | `near white, orange, dark red` | The glowing edge's colors from the burned side outward.                            |
| `CHAR_COLOR`   | `(35, 20, 12)`                 | Color of the scorched paper next to the edge.                                      |
| `GLOW_COLOR`   | `(255, 110, 20)`               | Color of the light the edge throws on both clips.                                  |
| `SEED`         | `3`                            | Change for a different burn shape.                                                 |

## 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.5 second burning paper transition that starts 1.5 seconds before the end of A, so the output is 10.5 seconds long. Match B's size to A (scale to cover and center-crop) and output 30fps. Do it in Python with numpy and Pillow: read both clips' frames as RGB through ffmpeg pipes, composite each frame of the transition in numpy and pipe the result back to ffmpeg. Outside the 1.5 second window the picture must be untouched. Build a static burn map once, with h the frame height: dist = (distance in pixels from the frame center) / h + 0.24 * (n - 0.5), where n = 0.55*N(4x7) + 0.3*N(10x18) + 0.15*N(40x70) and N(cols x rows) is a fixed grid of uniform random values (0-1) upscaled to the frame with bicubic resampling. With EMBER = 0.014, CHAR = 0.045 and GLOW = 0.03, the burn front r runs linearly from min(dist) - EMBER - CHAR - 3*GLOW at the start of the transition to max(dist) + 3*GLOW at the end. For each pixel let e = dist - r. Where e < 0 show clip B, otherwise clip A. Where EMBER <= e < EMBER + CHAR, blend A toward the scorched color RGB (35, 20, 12) by clip(1 - (e - EMBER)/CHAR, 0, 1)^1.5. Where 0 <= e < EMBER, paint the glowing edge, interpolating e/EMBER = 0, 0.5, 1 to RGB (255, 235, 170), (255, 140, 30), (150, 40, 5). Then add an orange glow on both sides of the edge: add RGB (255, 110, 20) * 0.6 * exp(-(e/GLOW)^2) and clip to 0-255. Crossfade the audio over the same 1.5 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 `burning-paper-transition.py` and run:

```
python3 burning-paper-transition.py clipA.mp4 clipB.mp4 output.mp4
```

```
#!/usr/bin/env python3
"""Burning paper: a hole burns open in the middle of clip A and spreads out on a ragged, glowing edge to uncover clip B.

Usage: python3 burning-paper-transition.py clipA.mp4 clipB.mp4 output.mp4  (both clips need an audio track)
Needs ffmpeg, numpy and Pillow (pip install numpy pillow). The burn edge is 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.5                        # transition length in seconds
CENTER = (0.5, 0.5)            # where the hole starts (0-1 across and down the frame)
RAGGED = 0.12                  # how far the noise pushes the burn edge in and out, as a share of the frame height
EMBER = 0.014                  # width of the glowing edge, as a share of the frame height
CHAR = 0.045                   # width of the scorched brown band beyond it
GLOW = 0.03                    # reach of the orange glow either side of the edge
EMBER_COLORS = [(255, 235, 170), (255, 140, 30), (150, 40, 5)]  # glowing edge, inside to outside: near white, orange, dark red
CHAR_COLOR = (35, 20, 12)      # color of the scorched paper next to the edge
GLOW_COLOR = (255, 110, 20)    # orange light the edge throws on both clips
SEED = 3                       # change for a different burn shape

def noise(cols, rows):
    """Smooth random field in 0-1: a cols x rows grid of random values scaled up to the frame."""
    grid = np.random.default_rng([SEED, cols]).random((rows, cols)).astype(np.float32)
    return np.asarray(Image.fromarray(grid).resize((w, h), Image.BICUBIC))

def burn(fa, fb, u):
    """Clip A frame fa burned away into clip B frame fb, u (0-1) of the way through the transition."""
    e = dist - (start + (end - start) * u)        # each pixel's distance from the burn edge, into the unburned paper
    out = np.where((e < 0)[..., None], fb, fa).astype(np.float32)
    char = np.clip(1 - (e - EMBER) / CHAR, 0, 1) ** 1.5 * (e >= EMBER)
    out += (np.array(CHAR_COLOR) - out) * char[..., None]
    ember = (e >= 0) & (e < EMBER)
    k = e[ember] / EMBER
    out[ember] = np.stack([np.interp(k, [0, 0.5, 1], [c[i] for c in EMBER_COLORS]) for i in range(3)], axis=1)
    out += np.array(GLOW_COLOR) * 0.6 * np.exp(-(e / GLOW) ** 2)[..., None]
    return np.clip(out, 0, 255).astype(np.uint8)

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, vf):
    """Read a clip's frames as RGB arrays."""
    ff = subprocess.Popen(["ffmpeg", "-v", "error", "-i", path, "-vf", vf, "-f", "rawvideo", "-pix_fmt", "rgb24", "-"],
                          stdout=subprocess.PIPE)
    while data := ff.stdout.read(w * h * 3):
        yield np.frombuffer(data, np.uint8).reshape(h, w, 3)

a, b, out = sys.argv[1:4]
w, h, len_a = probe(a)
len_b = probe(b)[2]
fps = 30
offset = len_a - D
# distance from CENTER in frame heights, pushed in and out by noise so the hole's edge is ragged like burning paper
ys, xs = np.mgrid[0:h, 0:w]
n = 0.55 * noise(4, 7) + 0.3 * noise(10, 18) + 0.15 * noise(40, 70)   # big lobes, smaller bites and a crinkled edge
dist = np.hypot(xs - CENTER[0] * w, ys - CENTER[1] * h) / h + RAGGED * 2 * (n - 0.5)
start = dist.min() - EMBER - CHAR - 3 * GLOW   # nothing shows yet at the first frame
end = dist.max() + 3 * GLOW                    # all of clip B, glow gone, at the last
ra = frames(a, f"fps={fps}")
rb = frames(b, f"scale={w}:{h}:force_original_aspect_ratio=increase,crop={w}:{h},fps={fps}")
ff = 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)
for i in range(round((len_a + len_b - D) * fps)):
    t = i / fps
    if t < offset:
        frame = next(ra)
    elif t < len_a:
        frame = burn(next(ra), next(rb), (t - offset) / D)
    else:
        frame = next(rb)
    ff.stdin.write(frame.tobytes())
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)
