---
name: red-pearl
description: Audio-reactive spectrum visualizer. Dark, punk, VHS-graded music video from a single audio file — no asset scraping. Built on ffmpeg's showcqt/showspectrum/showwaves with chromatic aberration, moving scanlines, strobe flashes, vignette, hue drift. Six palettes, three intensity levels, 16:9 / 9:16 / 1:1.
---


# red-pearl — Audio-Reactive Spectrum Visualizer

Pure-ffmpeg audio visualizer. No asset scraping. Takes an audio file and emits a dark, punk/VHS-graded music video driven entirely by audio-reactive filters (showcqt + showspectrum + showwaves) with heavy VHS post (chromatic aberration, film noise, moving scanlines, strobe flashes, vignette, hue drift, strong-contrast curves).

## When to use

Use when the user asks for:
- a "vibe visualizer", "spectrum visualizer", "audio visualizer"
- a visual for a track that doesn't need sourced imagery
- a "red pearl" visualizer / "pearl" viz
- dark/punk/VHS looking visual driven by the audio itself

**NOT to use:** if the user wants GIF cuts, scraped Pinterest/Giphy content, anime fight cuts, etc. That's the separate `visualizer` skill (`~/visualizer-skill/visualizer.py`). The two are distinct.

## Setup

One-time: none. Requires only `ffmpeg` (already on the Mac Studio).

The script lives at `~/red-pearl/red_pearl.py`.

## Usage

```bash
# Defaults: 16:9, red-pearl palette, medium intensity
python3 ~/red-pearl/red_pearl.py --audio ~/path/to/track.mp3

# Vertical for TikTok/Reels
python3 ~/red-pearl/red_pearl.py -a track.mp3 --aspect 9:16

# Different palette + high VHS intensity
python3 ~/red-pearl/red_pearl.py -a track.mp3 --palette void --intensity high

# Custom output path
python3 ~/red-pearl/red_pearl.py -a track.mp3 -o ~/Desktop/viz.mp4
```

### Flags

| Flag | Values | Default | Purpose |
|---|---|---|---|
| `--audio, -a` | path | (required) | Input audio (mp3/wav/flac/m4a) |
| `--output, -o` | path | `~/Documents/Visualizer/red-pearl_<stem>_<palette>_<ts>.mp4` | Output mp4 |
| `--aspect` | `16:9` `9:16` `1:1` | `16:9` | Landscape / vertical / square |
| `--palette` | `red-pearl` `blood` `void` `neon` `toxic` `sunset` | `red-pearl` | Color scheme (cqt + wave colors + strobe tint) |
| `--intensity` | `low` `medium` `high` | `medium` | VHS noise + chromatic aberration amount |
| `--crf` | 0–51 | 20 | x264 quality (lower = bigger file) |
| `--preset` | x264 presets | `medium` | Encode speed/quality |

### Palette previews

- **red-pearl** — deep blacks, hot pink/red accents, white highlights. The default "grungy dark pearl" look.
- **blood** — saturated oxblood + orange, very red-heavy.
- **void** — purple/violet into white, cosmic.
- **neon** — cyan/magenta/yellow, arcade.
- **toxic** — radioactive green, hazmat.
- **sunset** — orange/pink/gold, warm.

## Output

Default output lives in `~/Documents/Visualizer/` with a self-describing filename. Full duration of input audio. x264 / yuv420p / AAC 192k, MP4 with `+faststart` for streaming.

## Sending to Telegram

Bot credentials in the user's memory (`reference_telegram.md`):

```bash
curl -s -X POST "https://api.telegram.org/bot<TOKEN>/sendVideo" \
  -F chat_id=<CHAT_ID> \
  -F supports_streaming=true \
  -F "caption=red-pearl // <track name>" \
  -F video=@<path>
```

If the file exceeds Telegram's 50 MB bot limit, transcode first:
```bash
ffmpeg -y -i in.mp4 -c:v libx264 -preset medium -b:v 1800k -maxrate 2000k \
  -bufsize 3200k -c:a aac -b:a 128k -pix_fmt yuv420p -movflags +faststart out.mp4
```

## How it works (filter chain)

1. **showcqt** — main spectrum bars, 6-count, gamma-stretched, palette-colored
2. **showspectrum** — scrolling log-scale spectrogram, blended at 35% alpha over cqt
3. **showwaves** — cline-mode waveform band along the bottom (H - waveform_h - 20)
4. **rgbashift** — chromatic aberration (R/B channel offset, intensity-scaled)
5. **noise** — temporal + uniform film grain
6. **vignette** — dark corners
7. **drawbox** x2 — two time-sinusoidal moving scanlines (white + palette strobe color)
8. **drawbox** x2 — periodic strobe flashes (black at ~0.2Hz, palette color at ~0.14Hz)
9. **curves** strong_contrast — final crush
10. **hue** — slow hue modulation `s = 1.3 + 0.4*sin(t*1.3)`

All audio-reactive stages are fps=30; video framerate is 30.

## Notes

- `drawtext` is NOT used (the system `ffmpeg` build lacks it). If you add text overlays later, generate PNG title cards with PIL and `overlay` them instead.
- `zoompan` with a `t`-variable expression breaks — ffmpeg zoompan uses `on`/`in_time`, not `t`. Stick to static zoom or drive with `scale` + `sin(t*X)` in separate filter.
- Drawbox sizes must be literal ints, not `w=w`/`h=h` expressions.
