Get this effect
Switch to Code in your Claude Desktop App
Install the skill (once)
Show the prompt
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/skillsAsk for the effect
Add a split-flap text to input.mp4 Lines: ["BACK IN", "STOCK"]
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 a split-flap text 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 |
|---|---|---|
LINES | ["BACK IN", "STOCK"] | The message, one board row per line. |
START | 0.5 | Second the blank board fades in. |
FLIP | 0.06 | Seconds each flap takes to fall. |
FIRST_FLIPS, EXTRA_FLIPS | 8, 2 | Flips the first tile makes, and how many more each later tile makes. |
Y | 0.20 | Center of the board, 0 at the top and 1 at the bottom. |
TILE, INK | (32, 32, 36), (250, 250, 250) | Tile and letter colors. |
Without the skill
Don’t want to install the skill? Paste this prompt into Claude Code and Claude writes the script itself.
Show the prompt
Add a split-flap board to input.mp4: "BACK IN" over "STOCK" on two rows of dark gray (32, 32, 36) rounded tiles, one tile per character with the space included, each tile 10.4% of the frame width wide and 15% of the frame width tall with gaps of 0.6% of the frame width, bold white (250, 250, 250) letters 62% of the tile height, and a thin black hinge line across each tile's middle behind the letter. The tiles sit on a near-black (8, 8, 10) rounded board that reaches 4.5% of the frame width past them, and the whole board is centered across and 20% of the way down. The board fades in at 0.5 seconds over 0.2 seconds, then every tile flips through the alphabet in order, 0.06 seconds per flip: the old letter's top half folds down to the hinge, then the new letter's bottom half swings down. The first tile makes 8 flips before it lands on its letter and each later tile, in reading order, makes 2 more, so the letters land left to right and the board reads BACK IN STOCK by 2.5 seconds, then stays. Use Python with Pillow to draw it and ffmpeg to put it on the video (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 split-flap-text.py and run:
python3 split-flap-text.py input.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""Split-flap text: a black departures board flips each tile through the alphabet until it spells the message.
Usage: python3 split-flap-text.py input.mp4 output.mp4
Needs ffmpeg and Pillow (pip install pillow).
"""
import json
import math
import subprocess
import sys
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
LINES = ["BACK IN", "STOCK"] # the message, one board row per line
START = 0.5 # second the blank board fades in
FADE = 0.2 # seconds the board takes to fade in
FLIP = 0.06 # seconds each flap takes to fall
FIRST_FLIPS = 8 # flips the first tile makes before it lands
EXTRA_FLIPS = 2 # each later tile makes this many more, so they land left to right
Y = 0.20 # center of the board (0 = top, 1 = bottom)
TILE_W, TILE_H = 0.104, 0.15 # tile width and height as a share of the frame width
GAP = 0.006 # space between tiles, share of the frame width
PAD = 0.045 # board frame around the tiles, share of the frame width
TILE = (32, 32, 36) # tile color
BOARD = (8, 8, 10) # color of the board behind the tiles
INK = (250, 250, 250) # letter color
CHARS = " ABCDEFGHIJKLMNOPQRSTUVWXYZ" # the order letters come round on each tile
FONTS = ["/System/Library/Fonts/Supplemental/Arial Bold.ttf", # macOS
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", # Linux
"C:/Windows/Fonts/arialbd.ttf"] # Windows
FONT_FILE = next((f for f in FONTS if Path(f).exists()), None) or sys.exit("No bold font found: add one to FONTS")
def tile(ch):
"""One flap tile showing ch, with the hinge line across the middle behind the letter."""
img = Image.new("RGBA", (tw, th))
draw = ImageDraw.Draw(img)
draw.rounded_rectangle([0, 0, tw - 1, th - 1], radius=tw // 10, fill=TILE)
draw.line([0, th // 2, tw, th // 2], fill=(0, 0, 0), width=max(2, th // 40))
draw.text((tw / 2, th / 2), ch, font=font, anchor="mm", fill=INK)
return img
def flap(old, new, p):
"""Tile partway through a flip from old to new: new's top shows behind old's top flap, which folds
down to the hinge (p 0 -> 0.5), then new's bottom flap unfolds down over old's bottom (0.5 -> 1)."""
a, b = tiles[old], tiles[new]
half = th // 2
img = Image.new("RGBA", (tw, th))
img.paste(b.crop((0, 0, tw, half)), (0, 0))
img.paste(a.crop((0, half, tw, th)), (0, half))
if p < 0.5:
fh = max(1, round(half * (1 - 2 * p)))
img.paste(a.crop((0, 0, tw, half)).resize((tw, fh)), (0, half - fh))
else:
fh = max(1, round(half * (2 * p - 1)))
img.paste(b.crop((0, half, tw, th)).resize((tw, fh)), (0, half))
return img
def tile_at(k, target, t):
"""What tile k (in reading order) shows at time t: it steps through CHARS and lands on target."""
flips = FIRST_FLIPS + EXTRA_FLIPS * k
done = (t - START - FADE) / FLIP # flips made so far, counting the one under way as a fraction
if done >= flips:
return tiles[target]
i = int(max(done, 0))
end = CHARS.index(target)
old = CHARS[(end - flips + i) % len(CHARS)]
new = CHARS[(end - flips + i + 1) % len(CHARS)]
return flap(old, new, max(done, 0) - i)
def overlay(t):
img = Image.new("RGBA", (w, h))
if t < START:
return img
top = h * Y - (len(LINES) * th + (len(LINES) - 1) * gap) / 2
widest = max(len(line) for line in LINES) * (tw + gap) - gap
ImageDraw.Draw(img).rounded_rectangle([(w - widest) / 2 - pad, top - pad, (w + widest) / 2 + pad, h * Y * 2 - top + pad],
radius=pad // 2, fill=BOARD)
k = 0
for row, line in enumerate(LINES):
x0 = (w - len(line) * tw - (len(line) - 1) * gap) / 2
y0 = top + row * (th + gap)
for col, ch in enumerate(line):
img.alpha_composite(tile_at(k, ch, t), (round(x0 + col * (tw + gap)), round(y0)))
k += 1
fade = min((t - START) / FADE, 1)
img.putalpha(img.getchannel("A").point(lambda a: round(a * fade)))
return img
def probe(path):
info = json.loads(subprocess.check_output(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
"stream=width,height,r_frame_rate:format=duration", "-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), float(info["format"]["duration"])
def render(src, out):
"""Draw overlay(t) on every frame of src and save to out, keeping the audio."""
ff = subprocess.Popen(["ffmpeg", "-y", "-v", "error", "-i", src,
"-f", "rawvideo", "-pix_fmt", "rgba", "-s", f"{w}x{h}", "-r", rate, "-i", "-",
"-filter_complex", "[0:v][1:v]overlay=shortest=1,format=yuv420p[v]",
"-map", "[v]", "-map", "0:a?", "-c:v", "libx264", "-crf", "18", "-c:a", "copy", out],
stdin=subprocess.PIPE)
for i in range(math.ceil(duration * fps)):
ff.stdin.write(overlay(i / fps).tobytes())
ff.stdin.close()
if ff.wait():
sys.exit("ffmpeg failed")
src, out = sys.argv[1:3]
w, h, rate, fps, duration = probe(src)
tw, th, gap, pad = (round(w * s) for s in (TILE_W, TILE_H, GAP, PAD))
font = ImageFont.truetype(FONT_FILE, round(th * 0.62))
tiles = {ch: tile(ch) for ch in CHARS}
render(src, out)





