---
title: "How to add a 8-bit pixel text with Claude (tested prompt and script)"
description: "Chunky yellow \"LEVEL UP\" and white \"YOUR GLOW\" in square-pixel arcade letters with a dark purple outline land one letter at a time at the top, each letter blinking on, off and on as it lands. Install one skill and ask Claude Code, or run the Python script we tested yourself."
url: https://www.recharm.com/effects/pixel-text
---

# How to add a 8-bit pixel text with Claude

Chunky yellow "LEVEL UP" and white "YOUR GLOW" in square-pixel arcade letters with a dark purple outline land one letter at a time at the top, each letter blinking on, off and on as it lands.

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 8-bit pixel text to input.mp4
   Lines: ("LEVEL UP", (255, 214, 0), 7, 0.08, 0.5), ("YOUR GLOW", (255, 255, 255), 6, 0.155, 1.4)
   ```

## 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 8-bit pixel text 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                                                                                  |
| ----------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- |
| `LINES`     | `("LEVEL UP", (255, 214, 0), 7, 0.08, 0.5), ("YOUR GLOW", (255, 255, 255), 6, 0.155, 1.4)` | Each line's text, color, block size in pixels, center (0 = top, 1 = bottom) and start second. |
| `STEP`      | `0.1`                                                                                      | Seconds between letters.                                                                      |
| `FLICKER`   | `3`                                                                                        | Frames each new letter blinks on, off, on as it lands.                                        |
| `OUTLINE`   | `(40, 12, 70)`                                                                             | Color of the outline and drop shadow.                                                         |
| `FONT_SIZE` | `10`                                                                                       | Glyph height in font pixels before scaling up; smaller looks blockier.                        |

## Without the skill

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

```
Add 8-bit pixel text to input.mp4. Two lines, each drawn with Pillow at a 10-pixel font size (Arial Black) with antialiasing off, then scaled up with nearest-neighbor so every font pixel becomes a solid square block: "LEVEL UP" in yellow (255, 214, 0) with 7-pixel blocks, centered horizontally with its middle 8% of the way down, and "YOUR GLOW" in white (255, 255, 255) with 6-pixel blocks, centered with its middle 15.5% down. Give the letters a dark purple (40, 12, 70) outline one block thick plus the same color offset one block down and right as a hard shadow. The letters land one at a time, left to right, every 0.1 seconds: "LEVEL UP" starting at 0.5 seconds and "YOUR GLOW" at 1.4 seconds. Each new letter blinks for its first 3 frames: shown, hidden, shown. Nothing is added before 0.5 seconds, the letters stay to the end, and the video behind them is untouched. Draw the text with Python and Pillow (don't rely on ffmpeg's drawtext filter), composite it with ffmpeg, keep the size, 30fps and audio, and save it as output.mp4.
```

## Run it without Claude

This is the exact script we tested. Save it as `pixel-text.py` and run:

```
python3 pixel-text.py input.mp4 output.mp4
```

```
#!/usr/bin/env python3
"""8-bit pixel text: blocky arcade letters land one at a time near the top, each flickering as it arrives.

Usage: python3 pixel-text.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

LINES = [("LEVEL UP", (255, 214, 0), 7, 0.08, 0.5),     # text, color, block size in px, center (0 = top), start second
         ("YOUR GLOW", (255, 255, 255), 6, 0.155, 1.4)]
STEP = 0.1               # seconds between letters
FLICKER = 3              # frames each new letter blinks on, off, on as it lands
OUTLINE = (40, 12, 70)   # one-block outline and drop shadow behind the letters
FONT_SIZE = 10           # glyph height in font pixels; each is scaled up to a solid square block
FONTS = ["/System/Library/Fonts/Supplemental/Arial Black.ttf",  # macOS
         "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",  # Linux
         "C:/Windows/Fonts/ariblk.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 blocks(text, shown, color, pixel):
    """The first `shown` letters of text drawn at FONT_SIZE with no smoothing, outlined, then scaled up
    so every font pixel becomes a solid square block."""
    font = ImageFont.truetype(FONT_FILE, FONT_SIZE)
    mask = Image.new("L", (math.ceil(font.getlength(text)) + 4, FONT_SIZE + 6))
    draw = ImageDraw.Draw(mask)
    draw.fontmode = "1"
    draw.text((2, 1), text[:shown], font=font, fill=255)
    edge = mask.filter(ImageFilter.MaxFilter(3))
    img = Image.new("RGBA", mask.size)
    img.paste(OUTLINE, (0, 0), edge)
    img.paste(OUTLINE, (1, 1), edge)
    img.paste(color, (0, 0), mask)
    return img.resize((mask.width * pixel, mask.height * pixel), Image.NEAREST)

def overlay(t):
    img = Image.new("RGBA", (w, h))
    for text, color, pixel, y, start in LINES:
        if t < start:
            continue
        frames, per = round((t - start) * fps), round(STEP * fps)
        n = min(frames // per + 1, len(text))  # letters landed so far
        age = frames - (n - 1) * per           # frames since the newest one landed
        shown = n - 1 if age < FLICKER and age % 2 == 1 else n
        if (text, shown) not in cache:
            cache[text, shown] = blocks(text, shown, color, pixel)
        b = cache[text, shown]
        img.alpha_composite(b, (round((w - b.width) / 2), round(h * y - b.height / 2)))
    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)
cache = {}
render(src, out)
```

## More text and titles

- [Animated text frame **Animated text frame**](https://www.recharm.com/effects/animated-text-frame)
- [Brush stroke text reveal **Brush stroke text reveal**](https://www.recharm.com/effects/brush-stroke-text-reveal)
- [Burning text **Burning text**](https://www.recharm.com/effects/burning-text)
- [Drop shadow text **Drop shadow text**](https://www.recharm.com/effects/drop-shadow-text)
- [Echo text **Echo text**](https://www.recharm.com/effects/echo-text)

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