---
title: "How to add a hexagon transition with Claude (tested prompt and script)"
description: "Honeycomb cells of clip B grow open from the middle of the frame outward, each white-rimmed hexagon widening until the cells lock together and clip A is gone, over 1.2 seconds. Install one skill and ask Claude Code, or run the Python script we tested yourself."
url: https://www.recharm.com/effects/hexagon-transition
---

# How to add a hexagon transition with Claude

Honeycomb cells of clip B grow open from the middle of the frame outward, each white-rimmed hexagon widening until the cells lock together and clip A is gone, over 1.2 seconds.

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 hexagon transition
   Length of the transition in seconds: 1.2
   Hexagon size from center to corner, in pixels: 60
   ```

## 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 hexagon 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.2`             | Length of the transition in seconds.                                                                  |
| `R`         | `60`              | Hexagon size from center to corner, in pixels.                                                        |
| `GROW`      | `0.5`             | Share of the transition each cell takes to open; the rest staggers the cells outward from the center. |
| `RIM`       | `0.08`            | Thickness of the white rim, as a share of a cell's center-to-edge distance (about 4 pixels).          |
| `RIM_COLOR` | `(255, 255, 255)` | Color of the rim on each growing hexagon.                                                             |

## 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 (both 540x960, 30fps) with a 1.2 second hexagon transition starting 1.2 seconds before A ends. Lay a honeycomb of pointy-top hexagons over the frame, 60 pixels from center to corner (104 pixels across the flat sides), with one cell centered exactly on the frame's center (270, 480). Each cell opens onto clip B as a hexagon growing from the cell's center, eased in and out (smoothstep) over 0.6 seconds, growing to 1.05 times the cell's size so neighbors close with no seams. The middle cell starts at once and the others start later in proportion to their centers' distance from the frame's center, the furthest cell starting 0.6 seconds in, so the honeycomb spreads outward and the whole transition ends at 1.2 seconds. While a cell is growing, draw a 4 pixel pure white (255, 255, 255) rim just inside its hexagon's edge; no rims before or after the transition. Crossfade the audio over the same 1.2 seconds. Match B's size and frame rate to A. Use Python with numpy (and Pillow for any drawing, not ffmpeg's drawtext) and ffmpeg, keep the audio and save it as output.mp4 (H.264, yuv420p, 30fps, 10.8 seconds long).
```

## Run it without Claude

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

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

```
#!/usr/bin/env python3
"""Hexagon transition: honeycomb cells grow open from the center outward, each with a white rim, swapping clip A for clip B over 1.2s.

Usage: python3 hexagon-transition.py clipA.mp4 clipB.mp4 output.mp4  (both clips need an audio track)
Needs ffmpeg, numpy and Pillow (pip install numpy pillow).
"""
import json
import subprocess
import sys
from itertools import islice

import numpy as np

D = 1.2                  # transition length in seconds
FPS = 30                 # output frame rate
R = 60                   # hexagon size: center to corner, in pixels
GROW = 0.5               # share of the transition each cell takes to open
RIM = 0.08               # rim thickness, as a share of the cell's center-to-edge distance (about 4 px)
RIM_COLOR = (255, 255, 255)

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 as w x h RGB frames at FPS, cropping it to fill the frame if its shape differs."""
    ff = 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 True:
        data = ff.stdout.read(w * h * 3)
        if len(data) < w * h * 3:
            return
        yield np.frombuffer(data, np.uint8).reshape(h, w, 3)

def honeycomb():
    """For every pixel: how far it sits from its cell's center (0 at the center, 1 on the cell's edge),
    and when its cell starts to open (0 for the middle cell, 1 - GROW for the cells furthest out)."""
    y, x = np.mgrid[0:h, 0:w].astype(np.float32)
    x, y = x - w / 2, y - h / 2                      # a cell sits right on the frame's center
    # pointy-top hex grid: pixel -> axial (q, r), rounded to the nearest cell in cube coordinates
    q, r = (np.sqrt(3) / 3 * x - y / 3) / R, (2 / 3 * y) / R
    s = -q - r
    rq, rr, rs = np.round(q), np.round(r), np.round(s)
    dq, dr, ds = abs(rq - q), abs(rr - r), abs(rs - s)
    rq = np.where((dq > dr) & (dq > ds), -rr - rs, rq)
    rr = np.where((dr >= dq) & (dr > ds), -rq - rs, rr)
    cx, cy = R * np.sqrt(3) * (rq + rr / 2), R * 1.5 * rr
    # distance to the cell's center measured against its three pairs of edges
    ox, oy = np.abs(x - cx), np.abs(y - cy)
    edge = np.maximum(ox, ox / 2 + oy * np.sqrt(3) / 2) / (R * np.sqrt(3) / 2)
    reach = np.hypot(cx, cy)
    return edge, reach / reach.max() * (1 - GROW)

def hexagons(a, b, p):
    """One transition frame at progress p (0-1): each cell shows B inside a hexagon growing from its center."""
    local = np.clip((p - start) / GROW, 0, 1)
    size = local * local * (3 - 2 * local) * 1.05    # smoothstep, a touch past 1 so cells close with no seams
    img = np.where((edge < size)[..., None], b, a)
    img[(edge < size) & (edge >= size - RIM) & (local < 1)] = RIM_COLOR
    return img

A, B, out = sys.argv[1:4]
w, h, length = probe(A)
edge, start = honeycomb()
cut_in = round((length - D) * FPS)   # first frame of the transition
n = round(D * FPS)                   # frames in the transition

enc = 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)
clip_a, clip_b = frames(A), frames(B)
for a in islice(clip_a, cut_in):
    enc.stdin.write(a.tobytes())
for i, (a, b) in enumerate(zip(islice(clip_a, n), islice(clip_b, n))):
    enc.stdin.write(hexagons(a, b, i / n).tobytes())
for b in clip_b:
    enc.stdin.write(b.tobytes())
enc.stdin.close()
if enc.wait():
    sys.exit("ffmpeg failed")
```

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