How to add a film leader countdown with Claude

Before the clip, a grainy gray film leader counts 8 down to 2 in black numbers inside a white double ring, a dark wedge sweeping around like a clock hand each count, with a beep on the 2.

Get this effect

  1. Switch to Code in your Claude Desktop App

  2. 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/skills
  3. Ask for the effect

    Add a film leader countdown to input.mp4
    First number; the leader counts down to 2: 8
    How long each number stays (a real leader uses 1): 0.5

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 film leader countdown 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.

SettingDefaultWhat it does
COUNT_FROM8First number; the leader counts down to 2.
NUMBER_SECONDS0.5How long each number stays (a real leader uses 1).
LEADER(150, 150, 150)Gray of the film leader.
SWEPT(95, 95, 95)Darker gray the sweeping hand leaves behind.
GRAIN9Strength of the film grain; 0 for none.
POP1000Pitch in Hz of the beep on the 2; 0 for silence.

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
Put a film leader countdown before input.mp4. For 3.5 seconds at 30 fps, show gray (150, 150, 150) film leader at the video's size with the numbers 8, 7, 6, 5, 4, 3, 2 for 0.5 seconds each: a black (20, 20, 20) bold number about 45% of the frame width tall (font size 62% of the width), centered in the frame. Behind it, a darker gray (95, 95, 95) wedge centered on the frame sweeps clockwise from 12 o'clock through a full turn over each number's 0.5 seconds and reaches past the frame edges, so the frame turns dark gray behind the hand. Over the wedge draw a light (235, 235, 235) crosshair through the center, lines 0.6% of the width thick, and two (245, 245, 245) rings centered on the frame, radius 40% and 34.4% of the frame width, 1.1% of the width thick. Make every frame look like worn film: random brightness flicker of up to 4%, gray film grain (normal noise, standard deviation 9), one to three thin light vertical scratches, a few small black or white dust specks and a 2-pixel up-and-down gate weave. The leader is silent apart from a 1000 Hz beep 0.05 seconds long at 3.0 seconds, as the 2 appears. Then play the whole of input.mp4 with its own audio, so the result is 3.5 seconds longer than the input. Use Python with Pillow and numpy to draw the leader frames and ffmpeg to join them to the video (don't rely on ffmpeg's drawtext filter), and save it as output.mp4.

Run it without Claude

This is the exact script we tested. Save it as film-leader-countdown.py and run:

python3 film-leader-countdown.py input.mp4 output.mp4
Show the script
#!/usr/bin/env python3
"""Film leader countdown: a sweeping hand counts 8 down to 2 over scratchy gray film leader, then the video starts.

Usage: python3 film-leader-countdown.py input.mp4 output.mp4  (the input needs an audio track)
Needs ffmpeg, Pillow and numpy (pip install pillow numpy).
"""
import json
import subprocess
import sys
from pathlib import Path

import numpy as np
from PIL import Image, ImageDraw, ImageFont

COUNT_FROM = 8                # first number; the leader counts down to 2, like a real Academy leader
NUMBER_SECONDS = 0.5          # how long each number stays (a real leader uses 1)
LEADER = (150, 150, 150)      # gray of the film leader
SWEPT = (95, 95, 95)          # darker gray the hand leaves behind as it sweeps
GRAIN = 9                     # strength of the film grain (0 for none)
POP = 1000                    # pitch in Hz of the short beep on the 2; 0 for silence
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")

rng = np.random.default_rng(8)


def leader_frame(t):
    number, p = COUNT_FROM - int(t / NUMBER_SECONDS), t / NUMBER_SECONDS % 1   # p: how far round the hand is
    img = Image.new("RGB", (w, h), LEADER)
    draw = ImageDraw.Draw(img)
    cx, cy, r = w / 2, h / 2, w * 0.40
    big = r * 3                                                                 # the wedge reaches the frame edges
    if p > 0:
        draw.pieslice([cx - big, cy - big, cx + big, cy + big], -90, -90 + 360 * p, fill=SWEPT)
    line = max(2, round(w * 0.006))
    draw.line([0, cy, w, cy], fill=(235, 235, 235), width=line)                 # crosshair
    draw.line([cx, 0, cx, h], fill=(235, 235, 235), width=line)
    for ring in (r, r * 0.86):                                                  # double ring round the number
        draw.ellipse([cx - ring, cy - ring, cx + ring, cy + ring], outline=(245, 245, 245), width=line * 2)
    font = ImageFont.truetype(FONT_FILE, round(w * 0.62))
    draw.text((cx, cy), str(number), font=font, anchor="mm", fill=(20, 20, 20))
    return wear(np.asarray(img, np.float32))


def wear(px):
    """Grain, flicker, dust and a scratch or two, so it looks like old film run through a projector."""
    px = px * rng.uniform(0.96, 1.04) + rng.normal(0, GRAIN, (h, w, 1))
    for _ in range(rng.integers(1, 4)):                                         # vertical scratches
        x = rng.integers(0, w)
        px[:, x:x + 2] = px[:, x:x + 2] * 0.5 + 115
    for _ in range(rng.integers(3, 9)):                                         # dust specks
        x, y, s = rng.integers(0, w - 6), rng.integers(0, h - 6), rng.integers(2, 6)
        px[y:y + s, x:x + s] = rng.choice([15, 230])
    shift = rng.integers(-2, 3)                                                 # gate weave
    return np.roll(px, shift, axis=0).clip(0, 255).astype(np.uint8).tobytes()


def probe(path):
    info = json.loads(subprocess.check_output(["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
                                               "stream=width,height", "-of", "json", path]))
    return info["streams"][0]["width"], info["streams"][0]["height"]


src, out = sys.argv[1:3]
w, h = probe(src)
length = (COUNT_FROM - 1) * NUMBER_SECONDS
# leader frames come in on stdin, the beep on the 2 from a tone generator, then both are joined to the video
pop_at = length - NUMBER_SECONDS
beep = f"0.5*sin(2*PI*{POP}*t)*between(t,{pop_at},{pop_at + 0.05})"
ff = subprocess.Popen(["ffmpeg", "-y", "-v", "error",
                       "-f", "rawvideo", "-pix_fmt", "rgb24", "-s", f"{w}x{h}", "-r", "30", "-i", "-",
                       "-f", "lavfi", "-i", f"aevalsrc='{beep}':s=48000:d={length}",
                       "-i", src,
                       "-filter_complex", "[0:v]setsar=1[c];[2:v]fps=30,setsar=1[v];[1:a]aformat=channel_layouts=stereo[b];"
                                          "[2:a]aformat=sample_rates=48000:channel_layouts=stereo[a];"
                                          "[c][b][v][a]concat=n=2:v=1:a=1[joined][outa];[joined]format=yuv420p[outv]",
                       "-map", "[outv]", "-map", "[outa]", "-c:v", "libx264", "-crf", "18", "-c:a", "aac", out],
                      stdin=subprocess.PIPE)
for i in range(round(length * 30)):
    ff.stdin.write(leader_frame(i / 30))
ff.stdin.close()
if ff.wait():
    sys.exit("ffmpeg failed")

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