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 sci-fi HUD overlay to input.mp4 Label: TARGET LOCKED
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 sci-fi hud overlay 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 |
|---|---|---|
START | 0.5 | Second the HUD starts booting up. |
BOOT | 0.5 | Seconds the brackets and reticle take to slide into place. |
COLOR | (80, 255, 230) | Line and text color. |
RETICLE | 0.20 | Reticle ring radius as a share of the frame width. |
SPIN | 90 | Degrees per second the reticle's outer arcs turn. |
LABEL | TARGET LOCKED | Text under the reticle. |
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 sci-fi HUD overlay to input.mp4, all lines and text in (80, 255, 230) with a soft 4-pixel dark (0, 20, 30) shadow behind them. Before 0.5 seconds the video is untouched. From 0.5s, over 0.5 seconds with an ease-out: four L-shaped corner brackets (arms 70 pixels long, 3 pixels thick, corners 28 pixels in from each frame edge) slide in from 40 pixels further out, and a targeting reticle centered on the frame shrinks from 1.6x into place. The reticle is a 2-pixel ring with a radius of 20% of the frame width, four crosshair ticks from 0.75 to 1.2 times the radius on each side, a small 16-pixel cross in the middle, and two 60-degree arcs 5 pixels thick at 1.12 times the radius, opposite each other, turning clockwise at 90 degrees per second. Once it's in place (1.0s) show readouts in a monospaced font: "TARGET LOCKED" at 5.5% of the frame width tall, centered 34 pixels below the bottom crosshair tick, in a 2-pixel outlined box with a dark (0, 20, 30) fill at 67% opacity; a running "REC mm:ss:ff" timecode in the top-left corner and "SYS ONLINE" in the top-right corner, 14 pixels inside the brackets; and "RANGE 2.30 M" over "AZ 134.0" in the bottom-left corner, both numbers changing slowly. Text other than the label is 4% of the frame width tall. Draw it with Python and Pillow (don't use ffmpeg's drawtext filter), composite it with ffmpeg, keep the audio, and save it as output.mp4 at 30fps.Run it without Claude
This is the exact script we tested. Save it as hud-overlay.py and run:
python3 hud-overlay.py input.mp4 output.mp4Show the script
#!/usr/bin/env python3
"""HUD overlay: thin corner brackets, a spinning targeting reticle and live readouts boot up over the video.
Usage: python3 hud-overlay.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, ImageFilter, ImageFont
START = 0.5 # second the HUD starts booting up
BOOT = 0.5 # seconds the brackets and reticle take to slide and shrink into place
COLOR = (80, 255, 230) # HUD line and text color
LINE = 3 # line thickness in pixels
INSET = 28 # corner brackets' distance from the frame edge, in pixels
ARM = 70 # length of each bracket arm, in pixels
RETICLE = 0.20 # reticle ring radius as a share of the frame width, centered on the frame
SPIN = 90 # degrees per second the reticle's outer arcs turn
LABEL = "TARGET LOCKED" # text under the reticle
FONTS = ["/System/Library/Fonts/Menlo.ttc", # macOS
"/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", # Linux
"C:/Windows/Fonts/consola.ttf"] # Windows
FONT_FILE = next((f for f in FONTS if Path(f).exists()), None) or sys.exit("No monospaced font found: add one to FONTS")
def brackets(draw, p):
"""L-shaped brackets in the four corners, sliding in from 40px further out as p goes 0 -> 1."""
off = round(40 * (1 - p))
for sx, sy in [(1, 1), (-1, 1), (1, -1), (-1, -1)]:
x = (INSET - off) if sx > 0 else w - 1 - INSET + off
y = (INSET - off) if sy > 0 else h - 1 - INSET + off
draw.line([(x, y + sy * ARM), (x, y), (x + sx * ARM, y)], fill=COLOR, width=LINE, joint="curve")
def reticle(draw, t, p):
"""A ring with crosshair ticks and two spinning arcs, shrinking from 1.6x its size as p goes 0 -> 1."""
cx, cy = w / 2, h / 2
r = w * RETICLE * (1.6 - 0.6 * p)
draw.ellipse([cx - r, cy - r, cx + r, cy + r], outline=COLOR, width=2)
for dx, dy in [(1, 0), (-1, 0), (0, 1), (0, -1)]:
draw.line([(cx + dx * r * 0.75, cy + dy * r * 0.75), (cx + dx * r * 1.2, cy + dy * r * 1.2)], fill=COLOR, width=LINE)
draw.line([(cx - 8, cy), (cx + 8, cy)], fill=COLOR, width=2)
draw.line([(cx, cy - 8), (cx, cy + 8)], fill=COLOR, width=2)
R = r * 1.12
turn = SPIN * (t - START)
for a in (turn, turn + 180):
draw.arc([cx - R, cy - R, cx + R, cy + R], a, a + 60, fill=COLOR, width=LINE + 2)
def readouts(draw, t):
"""Timecode top left, status top right, the label under the reticle and changing numbers bottom left."""
frames = round(t * 30)
draw.text((INSET + 14, INSET + 14), f"REC {frames // 30 // 60:02d}:{frames // 30 % 60:02d}:{frames % 30:02d}",
font=small, fill=COLOR)
draw.text((w - INSET - 14, INSET + 14), "SYS ONLINE", font=small, fill=COLOR, anchor="ra")
y = h / 2 + w * RETICLE * 1.2 + 34
box = draw.textbbox((w / 2, y), LABEL, font=big, anchor="mm")
draw.rectangle([box[0] - 12, box[1] - 8, box[2] + 12, box[3] + 8], fill=(0, 20, 30, 170), outline=COLOR, width=2)
draw.text((w / 2, y), LABEL, font=big, fill=COLOR, anchor="mm")
draw.text((INSET + 14, h - INSET - 14), f"RANGE {2.4 - 0.1 * t:.2f} M\nAZ {134 + 7 * math.sin(t * 2):6.1f}",
font=small, fill=COLOR, anchor="ld", spacing=6)
def overlay(t):
img = Image.new("RGBA", (w, h))
if t < START:
return img
p = ease_out(min((t - START) / BOOT, 1))
draw = ImageDraw.Draw(img)
brackets(draw, p)
reticle(draw, t, p)
if p >= 1:
readouts(draw, t)
shadow = Image.new("RGBA", (w, h), (0, 20, 30))
shadow.putalpha(img.getchannel("A").filter(ImageFilter.GaussianBlur(4)).point(lambda a: min(255, a * 2)))
shadow.alpha_composite(img)
return shadow
def ease_out(p):
return 1 - (1 - p) ** 3
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)
small = ImageFont.truetype(FONT_FILE, round(w * 0.04))
big = ImageFont.truetype(FONT_FILE, round(w * 0.055))
render(src, out)





