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
Make a comic panel layout from main.mp4 and second.mp4 and wide.mp4 Caption: MEANWHILE...
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 comic panel layout 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 |
|---|---|---|
GUTTER | 0.03 | White gap between panels and round the page, as a share of the frame width. |
BORDER | 6 | Black panel border in pixels. |
TOP_SHARE, LEFT_SHARE | 0.42, 0.56 | Where the top panel ends down the frame and the bottom-left panel ends across it. |
APPEAR | (0.0, 0.5, 1.0) | Seconds the top, bottom-left and bottom-right panels snap in. |
CAPTION | MEANWHILE... | Text in the caption box. |
CAPTION_AT | 1.5 | Second the caption box appears. |
CAPTION_COLOR | (250, 215, 0) | Caption box yellow. |
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
Make a comic-page layout from main.mp4, second.mp4 and wide.mp4, the same size as main.mp4 (540x960), 30fps, 6 seconds. Start from a white page. Lay out three panels with 16px white gutters between them and round the page edge: a wide top panel from (16, 16) to (524, 403), a bottom-left panel from (16, 419) to (302, 944) and a narrow bottom-right panel from (318, 419) to (524, 944) (pixel corners, x then y). Each panel has a 6px black border on the inside of its box, and the clip fills the area inside the border, scaled to cover it and cropped from the center. wide.mp4 goes in the top panel and appears at 0 seconds, main.mp4 in the bottom-left panel snaps in at 0.5 seconds, second.mp4 in the bottom-right panel snaps in at 1.0 second; before a panel snaps in its space is plain white page. At 1.5 seconds, a caption box appears flush in the top panel's top-left corner (its top-left at (16, 16)): a yellow (250, 215, 0) rectangle with a 6px black outline and "MEANWHILE..." in black bold text 27px tall, with 11px padding, and it stays to the end. All clips keep playing. Draw the caption box with Python and Pillow (not ffmpeg's drawtext filter), keep main.mp4's audio, and save it as output.mp4.Run it without Claude
This is the exact script we tested. Save it as comic-panel-layout.py and run:
python3 comic-panel-layout.py main.mp4 second.mp4 wide.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""Comic panel layout: three clips snap one by one into black-bordered panels on a white page, then a yellow caption box.
Usage: python3 comic-panel-layout.py main.mp4 second.mp4 wide.mp4 output.mp4
main.mp4 sets the size and the sound and fills the big bottom-left panel; second.mp4 fills the narrow
bottom-right panel; wide.mp4 fills the wide top panel.
Needs ffmpeg and Pillow (pip install pillow).
"""
import json
import subprocess
import sys
import tempfile
from pathlib import Path
from PIL import Image, ImageDraw, ImageFont
GUTTER = 0.03 # white gap between panels and round the page, as a share of the frame width
BORDER = 6 # black panel border in pixels
TOP_SHARE = 0.42 # the top panel ends this far down the frame
LEFT_SHARE = 0.56 # the bottom-left panel ends this far across the frame
APPEAR = (0.0, 0.5, 1.0) # seconds the top, bottom-left and bottom-right panels snap in
CAPTION = "MEANWHILE..."
CAPTION_AT = 1.5 # second the caption box appears in the top panel's top-left corner
CAPTION_COLOR = (250, 215, 0) # caption box yellow
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 panels():
"""Boxes (x0, y0, x1, y1) in pixels for the top, bottom-left and bottom-right panels."""
g = round(w * GUTTER)
split_y, split_x = round(h * TOP_SHARE), round(w * LEFT_SHARE)
return [(g, g, w - g, split_y),
(g, split_y + g, split_x, h - g),
(split_x + g, split_y + g, w - g, h - g)]
def caption_box(path):
font = ImageFont.truetype(FONT_FILE, round(w * 0.05))
left, top, right, bottom = font.getbbox(CAPTION)
pad = round(w * 0.02)
img = Image.new("RGBA", (right - left + 2 * pad, bottom - top + 2 * pad))
draw = ImageDraw.Draw(img)
draw.rectangle([0, 0, img.width - 1, img.height - 1], fill=CAPTION_COLOR, outline="black", width=BORDER)
draw.text((pad - left, pad - top), CAPTION, font=font, fill="black")
img.save(path)
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]))
s = info["streams"][0]
return s["width"], s["height"], float(info["format"]["duration"])
main, second, wide, out = sys.argv[1:5]
w, h, duration = probe(main)
boxes = panels()
with tempfile.TemporaryDirectory() as tmp:
caption = str(Path(tmp) / "caption.png")
caption_box(caption)
# each clip is cropped to fill its panel inside the border, then padded out with the black border
graph = [f"color=white:s={w}x{h}:r=30:d={duration}[page]"]
for i, (x0, y0, x1, y1) in enumerate(boxes):
pw, ph = x1 - x0, y1 - y0
graph.append(f"[{i}:v]fps=30,scale={pw - 2 * BORDER}:{ph - 2 * BORDER}:force_original_aspect_ratio=increase,"
f"crop={pw - 2 * BORDER}:{ph - 2 * BORDER},pad={pw}:{ph}:{BORDER}:{BORDER}:black,setsar=1[p{i}]")
layer = "page"
for i, (x0, y0, _, _) in enumerate(boxes):
graph.append(f"[{layer}][p{i}]overlay={x0}:{y0}:enable='gte(t,{APPEAR[i]})'[l{i}]")
layer = f"l{i}"
x0, y0 = boxes[0][:2]
graph.append(f"[{layer}][3:v]overlay={x0}:{y0}:enable='gte(t,{CAPTION_AT})',format=yuv420p[v]")
# panel order on the page: wide on top, main bottom-left, second bottom-right
subprocess.run(["ffmpeg", "-y", "-v", "error", "-i", wide, "-i", main, "-i", second, "-loop", "1", "-i", caption,
"-filter_complex", ";".join(graph), "-map", "[v]", "-map", "1:a?", "-t", str(duration),
"-c:v", "libx264", "-crf", "18", "-c:a", "copy", out], check=True)





