How to add a camcorder date stamp with Claude

Blocky amber pixel text reading "PM 3:42:07" over "JUN. 14 1998" appears in the lower-right corner at half a second, its seconds ticking up like a 90s home-video camcorder.

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 camcorder date stamp to input.mp4
    Date: JUN. 14 1998

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 camcorder date stamp 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
START0.5Second the stamp appears.
DATEJUN. 14 1998The date on the bottom line.
HOUR, MINUTE, SECOND3, 42, 7Clock time (PM) when the stamp appears; it ticks once a second.
COLOR(255, 176, 32)Text color.
GLOW150Strength (0-255) of the soft dark glow behind the text.
BLOCK3On-screen size of one font pixel; bigger is blockier.
TEXT_SIZE15Font size in font pixels.
RIGHT, BOTTOM0.92, 0.92Right edge of the text and bottom of the date line, as shares of the frame.

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 90s camcorder date stamp to input.mp4 (540x960). Before 0.5 seconds the video is untouched; from 0.5s two right-aligned lines of amber (255, 176, 32) text sit in the lower right: "PM 3:42:07" on top and "JUN. 14 1998" below it. The clock adds one second at each whole second after 0.5s (PM 3:42:08 at 1.5s, PM 3:42:09 at 2.5s and so on). Make the text look like blocky pixel lettering: draw it with a monospace font (Andale Mono, DejaVu Sans Mono or Consolas) at size 15 on a transparent canvas a third of the frame's size (180x320) with anti-aliasing off and a 1-pixel dark (24, 16, 8) outline around every letter, then scale that canvas up 3 times with nearest-neighbor so every font pixel becomes a 3x3 block. On the small canvas, the text's right edge is at 92% across, the date line's bottom at 92% down and the clock line's bottom 18 pixels above it (54 pixels on screen). Behind the text put a soft black glow, up to 60% opacity, about 10 pixels wide on screen, so it stays readable on bright footage. Leave the rest of the picture unchanged. Draw the text 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 camcorder-date-stamp.py and run:

python3 camcorder-date-stamp.py input.mp4 output.mp4
Show the script
#!/usr/bin/env python3
"""Camcorder date stamp: blocky amber "PM 3:42:07" and "JUN. 14 1998" sit in the lower right like a 90s home video.

Usage: python3 camcorder-date-stamp.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 stamp appears
DATE = "JUN. 14 1998"             # bottom line
HOUR, MINUTE, SECOND = 3, 42, 7   # clock time (PM) at START; it ticks once a second
COLOR = (255, 176, 32)            # amber text
OUTLINE = (24, 16, 8)             # hard dark edge one block wide around every letter
GLOW = 150                        # strength (0-255) of the soft dark glow that keeps it readable on bright footage
BLOCK = 3                         # each font pixel becomes a BLOCK x BLOCK square on screen (bigger = blockier)
TEXT_SIZE = 15                    # font size in font pixels, so the font is TEXT_SIZE * BLOCK pixels on screen
RIGHT, BOTTOM = 0.92, 0.92        # right edge of the text and bottom of the date line (0-1 across and down)
FONTS = ["/System/Library/Fonts/Supplemental/Andale Mono.ttf",  # 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 monospace font found: add one to FONTS")


def clock(t):
    """'PM 3:42:07' at START, one second later for each whole second after it."""
    s = HOUR * 3600 + MINUTE * 60 + SECOND + math.floor(t - START)
    return f"PM {s // 3600}:{s // 60 % 60:02d}:{s % 60:02d}"


def overlay(t):
    """Draw the stamp on a canvas BLOCK times smaller with anti-aliasing off, then blow it up pixel for pixel."""
    if t < START:
        return Image.new("RGBA", (w, h))
    small = Image.new("RGBA", (w // BLOCK, h // BLOCK))
    draw = ImageDraw.Draw(small)
    draw.fontmode = "1"
    x, y = small.width * RIGHT, small.height * BOTTOM
    for line, bottom in [(clock(t), y - round(TEXT_SIZE * 1.2)), (DATE, y)]:
        draw.text((x, bottom), line, font=font, fill=COLOR, anchor="rd", stroke_width=1, stroke_fill=OUTLINE)
    glow = Image.new("RGBA", (w, h), (0, 0, 0))
    glow.putalpha(small.getchannel("A").filter(ImageFilter.MaxFilter(3)).filter(ImageFilter.GaussianBlur(3))
                  .point(lambda a: min(GLOW, a)).resize((w, h), Image.BILINEAR))
    glow.alpha_composite(small.resize((w, h), Image.NEAREST))
    return glow


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)
font = ImageFont.truetype(FONT_FILE, TEXT_SIZE)
render(src, out)

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