Brotviz is a macOS terminal music visualizer written in Rust. It is built for real-time use: low-latency audio analysis, a CPU and Metal visual engine, and terminal renderers that trade speed for detail.
Current focus:
- Ghostty support
- audio-reactive fractal and geometric presets
- playlist manager in-terminal
- transition system (cuts, smooth blends, morph/remix styles)
- macOS 13+
- Rust toolchain (
cargo) - A terminal that supports the renderer you pick:
half-blockworks almost everywherebraillegives denser text-mode outputkittyuses the Kitty graphics protocol for higher fidelity
For --source system, Brotviz uses ScreenCaptureKit (no virtual loopback device required).
You must grant Screen Recording permission to your terminal app in:
System Settings -> Privacy & Security -> Screen Recording.
Install released binary (Homebrew tap, macOS Apple Silicon):
brew tap gradigit/tap
brew install brotvizRun installed binary:
brotviz --source mic --engine metal --renderer half-blockList input devices:
cargo run --bin tui_visualizer -- --list-devicesMic input, Metal engine, fast terminal-safe renderer:
cargo run --release --bin tui_visualizer -- --source mic --engine metal --renderer half-blockSystem audio (ScreenCaptureKit), Metal engine, Kitty renderer:
cargo run --release --bin tui_visualizer -- --source system --engine metal --renderer kittySystem audio + synced lyrics file + opt-in local system-data typography feed:
cargo run --release --bin tui_visualizer -- \
--source system --engine metal --renderer kitty \
--lyrics-file assets/samples/yankee_doodle_choral.lrc \
--system-data creepCPU fallback:
cargo run --release --bin tui_visualizer -- --source mic --engine cpu --renderer half-blockCreate a short promo video from promo/:
cd promo
npm install
npm run renderOutput:
promo/out/brotviz-promo.mp4
Left/Right: previous or next presetSpace: toggle auto mode1..5: switch mode (manual,beat,energy,time,adaptive)Up/Down: intensityC: cycle camera path mode,/.: camera path speed down/upS: shuffle on/offT: cycle transition mode[/]: step transition selectionZ: cycle fractal zoom modeV: fractal zoom motion on/offX/Shift+X: zoom speed up/downF: toggle calm-section fractal biasY: toggle typography on/offShift+Y: cycle typography style (line,word,glyph,matrix)L: toggle latency auto-calibration-/=: latency offset down/up (ms)0: reset manual latency offsetP: open playlist managerM: open theme selector menuO: open preset graph selector menuK: open lyrics selector menuU: open typography selector menu;: cycle system-data feed (off -> subtle -> creep)I: show/hide HUDG: stage mode toggle (persisted in prefs)?,/,H,F1, orTab: help overlayQorEsc: quit
Typography is rendered inside the visualizer frame (not only HUD text):
- Typography is currently experimental (WIP).
line: scrollingBROTVIZribbon pulsesword: beat-synced center word pulsesglyph: orbiting neon glyph swarmmatrix: reactive alphanumeric rain
Lyrics + system-data typography inputs:
--lyrics-fileinjects synced lyric lines into HUD + in-frame typography--system-data subtle|creepinjects local-only tokens (USER/HOST/CWD/home names) for psychedelic overlays- No network calls are made for these feeds; data stays local in-process
- Engine
metal: GPU shader path (macOS only) - Engine
cpu: pure CPU fallback - Renderer
half-block: best compatibility and speed - Renderer
braille: text-mode higher apparent resolution - Renderer
kitty: best color and detail, depends on terminal graphics support - Startup capability probing (
--auto-probe true) will auto-fallback:renderer kitty->half-blockif Kitty graphics capability is missingengine metal->cpuif Metal is unavailable
- Always run with
--releasefor real usage. - Tune frame rate with
--fps. - If Kitty rendering flickers or stalls in your terminal, try
--sync-updates false. - The HUD shows:
- end-to-end latency stats (
now/avg/p95) - latency calibration status (
manual/auto/effectiveoffset) - capability probe status and fallback reason
- engine, render, and total frame times
- end-to-end latency stats (
Latency calibration flags:
--latency-calibrationenables dynamic offset estimation--latency-offset-ms <f32>adds manual phase offset (also adjustable with hotkeys)
Optional runtime integration files:
--theme-pack <path>--control-matrix <path>--preset-graph <path>--lyrics-file <path>(.lrcpreferred, plain text also supported)--lyrics-loop true|false--lyrics-offset-ms <f32>--system-data off|subtle|creep(local-only tokens for typography overlays)
If parse fails, Brotviz continues and surfaces warnings in HUD/help.
Bundled samples are in:
assets/theme/assets/graph/
Included theme packs:
psychedelic-journey.theme(broad colorful journey)fractal-infinite-dive.theme(fractal-heavy set)lowlight-ambient.theme(smoother, subtler tracks)percussive-glitch-punch.theme(hard-beat/glitch emphasis)
Included preset graphs:
narrative-arc.graphfractal-descent.graphpercussive-cutup.graph
Sample audio + lyrics pair (for typography review):
assets/samples/yankee_doodle_choral.oggassets/samples/yankee_doodle_choral.lrc
Playback + visualizer review example:
afplay assets/samples/yankee_doodle_choral.ogg &
cargo run --release --bin tui_visualizer -- \
--source system --engine metal --renderer kitty \
--lyrics-file assets/samples/yankee_doodle_choral.lrc \
--lyrics-loop true \
--system-data subtleYou can load them via CLI flags or select them live in-app:
Mopens theme selectionOopens graph selectionUopens typography selection- In selector popups:
Up/Downmove,Enter/Spaceapply,Tab/Left/Rightswitch selector group.
Benchmark and latency docs:
- docs/testing.md
Generate deterministic latency fixture:
cargo run --release --bin gen_test_audioRun benchmark:
cargo run --release --bin benchmark -- --mode both --frames 120 --w 160 --h 88 --quality balancedRun offline latency report:
cargo run --release --bin latency_report -- --wav assets/test/latency_pulse_120bpm.wav --fail-over-ms 120Offline video export (WAV -> MP4 via ffmpeg):
cargo run --release --bin export_video -- \
--audio assets/test/latency_pulse_120bpm.wav \
--out out/latency_export.mp4 \
--width 1280 --height 720 --fps 60 \
--preset "Mandelbrot" \
--engine metal \
--duration 12Notes:
ffmpegmust be available in yourPATH.--engine metalfalls back to CPU automatically if Metal is unavailable.- Preset selection accepts either an index (
--preset 3) or a case-insensitive substring.
Playlists are persisted at:
$XDG_CONFIG_HOME/tui_visualizer/playlists.txt, or~/.config/tui_visualizer/playlists.txtifXDG_CONFIG_HOMEis unset.
The built-in All Presets playlist is immutable.
Stage mode preference is persisted at:
$XDG_CONFIG_HOME/tui_visualizer/prefs.txt, or~/.config/tui_visualizer/prefs.txt
- docs/USAGE.md
- docs/ARCHITECTURE.md
- docs/testing.md