---
title: "How to add a fire transition with Claude (tested prompt and script)"
description: "A ragged wall of orange flames climbs from the bottom of the frame to the top, and clip B is left behind wherever it has burned through clip A. Install one skill and ask Claude Code, or run the Python script we tested yourself."
url: https://www.recharm.com/effects/fire-transition
---

# How to add a fire transition with Claude

A ragged wall of orange flames climbs from the bottom of the frame to the top, and clip B is left behind wherever it has burned through clip A.

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 fire transition
   Colors: ember, 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 fire 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, from the first flame tips to the last. |
| `FLAME`  | `0.35`                                  | Flame height above the burning edge, as a share of the frame height.        |
| `RAGGED` | `0.04`                                  | How far the burning edge wobbles up and down.                               |
| `RISE`   | `1.2`                                   | How fast the flames lick upwards, in frame heights per second.              |
| `COLORS` | `ember, red, orange, amber, near white` | Flame colors from the tips to the edge.                                     |

## 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 fire transition starting 1.5 seconds before the end of A, so the output is 10.5 seconds long. A horizontal burning edge rises from below the frame to above it at a steady speed: its height runs from 1.35 frame heights down to -0.35 (0 is the top, 1 the bottom) over the 1.5 seconds, wobbling up and down by 0.04 frame heights with smooth noise across the width. Below the edge show B, above it show A. On top of the edge draw flames up to 0.35 frame heights tall: smooth random noise that scrolls upward at 1.2 frame heights per second sets each tongue's height between 30% and 120% of that, colored from near white (255, 245, 200) and amber (255, 180, 40) at the edge through orange (250, 100, 10) and red (180, 25, 0) to dark ember (40, 5, 0) at the tips, opaque except the top 30% of each tongue, with a 0.01 frame height white-hot line right on the edge. Darken A to 15% in the 0.03 frame heights just above the edge. Crossfade the audio over the same 1.5 seconds. Match B's size to A, output 30fps H.264 yuv420p. Use Python with numpy to draw the frames and ffmpeg to read and write the video, and save it as output.mp4.
```

## Run it without Claude

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

```
python3 fire-transition.py clipA.mp4 clipB.mp4 output.mp4
```

```
#!/usr/bin/env python3
"""Fire transition: a wall of flames rises from the bottom of the frame and burns clip A away to reveal clip B.

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

import numpy as np

D = 1.5                  # transition length in seconds, from the first flame tips to the last
FLAME = 0.35             # flame height above the burning edge, as a share of the frame height
RAGGED = 0.04            # how far the burning edge wobbles up and down
CHAR = 0.03              # height of the scorched band just above the edge
RISE = 1.2               # how fast the flame texture climbs, in frame heights per second
HEAT = [0, 0.25, 0.5, 0.75, 1.0]                                                    # flame heat...
COLORS = [(40, 5, 0), (180, 25, 0), (250, 100, 10), (255, 180, 40), (255, 245, 200)]  # ...and its color: ember, red, orange, amber, near white
SEED = 3                 # change for different flames

def noise(x, y, cols, rows, layer):
    """Smooth random values in 0-1 at x, y (0-1 across and down; y may run past 1), on a cols x rows grid."""
    grid = np.random.default_rng([SEED, layer]).random((64, cols + 1))
    gx, gy = x * cols, y * rows
    ix, iy = np.floor(gx).astype(int), np.floor(gy).astype(int)
    fx, fy = gx - ix, gy - iy
    fx, fy = fx * fx * (3 - 2 * fx), fy * fy * (3 - 2 * fy)
    iy0, iy1, ix1 = iy % 64, (iy + 1) % 64, np.minimum(ix + 1, cols)
    top = grid[iy0, ix] * (1 - fx) + grid[iy0, ix1] * fx
    bottom = grid[iy1, ix] * (1 - fx) + grid[iy1, ix1] * fx
    return top * (1 - fy) + bottom * fy

def burn(frame_a, frame_b, t):
    """Clip A burning away to clip B, u = 0 -> 1 through the transition."""
    u = (t - offset) / D
    edge = 1 + FLAME - (1 + 2 * FLAME) * u + RAGGED * (noise(xs[0], t * 0.8, 9, 1, 0) - 0.5)
    d = edge[None, :] - ys                                   # distance above the burning edge (negative: already burned)
    picture = np.where((d < 0)[..., None], frame_b, frame_a * np.clip(d / CHAR, 0.15, 1)[..., None])
    climb = ys + RISE * t                                    # the texture scrolls up, so the flames lick upwards
    flicker = 0.6 * noise(xs, climb, 9, 5, 1) + 0.4 * noise(xs, climb * 1.7, 22, 10, 2)
    reach = FLAME * (0.3 + 0.9 * flicker)                     # each tongue of flame reaches a different height
    heat = np.clip(1 - d / reach, 0, 1) * (d > 0)             # hottest at the edge, cooling towards the tips
    heat = np.maximum(0.85 * heat, np.exp(-(d / 0.01) ** 2))  # white-hot line right on the edge
    color = np.stack([np.interp(heat, HEAT, [c[k] for c in COLORS]) for k in range(3)], axis=2)
    alpha = np.clip(heat / 0.3, 0, 1)[..., None]               # soft only at the very tips
    return picture * (1 - alpha) + color * alpha

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):
    """Decode a clip at the output's size and frame rate, one RGB array per frame."""
    dec = subprocess.Popen(["ffmpeg", "-v", "error", "-i", path, "-vf",
                            f"scale={w}:{h}:force_original_aspect_ratio=increase,crop={w}:{h},fps={fps}",
                            "-f", "rawvideo", "-pix_fmt", "rgb24", "-"], stdout=subprocess.PIPE)
    while raw := dec.stdout.read(w * h * 3):
        yield np.frombuffer(raw, np.uint8).reshape(h, w, 3).astype(np.float32)

a, b, out = sys.argv[1:4]
w, h, len_a = probe(a)
fps = 30
offset = len_a - D
ys, xs = np.mgrid[0:h, 0:w] / np.array([h, w]).reshape(2, 1, 1)
enc = subprocess.Popen(["ffmpeg", "-y", "-v", "error", "-i", a, "-i", b,
                        "-f", "rawvideo", "-pix_fmt", "rgb24", "-s", f"{w}x{h}", "-r", str(fps), "-i", "-",
                        "-filter_complex", f"[0:a][1:a]acrossfade=d={D}[au]",
                        "-map", "2:v", "-map", "[au]", "-c:v", "libx264", "-crf", "18", "-pix_fmt", "yuv420p", "-c:a", "aac", out],
                       stdin=subprocess.PIPE)
clip_a, clip_b = frames(a), frames(b)
i = 0
for frame_a in clip_a:                                       # A on its own, then A burning into the start of B
    t = i / fps
    picture = frame_a if t < offset else burn(frame_a, next(clip_b), t)
    enc.stdin.write(picture.clip(0, 255).astype(np.uint8).tobytes())
    i += 1
for frame_b in clip_b:                                       # the rest of B
    enc.stdin.write(frame_b.astype(np.uint8).tobytes())
enc.stdin.close()
sys.exit("ffmpeg failed" if enc.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)
