How to add a countdown intro with Claude

Before the clip plays, giant white numbers 3, 2, 1 fill a blurred, darkened still, one per second, each with a beep and a yellow ring draining around it.

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 countdown intro to input.mp4
    First number shown; the countdown adds this many seconds to the start: 3
    Number height as a share of the frame width: 0.62

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 countdown intro 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_FROM3First number shown; the countdown adds this many seconds to the start.
NUMBER_SIZE0.62Number height as a share of the frame width.
RING_COLOR(255, 214, 0)Color of the ring that drains around each number.
BACKDROP0.3Brightness of the blurred first frame behind the numbers (1 = unchanged).
BEEP880Pitch in Hz of the beep on each number; 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 3-second countdown before input.mp4. Make a backdrop from the video's first frame: Gaussian blur with radius 4% of the frame width, brightness down to 30%. On it, for 1 second each, draw a white number 3, then 2, then 1, centered in the frame, about 62% of the frame width tall (bold font); each number lands from 125% size to 100% over its first 0.2 seconds. Around the number draw a ring centered on the frame, radius 42% of the frame width, 2.5% of the width thick: a dark gray (90, 90, 90) track with a yellow (255, 214, 0) arc that starts full at 12 o'clock and drains clockwise to nothing over the second. Add an 880 Hz beep 0.15 seconds long at the start of each number. Then play the whole of input.mp4 with its own audio. Keep the size, use 30 fps, and the result is 3 seconds longer than the input. Use Python with Pillow to draw the countdown 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 countdown-intro.py and run:

python3 countdown-intro.py input.mp4 output.mp4
Show the script
#!/usr/bin/env python3
"""Countdown intro: huge numbers 3, 2, 1 fill the screen, each with a beep and a draining ring, before the video starts.

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

from PIL import Image, ImageDraw, ImageEnhance, ImageFilter, ImageFont

COUNT_FROM = 3              # first number shown; one number per second down to 1
NUMBER_SIZE = 0.62          # number height as a share of the frame width
RING_COLOR = (255, 214, 0)  # ring that drains around each number
BACKDROP = 0.3              # brightness of the blurred first frame behind the numbers (1 = unchanged)
BEEP = 880                  # pitch in Hz of the beep on each number (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")


def backdrop(src):
    """The video's first frame, blurred and darkened, so the countdown sits on the same colors."""
    raw = subprocess.check_output(["ffmpeg", "-v", "error", "-i", src, "-frames:v", "1", "-f", "rawvideo", "-pix_fmt", "rgb24", "-"])
    still = Image.frombytes("RGB", (w, h), raw).filter(ImageFilter.GaussianBlur(w * 0.04))
    return ImageEnhance.Brightness(still).enhance(BACKDROP)


def countdown_frame(t):
    number, p = COUNT_FROM - int(t), t % 1          # p: how far through this number's second
    img = bg.copy()
    draw = ImageDraw.Draw(img)
    r, stroke = w * 0.42, round(w * 0.025)
    box = [w / 2 - r, h / 2 - r, w / 2 + r, h / 2 + r]
    draw.ellipse(box, outline=(90, 90, 90), width=stroke)
    draw.arc(box, -90 + 360 * p, 270, fill=RING_COLOR, width=stroke)
    pop = 1 + 0.25 * max(0, 1 - p / 0.2) ** 2       # each number lands from 125% size over 0.2s
    font = ImageFont.truetype(FONT_FILE, round(w * NUMBER_SIZE * 1.38 * pop))   # digits are ~0.72 of the font size tall
    draw.text((w / 2, h / 2), str(number), font=font, anchor="mm", fill="white")
    return img


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)
bg = backdrop(src)
# countdown frames come in on stdin, the beeps from a tone generator, then both are joined to the video
beeps = f"0.4*sin(2*PI*{BEEP}*t)*lt(mod(t,1),0.15)"
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='{beeps}':s=48000:d={COUNT_FROM}",
                       "-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(COUNT_FROM * 30):
    ff.stdin.write(countdown_frame(i / 30).tobytes())
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