A pixel-art terminal music player daemon built for long coding sessions.
┌ PIXELBEAT ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ──┐
│ ◉ ──────────────●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ○ ▶ 2:47/4:12 │
│ 🎵 Sleepy Fish - A Rainy Night in Kyoto ▅▂█▄▇▁▃▆▂▅▃▇ │
│ ⏮ ⏸ ⏭ │
└────────────────────────────────────────────────────────────────────────┘
pixelbeat runs as a background daemon and exposes a tiny CLI (px) for playback control. It streams YouTube playlists via mpv, plays local audio files through rodio, and ships with built-in chillhop and lofi radio stations. The animated cassette tape UI and spectrum visualizer plug directly into Claude Code's status line, tmux, or starship.
- Daemon architecture -- Start once, control from anywhere via Unix socket IPC
- YouTube streaming -- Play any YouTube video or playlist instantly through mpv (no download step)
- Local file playback -- MP3, FLAC, WAV, OGG, M4A, AAC, Opus, AIFF via rodio/symphonia
- Built-in radio -- Chillhop and lofi stations with curated track lists, ready out of the box
- Cassette tape UI -- Animated reel-to-reel visualization with playhead tracking
- Spectrum visualizer -- 32-bar beat-synced spectrum analyzer with Anthropic orange gradient
- TUI mode -- Full-screen terminal interface built with ratatui
- Status bar integration -- Plug into Claude Code, tmux, or starship with one command
- Format template engine -- Compose your own status line with tokens like
{tape:30},{spectrum:16},{cassette:70} - Shuffle and repeat -- Persistent mode toggles across sessions via config file
- Clickable controls -- OSC 8 hyperlink buttons (prev/toggle/next/repeat/shuffle) in supported terminals
Prerequisites: Rust toolchain, mpv and yt-dlp (for YouTube).
# Install dependencies (macOS)
brew install mpv yt-dlp
# Clone and build
git clone https://github.com/Dylanwooo/pixelbeat.git
cd pixelbeat
cargo build --release
# Add to PATH
cp target/release/px ~/.local/bin/ # or anywhere on your PATH
# Start the daemon and play a YouTube playlist
px daemon &
px yt "https://www.youtube.com/watch?v=jfKfPfyJRdk"You should hear music within a few seconds. Run px tui to open the full-screen player, or px status to see the cassette deck in your terminal.
git clone https://github.com/Dylanwooo/pixelbeat.git
cd pixelbeat
cargo install --path .This installs the px binary to ~/.cargo/bin/. Make sure that directory is in your PATH.
| Dependency | Required | Purpose | Install |
|---|---|---|---|
| Rust (2021 edition) | Yes | Build toolchain | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh |
| mpv | For YouTube | Audio streaming backend | brew install mpv |
| yt-dlp | For YouTube | Playlist resolution and audio extraction | brew install yt-dlp |
Local file playback and built-in radio work without mpv or yt-dlp.
The daemon must be running before you can send any playback commands.
# Start the daemon (blocks the terminal)
px daemon
# Start and immediately play a directory
px daemon --play ~/Music
# Start in the background
px daemon &# Play a single file
px play ~/Music/song.mp3
# Play all supported files in a directory
px play ~/Music/chillhop/
# Resume playback (if paused)
px playSupported formats: MP3, FLAC, WAV, OGG, M4A, AAC, Opus, AIFF.
Stream any YouTube video or playlist. Audio plays instantly via mpv -- nothing is downloaded to disk.
# Play a single video
px yt "https://www.youtube.com/watch?v=jfKfPfyJRdk"
# Play a playlist
px yt "https://www.youtube.com/playlist?list=PLOzDu-MXXLliO9fBNZOQTBDddoA3FzZUo"# List available stations
px radio
# Play a station
px radio chillhop
px radio lofiStations: chillhop (30 curated tracks from Chillhop Music), lofi (15 tracks from the Lofi Girl archive).
px toggle # Play/pause toggle
px pause # Pause
px next # Next track
px prev # Previous track
px stop # Stop playback
px vol 0.5 # Set volume (0.0 to 1.0)
px shuffle # Toggle shuffle mode
px repeat # Toggle repeat modeOpen a full-screen terminal UI with spectrum visualizer, progress bar, and keyboard controls.
px tuiTUI keybindings:
| Key | Action |
|---|---|
Space |
Play / pause |
n or Right |
Next track |
p or Left |
Previous track |
+ or Up |
Volume up |
- or Down |
Volume down |
s |
Toggle shuffle |
r |
Toggle repeat |
q or Esc |
Quit TUI |
Query the current player state, formatted however you want.
# Default: renders the full cassette deck widget
px status
# Custom format string
px status --format "{icon} {title:.25} {bar:12} {elapsed}/{duration}"
# Spectrum only
px status --format "{spectrum:32}"
# Cassette tape with custom width
px status --format "{tape:40}"px quitRun the setup wizard:
px setup claude-codeOr manually add this to ~/.claude/statusline.sh:
# pixelbeat music player status
if command -v px &>/dev/null; then
PX_STATUS=$(px status --format "♪ {title:.25} {icon} {bar:12} {elapsed}/{duration}" 2>/dev/null)
if [ -n "$PX_STATUS" ]; then
echo "$PX_STATUS"
echo "$(px status --format " {spectrum:32}" 2>/dev/null)"
fi
fiA ready-to-source script is also available at integrations/claude-code.sh.
Run px setup tmux, or add to ~/.tmux.conf:
set -g status-right '#(px status --format "{icon} {title:.20} {bar:8} {elapsed}" 2>/dev/null)'
set -g status-interval 1Then reload: tmux source-file ~/.tmux.conf
Run px setup starship, or add to ~/.config/starship.toml:
[custom.music]
command = "px status --format '{icon} {title:.15} {elapsed}'"
when = "px status"
format = "[$output]($style) "
style = "bold #E3893E"Use these tokens in px status --format "..." to build custom status lines.
| Token | Description | Example Output |
|---|---|---|
{title} |
Track title (full) | Sleepy Fish - A Rainy Night in Kyoto |
{title:.N} |
Track title, truncated to N chars | Sleepy Fish - A Rain… |
{icon} |
Play/pause icon | ▶ or ⏸ |
{bar:N} |
Progress bar, N chars wide | ████░░░░░░ |
{tape:N} |
Cassette tape reel visualization, N chars wide | ◉ ──────●━━━━━━━ ◎ |
{spectrum:N} |
Animated spectrum bars, N bars wide | ▅▂█▄▇▁▃▆▂▅▃▇▁▄▆▂ |
{cassette:N} |
Full cassette deck widget (multi-line), N chars wide | (see above) |
{elapsed} |
Elapsed time | 2:47 |
{duration} |
Total duration | 4:12 |
{vol} |
Volume percentage | 80% |
{vol:bar:N} |
Volume as a bar, N chars wide | ████░ |
{index} |
Current track number (1-based) | 3 |
{count} |
Total track count | 12 |
{shuffle} |
Shuffle indicator (bright when on) | 🔀 |
{repeat} |
Repeat indicator (bright when on) | 🔁 |
{modes} |
Combined repeat + shuffle indicators | 🔁 🔀 |
{controls} |
Text-based control legend | ⏮ prev ⏯ toggle ⏭ next 🔁 loop |
{buttons} |
Clickable OSC 8 hyperlink buttons | ⏮ ⏸ ⏭ 🔁 🔀 |
All tokens render with Anthropic orange ANSI color codes (#E3893E primary, with bright/dim/background variants).
pixelbeat reads its config from ~/.config/pixelbeat/config.toml. Every field is optional -- sensible defaults are used when omitted.
# Default source on daemon startup: "local", "chillhop", "lofi", "youtube"
source = "local"
# YouTube playlist URL (used when source = "youtube")
youtube_url = "https://www.youtube.com/watch?v=jfKfPfyJRdk"
# Local music directory (used when source = "local")
music_dir = "~/Music/pixelbeat"
# Default volume (0.0 - 1.0)
volume = 0.8
# Auto-repeat / loop
repeat = false
# Shuffle mode
shuffle = false| Key | Type | Default | Description |
|---|---|---|---|
source |
string |
(none) | Auto-play source on startup. One of "local", "chillhop", "lofi", "youtube". If omitted, the daemon loads music_dir when it exists. |
youtube_url |
string |
(none) | YouTube video or playlist URL. Only used when source = "youtube". |
music_dir |
string |
"~/Music/pixelbeat" |
Directory to scan for local audio files. Tilde expansion is supported. |
volume |
float |
0.8 |
Initial volume level, from 0.0 (mute) to 1.0 (max). |
repeat |
bool |
false |
Loop the playlist when it reaches the end. Radio mode forces this on. |
shuffle |
bool |
false |
Randomize track order. Re-shuffles on each loop when repeat is also enabled. |
┌─────────┐ Unix socket IPC ┌────────────────────┐
│ px CLI │ ──────────────────── │ px daemon │
│ │ JSON commands │ │
│ px tui │ ◄────────────────── │ ┌──────────────┐ │
└─────────┘ JSON responses │ │ Player │ │
│ │ - rodio │ │ Local files
│ │ - mpv IPC │──│──────────────
│ └──────────────┘ │
│ ┌──────────────┐ │ YouTube
│ │ mpv process │──│──────────────
│ └──────────────┘ │ (yt-dlp)
│ ┌──────────────┐ │
│ │ Spectrum │ │ Radio streams
│ │ Analyzer │──│──────────────
│ └──────────────┘ │ (HTTP)
└────────────────────┘
Daemon (px daemon) -- Long-running process that owns the audio output. Listens on a Unix socket at $XDG_RUNTIME_DIR/pixelbeat.sock (falls back to /tmp/pixelbeat.sock). Ticks at 50ms intervals to update playback position, detect track endings, and generate spectrum data.
CLI (px <command>) -- Thin client that serializes commands as JSON, sends them over the Unix socket, and prints the response. Each invocation connects, sends one command, reads one response, and exits.
TUI (px tui) -- Full-screen ratatui interface that polls the daemon for state every 100ms and renders a live spectrum visualizer. All input is translated to the same IPC commands the CLI uses.
Player engine -- Local files are decoded by rodio (via symphonia). YouTube audio is streamed through an mpv subprocess controlled via mpv's JSON IPC protocol. The player transparently switches between rodio and mpv depending on the source.
Spectrum analyzer -- Generates 32-bar beat-synced animation data at ~20 FPS. Uses deterministic pseudo-random waves with contrast boosting and spike injection for a punchy, reactive look. An FFT-based real PCM analysis path is implemented for future use.
Contributions are welcome. Here is how to get started:
- Fork the repository and clone your fork.
- Create a feature branch:
git checkout -b my-feature. - Make your changes. Run
cargo fmtandcargo clippybefore committing. - Test locally: start the daemon with
cargo run -- daemon, then exercise your changes with the CLI. - Open a pull request against
main.
If you find a bug or have a feature idea, please open an issue first so we can discuss it.
MIT -- see LICENSE for details.
Copyright (c) 2026 Dylan Woo