---
title: "How to add a live stream overlay with Claude (tested prompt and script)"
description: "A red LIVE badge and a climbing viewer count sit top left while viewer comments pop in at the bottom and push older ones up and out. Install one skill and ask Claude Code, or run the Python script we tested yourself."
url: https://www.recharm.com/effects/live-stream-overlay
---

# How to add a live stream overlay with Claude

A red LIVE badge and a climbing viewer count sit top left while viewer comments pop in at the bottom and push older ones up and out.

Made by the script on this page, from our own test clip.

## Get this effect

1. ### Switch to Code in your [Claude Desktop App](https://claude.com/download)

2. ### Install the skill (once)

   ```
   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 live stream overlay to input.mp4
   Comments: 5 (username, message) pairs
   ```

## 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 live stream 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                                                     |
| --------------- | ----------------------------- | ---------------------------------------------------------------- |
| `COMMENTS`      | `5 (username, message) pairs` | The comments, in the order they arrive.                          |
| `START`         | `0.5`                         | Second the badge and viewer count appear.                        |
| `FIRST, GAP`    | `1.0, 0.9`                    | When the first comment arrives and the seconds between comments. |
| `SHOWN`         | `4`                           | Comments on screen at once.                                      |
| `VIEWERS, RISE` | `1248, 60`                    | Starting viewer count and how much it climbs a second.           |
| `RED`           | `(230, 30, 45)`               | LIVE badge color.                                                |

## Without the skill

Don’t want to install the skill? Paste this prompt into Claude Code and Claude writes the script itself.

```
Make input.mp4 look like a live stream. From 0.5 seconds (fading in over 0.25 seconds), put a red (230, 30, 45) pill badge reading "LIVE" in white with a white dot before it, 7.2% of the frame width tall, with its top-left corner 4% across and 3.5% down; right next to it, 2% of the width further right, a translucent black pill with a white eye icon and a viewer count that starts at 1,248 and climbs by 60 a second. Then add five comments, one every 0.9 seconds from 1.0 seconds: jess_r "is it good for oily skin?", dani.b "just ordered two", sam_lee "the glow is unreal", priya.m "link please!!", tom.w "restocked yet?". Each is a translucent black pill 11% of the frame width tall, left edge 4% across, with a colored circle avatar showing the username's first letter, the username in small light gray bold text above the message in white bold text. The newest comment slides up into place with its bottom at 90% down over 0.25 seconds and pushes the older ones up one row; keep four on screen and fade out the oldest. Use Python with Pillow to draw it and ffmpeg to put it on the video (don't rely on ffmpeg's drawtext filter), keep the audio, and save it as output.mp4.
```

## Run it without Claude

This is the exact script we tested. Save it as `live-stream-overlay.py` and run:

```
python3 live-stream-overlay.py input.mp4 output.mp4
```

```
#!/usr/bin/env python3
"""Live stream overlay: a red LIVE badge, a climbing viewer count and comments that scroll up the left side.

Usage: python3 live-stream-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, ImageFont

COMMENTS = [("jess_r", "is it good for oily skin?"),   # (username, message), one arriving every GAP seconds
            ("dani.b", "just ordered two"),
            ("sam_lee", "the glow is unreal"),
            ("priya.m", "link please!!"),
            ("tom.w", "restocked yet?")]
START = 0.5              # second the badge and viewer count appear
FIRST = 1.0              # second the first comment arrives
GAP = 0.9                # seconds between comments
SLIDE = 0.25             # seconds a comment takes to slide in
SHOWN = 4                # comments on screen at once; older ones fade out at the top
VIEWERS = 1248           # viewer count at START; it climbs by RISE a second
RISE = 60
RED = (230, 30, 45)      # LIVE badge color
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")
AVATARS = [(255, 159, 67), (72, 219, 251), (29, 209, 161), (156, 136, 255), (254, 202, 87)]

def pill(size, fill):
    img = Image.new("RGBA", size)
    ImageDraw.Draw(img).rounded_rectangle([0, 0, size[0] - 1, size[1] - 1], radius=size[1] // 2, fill=fill)
    return img

def live_badge():
    font = ImageFont.truetype(FONT_FILE, round(w * 0.042))
    bh = round(w * 0.072)
    img = pill((round(font.getlength("LIVE") + bh * 1.35), bh), RED + (255,))
    draw = ImageDraw.Draw(img)
    r = bh * 0.13
    draw.ellipse([bh * 0.42 - r, bh / 2 - r, bh * 0.42 + r, bh / 2 + r], fill="white")
    draw.text((bh * 0.72, bh / 2), "LIVE", font=font, anchor="lm", fill="white")
    return img

def viewer_pill(count):
    font = ImageFont.truetype(FONT_FILE, round(w * 0.038))
    bh = round(w * 0.072)
    text = f"{count:,}"
    img = pill((round(font.getlength(text) + bh * 1.45), bh), (0, 0, 0, 140))
    draw = ImageDraw.Draw(img)
    cx, cy = bh * 0.5, bh / 2
    draw.ellipse([cx - bh * 0.22, cy - bh * 0.13, cx + bh * 0.22, cy + bh * 0.13], outline="white", width=2)
    draw.ellipse([cx - bh * 0.07, cy - bh * 0.07, cx + bh * 0.07, cy + bh * 0.07], fill="white")
    draw.text((bh * 0.9, cy), text, font=font, anchor="lm", fill="white")
    return img

def comment(i):
    user, message = COMMENTS[i]
    name_font = ImageFont.truetype(FONT_FILE, round(w * 0.032))
    text_font = ImageFont.truetype(FONT_FILE, round(w * 0.04))
    bh = round(w * 0.11)
    width = round(bh * 1.15 + max(name_font.getlength(user), text_font.getlength(message)) + bh * 0.4)
    img = pill((width, bh), (0, 0, 0, 120))
    draw = ImageDraw.Draw(img)
    draw.ellipse([bh * 0.14, bh * 0.14, bh * 0.86, bh * 0.86], fill=AVATARS[i % len(AVATARS)])
    draw.text((bh / 2, bh / 2), user[0].upper(), font=name_font, anchor="mm", fill="white")
    draw.text((bh * 1.05, bh * 0.3), user, font=name_font, anchor="lm", fill=(205, 205, 205))
    draw.text((bh * 1.05, bh * 0.68), message, font=text_font, anchor="lm", fill="white")
    return img

def ease(p):
    p = min(max(p, 0), 1)
    return 1 - (1 - p) ** 3

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

def overlay(t):
    img = Image.new("RGBA", (w, h))
    if t < START:
        return img
    shown = ease((t - START) / SLIDE)
    x, y = round(w * 0.04), round(h * 0.035)
    img.alpha_composite(faded(badge, shown), (x, y))
    img.alpha_composite(faded(viewer_pill(VIEWERS + int((t - START) * RISE)), shown), (x + badge.width + round(w * 0.02), y))
    bottom, row = h * 0.9, bubbles[0].height * 1.18
    arrivals = [FIRST + i * GAP for i in range(len(COMMENTS))]
    for i, bubble in enumerate(bubbles):
        if t < arrivals[i]:
            continue
        pushed = sum(ease((t - a) / SLIDE) for a in arrivals[i + 1:] if t >= a)   # rows later comments pushed it up
        came_in = ease((t - arrivals[i]) / SLIDE)
        alpha = came_in * min(max(SHOWN - pushed, 0), 1)
        if alpha > 0.01:
            top = bottom - bubble.height - pushed * row + (1 - came_in) * row * 0.6
            img.alpha_composite(faded(bubble, alpha), (x, round(top)))
    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)
badge = live_badge()
bubbles = [comment(i) for i in range(len(COMMENTS))]
render(src, out)
```

## More ugc and social proof

- [Comment reply overlay **Comment reply overlay**](https://www.recharm.com/effects/comment-reply-overlay)
- [Day counter **Day counter**](https://www.recharm.com/effects/day-counter)
- [Emoji rain **Emoji rain**](https://www.recharm.com/effects/emoji-rain)
- [Floating hearts **Floating hearts**](https://www.recharm.com/effects/floating-hearts)
- [Follow button animation **Follow button animation**](https://www.recharm.com/effects/follow-button-animation)

## 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](https://www.recharm.com/get-started)
