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 best seller badge to input.mp4 Top line, bottom line: BEST, SELLER
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 best seller badge 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 |
|---|---|---|
TOP_LINE, BOTTOM_LINE | BEST, SELLER | The two lines on the medal. |
START | 0.6 | Second the badge starts to drop in. |
SETTLE | 0.6 | Seconds it takes to land and settle. |
SIZE | 0.36 | Badge width as a share of the frame width. |
X, Y | 0.19, 0.36 | Where the badge settles, 0-1 across and down. |
GOLD | (240, 190, 50) | Wreath, rim and lettering color. |
NAVY | (25, 35, 75) | Medal center color. |
TILT | -8 | Degrees it rests at. |
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 best seller badge to input.mp4. Draw it with Python and Pillow (don't use ffmpeg's drawtext filter), at 3x size and scaled down for smooth edges, 36% of the frame width across: a gold (240, 190, 50) disc 60% of the badge across with a navy (25, 35, 75) center 53% across and a thin gold ring inside it; "BEST" in bold gold letters 12.5% of the badge tall with "SELLER" 7.5% tall under it and three small gold stars above; around the disc a gold laurel wreath, two branches of 10 pairs of pointed leaves on a thin stem rising from the bottom and nearly meeting at the top. At 0.6 seconds it fades in over 0.24 seconds while dropping from a quarter of the frame height above its spot, shrinking from 1.5x and turning from 22 to -8 degrees (clockwise tilt) over 0.6 seconds with a slight overshoot, then it stays still, centered at 19% across and 36% down, beside the bottle. Keep the audio and save it as output.mp4.Run it without Claude
This is the exact script we tested. Save it as best-seller-badge.py and run:
python3 best-seller-badge.py input.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""Best seller badge: a gold laurel-wreath medal reading "BEST SELLER" drops in and settles beside the product.
Usage: python3 best-seller-badge.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
TOP_LINE, BOTTOM_LINE = "BEST", "SELLER"
START = 0.6 # second the badge starts to drop in
SETTLE = 0.6 # seconds it takes to land and settle
SIZE = 0.36 # badge width as a share of the frame width
X, Y = 0.19, 0.36 # where the badge settles (0-1 across and down the frame)
GOLD = (240, 190, 50) # wreath, rim and lettering color
NAVY = (25, 35, 75) # medal center color
TILT = -8 # degrees it rests at
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 leaf(draw, cx, cy, angle, length, width, color):
"""A pointed leaf centered on (cx, cy), its long axis along angle (radians)."""
ux, uy, vx, vy = math.cos(angle), math.sin(angle), -math.sin(angle), math.cos(angle)
along = [i / 6 - 1 for i in range(13)] # tip to tip, -1 .. 1
outline = [(s, 1) for s in along] + [(s, -1) for s in reversed(along)]
draw.polygon([(cx + ux * s * length / 2 + vx * side * width / 2 * math.sqrt(1 - s * s),
cy + uy * s * length / 2 + vy * side * width / 2 * math.sqrt(1 - s * s)) for s, side in outline],
fill=color)
def badge():
"""The medal, drawn at 3x and scaled down for smooth edges."""
d = round(w * SIZE) * 3
img = Image.new("RGBA", (d, d))
draw = ImageDraw.Draw(img)
c, r = d / 2, d * 0.37 # center, and radius of the wreath's stems
draw.arc([c - r, c - r, c + r, c + r], 100, 240, fill=GOLD, width=d // 90)
draw.arc([c - r, c - r, c + r, c + r], -60, 80, fill=GOLD, width=d // 90)
for side in (-1, 1): # two laurel branches rising from the bottom
for k in range(10):
a = math.radians(90 - side * (12 + k * 14)) # round the side towards the top
px, py = c + r * math.cos(a), c + r * math.sin(a)
rising = a - side * math.pi / 2 # the stem's direction, heading up
for lean in (-1, 1): # a leaf to the outside and to the inside
angle = rising + side * lean * 0.55
length = d * (0.115 - k * 0.003)
leaf(draw, px + math.cos(angle) * length / 2, py + math.sin(angle) * length / 2,
angle, length, d * 0.045, GOLD)
draw.ellipse([d * 0.20, d * 0.20, d * 0.80, d * 0.80], fill=GOLD)
draw.ellipse([d * 0.235, d * 0.235, d * 0.765, d * 0.765], fill=NAVY)
draw.ellipse([d * 0.26, d * 0.26, d * 0.74, d * 0.74], outline=GOLD, width=d // 120)
draw.text((c, d * 0.45), TOP_LINE, font=ImageFont.truetype(FONT_FILE, round(d * 0.125)), anchor="mm", fill=GOLD)
draw.text((c, d * 0.575), BOTTOM_LINE, font=ImageFont.truetype(FONT_FILE, round(d * 0.075)), anchor="mm", fill=GOLD)
for i in (-1, 0, 1): # three small stars above the words
star(draw, c + i * d * 0.06, d * 0.345 - (i == 0) * d * 0.01, d * 0.023, GOLD)
return img.resize((d // 3, d // 3), Image.LANCZOS)
def star(draw, cx, cy, r, color):
pts = [(cx + (r if i % 2 == 0 else r * 0.42) * math.sin(i * math.pi / 5),
cy - (r if i % 2 == 0 else r * 0.42) * math.cos(i * math.pi / 5)) for i in range(10)]
draw.polygon(pts, fill=color)
def overlay(t):
"""The badge drops from above, shrinking from 1.5x and turning to TILT, with a small bounce as it lands."""
img = Image.new("RGBA", (w, h))
if t < START:
return img
p = ease_out_back((t - START) / SETTLE)
scale = 1.5 - 0.5 * p
b = full.resize((round(full.width * scale), round(full.height * scale)), Image.LANCZOS)
b = b.rotate(TILT + 30 * (1 - p), resample=Image.BICUBIC, expand=True)
alpha = min(1, (t - START) / (SETTLE * 0.4))
b.putalpha(b.getchannel("A").point(lambda a: round(a * alpha)))
img.alpha_composite(b, (round(w * X - b.width / 2), round(h * Y - h * 0.25 * (1 - p) - b.height / 2)))
return img
def ease_out_back(p):
"""0 -> 1 with a small overshoot past 1 before settling."""
p = min(max(p, 0), 1)
return 1 + 2.70158 * (p - 1) ** 3 + 1.70158 * (p - 1) ** 2
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)
full = badge()
render(src, out)





