---
title: "How to add a low stock alert with Claude (tested prompt and script)"
description: "A white card slides up under the product reading \"Only 5 left in stock\" in red, then the count ticks down to 3 as its red stock bar drains. Install one skill and ask Claude Code, or run the Python script we tested yourself."
url: https://www.recharm.com/effects/low-stock-alert
---

# How to add a low stock alert with Claude

A white card slides up under the product reading "Only 5 left in stock" in red, then the count ticks down to 3 as its red stock bar drains.

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 low stock alert to input.mp4
   Seconds and units left: the card appears at the first, then counts down: [(0.5, 5), (1.8, 4), (2.8, 3)]
   Stock the full bar stands for: 10
   ```

## 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 low stock alert 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                                                             |
| -------- | -------------------------------- | ------------------------------------------------------------------------ |
| `COUNTS` | `[(0.5, 5), (1.8, 4), (2.8, 3)]` | Seconds and units left: the card appears at the first, then counts down. |
| `TOTAL`  | `10`                             | Stock the full bar stands for.                                           |
| `SLIDE`  | `0.35`                           | Seconds the card takes to slide up.                                      |
| `DRAIN`  | `0.4`                            | Seconds the bar takes to drop to each new level.                         |
| `CARD`   | `(0.08, 0.74, 0.92, 0.88)`       | Card box as left, top, right, bottom (0-1 of the frame).                 |
| `RED`    | `(220, 38, 38)`                  | Text, dot and bar color.                                                 |
| `TRACK`  | `(229, 231, 235)`                | Color of the empty part of the bar.                                      |

## Without the skill

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

```
Add a low stock alert to input.mp4. At 0.5 seconds a white rounded card slides up 6% of the frame height into place over 0.35 seconds while fading in, filling the box from 8% to 92% across and 74% to 88% down. On it, in bold red (220, 38, 38) text 25% of the card's height, left-aligned 7% of the card's width in from its left edge after a small pulsing red dot, it reads "Only 5 left in stock", centered 36% down the card. Below, from 64% to 74% down the card and inset 7% of the card's width on each side, a rounded stock bar with a light gray (229, 231, 235) track and a red (220, 38, 38) fill showing units left out of 10, so 50% full. At 1.8 seconds the text changes to "Only 4 left in stock" and the fill eases down to 40% over 0.4 seconds; at 2.8 seconds it changes to "Only 3 left in stock" and eases down to 30%, then stays. 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 `low-stock-alert.py` and run:

```
python3 low-stock-alert.py input.mp4 output.mp4
```

```
#!/usr/bin/env python3
"""Low stock alert: a white card slides up with a red "Only 5 left in stock" line and a stock bar that drains as the count drops to 3.

Usage: python3 low-stock-alert.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

COUNTS = [(0.5, 5), (1.8, 4), (2.8, 3)]   # (second, units left): the card appears at the first, then counts down
TOTAL = 10                # stock the full bar stands for
SLIDE = 0.35              # seconds the card takes to slide up
DRAIN = 0.4               # seconds the bar takes to drop to each new level
CARD = (0.08, 0.74, 0.92, 0.88)   # card box (left, top, right, bottom as 0-1 of the frame)
RED = (220, 38, 38)       # text, dot and bar color
TRACK = (229, 231, 235)   # the empty part of the bar
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 ease_out(p):
    p = min(max(p, 0), 1)
    return 1 - (1 - p) ** 3

def stock(t):
    """Units shown at t, and the bar's fill (0-1), easing from the previous level to the current one."""
    shown, fill = COUNTS[0][1], COUNTS[0][1] / TOTAL
    for start, units in COUNTS[1:]:
        if t >= start:
            fill = (shown + (units - shown) * ease_out((t - start) / DRAIN)) / TOTAL
            shown = units
    return shown, fill

def card(units, fill, t):
    x0, y0, x1, y1 = (round(v * s) for v, s in zip(CARD, (w, h, w, h)))
    cw, ch = x1 - x0, y1 - y0
    img = Image.new("RGBA", (cw, ch))
    draw = ImageDraw.Draw(img)
    draw.rounded_rectangle([0, 0, cw - 1, ch - 1], radius=ch // 5, fill="white")
    pad = round(cw * 0.07)
    # pulsing dot, then the line of text
    r = ch * (0.065 + 0.015 * math.sin(t * 2 * math.pi * 1.5))
    cy = ch * 0.36
    draw.ellipse([pad + ch * 0.08 - r, cy - r, pad + ch * 0.08 + r, cy + r], fill=RED)
    font = ImageFont.truetype(FONT_FILE, round(ch * 0.25))
    draw.text((pad + ch * 0.22, cy), f"Only {units} left in stock", font=font, anchor="lm", fill=RED)
    # stock bar
    bx0, bx1, by0, by1 = pad, cw - pad, round(ch * 0.64), round(ch * 0.74)
    draw.rounded_rectangle([bx0, by0, bx1, by1], radius=(by1 - by0) // 2, fill=TRACK)
    end = bx0 + round((bx1 - bx0) * fill)
    draw.rounded_rectangle([bx0, by0, max(end, bx0 + by1 - by0), by1], radius=(by1 - by0) // 2, fill=RED)
    return img, x0, y0

def overlay(t):
    img = Image.new("RGBA", (w, h))
    p = ease_out((t - COUNTS[0][0]) / SLIDE)
    if p <= 0:
        return img
    piece, x, y = card(*stock(t), t)
    piece.putalpha(piece.getchannel("A").point(lambda a: round(a * p)))
    img.alpha_composite(piece, (x, y + round((1 - p) * h * 0.06)))
    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)
render(src, out)
```

## More product shots

- [Animated feature callouts **Animated feature callouts**](https://www.recharm.com/effects/animated-feature-callouts)
- [Before/after slider **Before/after slider**](https://www.recharm.com/effects/before-after-slider)
- [Best seller badge **Best seller badge**](https://www.recharm.com/effects/best-seller-badge)
- [Callout arrows and circles **Callout arrows and circles**](https://www.recharm.com/effects/callout-arrows-and-circles)
- [Carousel swipe **Carousel swipe**](https://www.recharm.com/effects/carousel-swipe)

## 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)
