How to add a press logo strip with Claude

A dark band fades in across the bottom with "AS SEEN IN" between two thin lines, then three white magazine wordmarks rise into a row under it one after another.

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 press logo strip to input.mp4
    Header: AS SEEN IN
    Logos: GLOSSE, Beauty Wire, THE GLOW
    Logo files: None

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 press logo strip 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
HEADERAS SEEN INThe line above the logos.
LOGOSGLOSSE, Beauty Wire, THE GLOWPlaceholder wordmarks and their font styles, left to right.
LOGO_FILESNoneYour outlets' logo PNGs (white on transparent) in place of the placeholders.
START0.5Second the band and header fade in.
LOGO_START0.8Second the first logo starts to rise in.
GAP0.3Seconds between logos.
Y0.87Where the band's center sits (0 = top, 1 = bottom).
BAND(12, 12, 18, 190)Band color and opacity.

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 an "as seen in" press strip to input.mp4. Draw it with Python and Pillow (don't rely on ffmpeg's drawtext filter) and overlay it with ffmpeg. A full-width near-black (12, 12, 18) band at 75% opacity, 30% of the frame width tall, with its center 87% of the way down the frame, fades in from 0.5 to 0.8 seconds. On it, 22% of the band's height from its top, the words "A S S E E N  I N" (letter-spaced bold sans capitals 3.2% of the frame width tall, white at 86% opacity) are centered, with a thin white line at 55% opacity on each side running out to 12% and 88% across, leaving a gap of 3% of the frame width next to the words. Under them, centered 62% of the band's height from its top, sit three white placeholder wordmarks, each at most 27% of the frame width wide, centered at 19%, 50% and 81% across: "G L O S S E" in letter-spaced bold serif capitals, "Beauty Wire" in bold italic serif and "THE GLOW" in a heavy black sans, all drawn about 7.5% of the frame width tall. Each wordmark fades in and rises 3% of the frame width into place over 0.4 seconds with an ease-out, starting at 0.8, 1.1 and 1.4 seconds. Everything stays on to the end and the rest of the frame is untouched. Keep the audio and save it as output.mp4.

Run it without Claude

This is the exact script we tested. Save it as press-logo-strip.py and run:

python3 press-logo-strip.py input.mp4 output.mp4
Show the script
#!/usr/bin/env python3
"""Press logo strip: an "AS SEEN IN" line on a dark band, then three publication wordmarks fade up one by one.

Usage: python3 press-logo-strip.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, ImageFont

HEADER = "AS SEEN IN"
LOGOS = [("GLOSSE", "serif"),             # (wordmark, font style), left to right; placeholders:
         ("Beauty Wire", "italic"),       # swap in the outlets that covered you, or set LOGO_FILES
         ("THE GLOW", "heavy")]
LOGO_FILES = None         # your logo PNGs (white on transparent) in place of LOGOS, e.g. ["a.png", "b.png", "c.png"]
START = 0.5               # second the band and header fade in
FADE = 0.3                # seconds the band's fade takes
LOGO_START = 0.8          # second the first logo starts to rise in
GAP = 0.3                 # seconds between logos
RISE = 0.4                # seconds each logo's fade and rise takes
Y = 0.87                  # where the band's center sits (0 = top, 1 = bottom)
BAND = (12, 12, 18, 190)  # band color and opacity (0-255)
FONTS = {"serif": ["/System/Library/Fonts/Supplemental/Georgia Bold.ttf",                # macOS
                   "/usr/share/fonts/truetype/dejavu/DejaVuSerif-Bold.ttf",              # Linux
                   "C:/Windows/Fonts/georgiab.ttf"],                                     # Windows
         "italic": ["/System/Library/Fonts/Supplemental/Georgia Bold Italic.ttf",
                    "/usr/share/fonts/truetype/dejavu/DejaVuSerif-BoldItalic.ttf",
                    "C:/Windows/Fonts/georgiaz.ttf"],
         "heavy": ["/System/Library/Fonts/Supplemental/Arial Black.ttf",
                   "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
                   "C:/Windows/Fonts/ariblk.ttf"],
         "label": ["/System/Library/Fonts/Supplemental/Arial Bold.ttf",
                   "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
                   "C:/Windows/Fonts/arialbd.ttf"]}
FONT_FILES = {k: next((f for f in v if Path(f).exists()), None) or sys.exit(f"No {k} font found: add one to FONTS")
              for k, v in FONTS.items()}


def band():
    """The dark band with the header between two thin rules, full frame size."""
    img = Image.new("RGBA", (w, h))
    draw = ImageDraw.Draw(img)
    bh = round(w * 0.30)
    top = round(h * Y - bh / 2)
    draw.rectangle([0, top, w, top + bh], fill=BAND)
    font = ImageFont.truetype(FONT_FILES["label"], round(w * 0.032))
    label = " ".join(HEADER)  # letter-spaced
    cy = top + bh * 0.22
    draw.text((w / 2, cy), label, font=font, anchor="mm", fill=(255, 255, 255, 220))
    half = draw.textlength(label, font=font) / 2 + w * 0.03
    for x0, x1 in ((w * 0.12, w / 2 - half), (w / 2 + half, w * 0.88)):
        draw.line([x0, cy, x1, cy], fill=(255, 255, 255, 140), width=max(1, w // 400))
    return img, top + bh * 0.62


def wordmark(name, style):
    """A white wordmark no wider than 27% of the frame, trimmed to its ink."""
    size = round(w * 0.075)
    font = ImageFont.truetype(FONT_FILES[style], size)
    text = " ".join(name) if style == "serif" else name  # the serif one is letter-spaced like a masthead
    img = Image.new("RGBA", (size * len(text), size * 2))
    ImageDraw.Draw(img).text((0, size / 2), text, font=font, fill="white")
    img = img.crop(img.getbbox())
    scale = min(1, w * 0.27 / img.width)
    return img.resize((round(img.width * scale), round(img.height * scale)), Image.LANCZOS)


def faded(img, a):
    out = img.copy()
    out.putalpha(img.getchannel("A").point(lambda v: round(v * a)))
    return out


def overlay(t):
    img = Image.new("RGBA", (w, h))
    a = min(max((t - START) / FADE, 0), 1)
    if a > 0:
        img.alpha_composite(faded(strip, a))
    for i, logo in enumerate(logos):
        p = min(max((t - LOGO_START - i * GAP) / RISE, 0), 1)
        if p > 0:
            ease = 1 - (1 - p) ** 3
            x = w * (0.5 + (i - (len(logos) - 1) / 2) * 0.31) - logo.width / 2
            y = logo_y - logo.height / 2 + (1 - ease) * w * 0.03
            img.alpha_composite(faded(logo, ease), (round(x), round(y)))
    return img


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)
strip, logo_y = band()
if LOGO_FILES:
    logos = [Image.open(f).convert("RGBA") for f in LOGO_FILES]
    logos = [im.resize((round(w * 0.27), round(w * 0.27 * im.height / im.width)), Image.LANCZOS) for im in logos]
else:
    logos = [wordmark(name, style) for name, style in LOGOS]
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