---
title: "How to add an explosion with Claude (tested prompt and script)"
description: "At 1 second the frame flashes white and a ragged fireball bursts out over the bottle, throwing sparks, then burns down to orange flames and dark smoke that drifts upward and clears. Install one skill and ask Claude Code, or run the Python script we tested yourself."
url: https://www.recharm.com/effects/explosion
---

# How to add an explosion with Claude

At 1 second the frame flashes white and a ragged fireball bursts out over the bottle, throwing sparks, then burns down to orange flames and dark smoke that drifts upward and clears.

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 an explosion to input.mp4
   Palette: dark smoke, deep red, orange, yellow, white-hot
   ```

## 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 an explosion 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                                                                        |
| ------------- | ------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `AT`          | `1.0`                                             | Second it goes off.                                                                 |
| `X, Y`        | `0.5, 0.62`                                       | Where it goes off (0-1 across and down the frame).                                  |
| `SIZE`        | `0.40`                                            | Fireball radius at full size, as a share of the frame width.                        |
| `GROW`        | `0.25`                                            | Seconds the fireball takes to reach about two thirds of its size.                   |
| `BURN`        | `1.0`                                             | Seconds of fire before only smoke is left.                                          |
| `SMOKE`       | `1.6`                                             | Seconds the smoke then takes to fade away.                                          |
| `RISE`        | `70`                                              | How fast the cloud drifts up, in pixels per second.                                 |
| `FLASH`       | `0.15`                                            | Seconds the white flash takes to die down.                                          |
| `SPARKS`      | `90`                                              | Burning sparks thrown out.                                                          |
| `SPARK_SPEED` | `900`                                             | How fast the fastest sparks fly out, in pixels per second.                          |
| `PALETTE`     | `dark smoke, deep red, orange, yellow, white-hot` | Fireball colors from cold to hot.                                                   |
| `DETAIL`      | `2`                                               | How much coarser than the frame the cloud is worked out; 1 is sharpest and slowest. |
| `SEED`        | `4`                                               | Change for a different cloud and spark pattern.                                     |

## Without the skill

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

```
Add an explosion to input.mp4 at 1.0 seconds, centered 50% across and 62% down. Before 1.0s the video is unchanged. At 1.0s the whole frame flashes toward white (blend 90% of the way to white, decaying as exp(-age/0.15 s)). A fireball grows from that point: its radius is 0.40 x frame width x (1 - exp(-age/0.25) + 0.12 x age), its center drifts up at 70 pixels per second, and its edge is ragged and billowing (use smooth tileable noise that scrolls over time and shade the colors by it, 0.7 to 1.3). Color it by heat from a palette: white-hot (255, 250, 225) in the core, yellow (255, 200, 60), orange (250, 105, 10), deep red (150, 25, 5) and dark smoke (45, 40, 38) at zero heat. The heat drops steadily so after 1.0 second of burning only smoke is left, and the smoke fades out linearly over the next 1.6 seconds, so nothing is left by 3.6s. Also throw 90 small yellow-white sparks outward from the center at 270 to 900 pixels per second with drag and a little gravity, each with a short fading trail, gone within 1.1 seconds. Lay the fireball and smoke over the shot with real opacity (not a screen blend) so they show on the pale backdrop. Use Python with numpy (no text, and don't rely on ffmpeg's drawtext filter), keep the audio, and save it as output.mp4.
```

## Run it without Claude

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

```
python3 explosion.py input.mp4 output.mp4
```

```
#!/usr/bin/env python3
"""Explosion: a white flash, then a billowing fireball bursts out of one point with flying sparks and cools into rising smoke.

Usage: python3 explosion.py input.mp4 output.mp4
Needs ffmpeg and numpy (pip install numpy).
"""
import json
import subprocess
import sys

import numpy as np

AT = 1.0                      # second it goes off
X, Y = 0.5, 0.62              # where it goes off (0-1 across and down the frame)
SIZE = 0.40                   # fireball radius at full size, as a share of the frame width
GROW = 0.25                   # seconds the fireball takes to reach about two thirds of its size
BURN = 1.0                    # seconds of fire before only smoke is left
SMOKE = 1.6                   # seconds the smoke then takes to fade away
RISE = 70                     # how fast the cloud drifts up, in pixels per second
FLASH = 0.15                  # seconds the white flash takes to die down
SPARKS = 90                   # burning sparks thrown out
SPARK_SPEED = 900             # how fast sparks fly out, in pixels per second
PALETTE = [(0.00, (45, 40, 38)),       # heat 0: dark smoke
           (0.30, (150, 25, 5)),       # deep red
           (0.55, (250, 105, 10)),     # orange
           (0.80, (255, 200, 60)),     # yellow
           (1.00, (255, 250, 225))]    # white-hot core
DETAIL = 2                    # the cloud is worked out on a grid this many times coarser than the frame, then smoothed up
SEED = 4                      # change for a different cloud and spark pattern

def probe(path):
    info = json.loads(subprocess.check_output(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
                                               "stream=width,height,r_frame_rate", "-of", "json", path]))
    s = info["streams"][0]
    num, den = s["r_frame_rate"].split("/")
    return s["width"], s["height"], s["r_frame_rate"], float(num) / float(den)

def turbulence(size):
    """Smooth random pattern (0-1) that wraps round at every edge: the billows of the cloud."""
    f = np.hypot(np.fft.fftfreq(size)[:, None], np.fft.rfftfreq(size)[None, :])
    f[0, 0] = 1
    tex = np.fft.irfft2(np.fft.rfft2(rng.standard_normal((size, size))) / f ** 1.5 * (f > 0.01), (size, size))
    lo, hi = np.percentile(tex, [1, 99])
    return np.clip((tex - lo) / (hi - lo), 0, 1)

def sample(tex, u, v):
    """Tex at fractional, wrapping coordinates u (across) and v (down), blended between the four nearest texels."""
    n = len(tex)
    u0, v0 = np.floor(u).astype(int), np.floor(v).astype(int)
    fu, fv = u - u0, v - v0
    u0, v0, u1, v1 = u0 % n, v0 % n, (u0 + 1) % n, (v0 + 1) % n
    return (tex[v0, u0] * (1 - fu) + tex[v0, u1] * fu) * (1 - fv) + (tex[v1, u0] * (1 - fu) + tex[v1, u1] * fu) * fv

def cloud(age):
    """Fireball color and opacity (0-1) over the whole frame, `age` seconds after it went off."""
    radius = SIZE * w * (1 - np.exp(-age / GROW) + 0.12 * age)   # bursts out fast, then keeps swelling slowly
    cx, cy = X * w, Y * h - RISE * age
    u, v = (gx - cx) / radius, (gy - cy) / radius                 # the frame in fireball radii from its center
    boil = 0.6 * sample(big, 70 * u + 9 * age, 70 * v - 14 * age) + 0.4 * sample(small, 150 * u - 6 * age, 150 * v - 20 * age)
    density = np.clip(1.7 * (1 - np.hypot(u, v)) + 1.3 * (boil - 0.5), 0, 1)   # ragged, billowing edge
    heat = np.clip(1.3 * density + 0.8 * (boil - 0.5) + 0.3 - 1.4 * age / BURN, 0, 1) * (density > 0)  # cools from the edge in
    shade = 0.7 + 0.6 * boil                                      # lit and shadowed billows
    fade = 1 - np.clip((age - BURN) / SMOKE, 0, 1)
    alpha = np.clip(2 * density, 0, 1) * np.maximum(0.85, heat) * fade
    color = [up_rows @ (np.interp(heat, stops, channel) * shade) @ up_cols for channel in colors]
    return np.stack(color, axis=-1), (up_rows @ alpha @ up_cols)[..., None]

def sparks(age):
    """Burning sparks as an additive light layer: short trails flying out of the blast, slowing and dropping."""
    light = np.zeros((h, w, 3), np.float32)
    for k in range(8):                                             # 8 points down each trail, fading to the tail
        a = age - k * 0.008
        if a <= 0:
            continue
        travel = (1 - np.exp(-2.5 * a)) / 2.5
        x = (X * w + vx * travel).astype(int)
        y = (Y * h + vy * travel + 250 * a ** 2).astype(int)
        glow = np.clip(1 - a / life, 0, 1)[:, None] * (1 - k / 8) * np.array((1, 0.75, 0.35), np.float32)
        inside = (x > 0) & (x < w - 1) & (y > 0) & (y < h - 1)
        for dx, dy in ((0, 0), (1, 0), (-1, 0), (0, 1), (0, -1)):
            np.add.at(light, (y[inside] + dy, x[inside] + dx), glow[inside] * 255)
    return light

def stretch_matrix(n, size):
    """Matrix that resizes n samples to `size` with linear interpolation."""
    pos = np.clip((np.arange(size) + 0.5) / size * n - 0.5, 0, n - 1)
    m = np.zeros((size, n), np.float32)
    i0 = np.minimum(pos.astype(int), n - 2)
    m[np.arange(size), i0] = 1 - (pos - i0)
    m[np.arange(size), i0 + 1] = pos - i0
    return m

src, out = sys.argv[1:3]
w, h, rate, fps = probe(src)
rng = np.random.default_rng(SEED)
big, small = turbulence(256), turbulence(256)
gh, gw = -(-h // DETAIL), -(-w // DETAIL)
gy, gx = np.mgrid[0:gh, 0:gw].astype(np.float32) * DETAIL
up_rows, up_cols = stretch_matrix(gh, h), stretch_matrix(gw, w).T
stops = [s for s, _ in PALETTE]
colors = np.array([c for _, c in PALETTE], np.float32).T
angle = rng.uniform(0, 2 * np.pi, SPARKS)
speed = SPARK_SPEED * rng.uniform(0.3, 1.0, SPARKS)
vx, vy = speed * np.cos(angle), speed * np.sin(angle)
life = rng.uniform(0.5, 1.1, SPARKS)

reader = subprocess.Popen(["ffmpeg", "-v", "error", "-i", src, "-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", rate, "-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)
i = 0
while raw := reader.stdout.read(w * h * 3):
    img = np.frombuffer(raw, np.uint8).reshape(h, w, 3).astype(np.float32)
    age = i / fps - AT
    if 0 < age < BURN + SMOKE:
        flash = np.exp(-age / FLASH)                                   # the whole frame blows out, then settles
        img += (255 - img) * 0.9 * flash
        color, alpha = cloud(age)
        img = img * (1 - alpha) + color * alpha + sparks(age)
    writer.stdin.write(np.clip(img, 0, 255).astype(np.uint8).tobytes())
    i += 1
writer.stdin.close()
if reader.wait() or writer.wait():
    sys.exit("ffmpeg failed")
```

## More overlays and light

- [Anamorphic streak **Anamorphic streak**](https://www.recharm.com/effects/anamorphic-streak)
- [Aurora **Aurora**](https://www.recharm.com/effects/aurora)
- [Blood splatter **Blood splatter**](https://www.recharm.com/effects/blood-splatter)
- [Bokeh lights **Bokeh lights**](https://www.recharm.com/effects/bokeh-lights)
- [Camera flash **Camera flash**](https://www.recharm.com/effects/camera-flash)

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