projectm-termgl is a small terminal visualizer prototype. It renders libprojectM frames into a hidden OpenGL context, downsamples them on the GPU, and displays the result in a terminal through TermGL.
./
├── flake.nix # Nix build and development shell
├── presets/ # Local Milkdrop presets (preferred when present)
├── src/
│ ├── audio/ # PCM capture / synthetic fallback audio
│ ├── gl/ # Off-screen OpenGL rendering and readback
│ ├── input/ # Terminal keyboard input handling
│ ├── projectm/ # projectM setup helpers
│ └── term/ # TermGL output path
└── README.md
nix develop
nix build
./result/bin/projectm-termglThe flake exports a development shell with the compiler and runtime dependencies, and builds a single binary named projectm-termgl.
Preset discovery works in this order:
./presetsif that directory exists in the repository root.PROJECTM_PRESET_PATHif the environment variable is set../presetsagain as the final fallback.
Inside the Nix shell and wrapped build output, PROJECTM_PRESET_PATH is set to the preset directory from the projectm package. If you want to use a different preset collection, either replace ./presets or override PROJECTM_PRESET_PATH.
The build enables both Wayland and X11 through GLFW.
- If only
WAYLAND_DISPLAYis set, the app hints GLFW to use Wayland. - If only
DISPLAYis set, the app hints GLFW to use X11. - If both are present, GLFW is left on automatic selection.
You can force the backend manually:
PROJECTM_GLFW_PLATFORM=x11 ./result/bin/projectm-termgl
PROJECTM_GLFW_PLATFORM=wayland ./result/bin/projectm-termglqorEsc: quitnorRight Arrow: next presetporLeft Arrow: previous presetr: random presetm: mute or unmute audio input
By default, the program does not capture live system audio. Instead, it feeds synthetic PCM into projectM so the visualizer keeps moving even without an audio source.
To enable PulseAudio capture:
export PROJECTM_AUDIO=1
./result/bin/projectm-termglWhen capture is enabled, the program first tries to record from the monitor source of the current default sink. You can override the source explicitly:
export PROJECTM_PULSE_SOURCE='alsa_output.pci-0000_00_1f.3.analog-stereo.monitor'
./result/bin/projectm-termglIf PulseAudio capture cannot be opened, the program falls back to synthetic audio.
- Renders projectM at
320x240in an off-screen OpenGL framebuffer. - Downscales the frame before terminal output.
- Uses half-block terminal rendering with a one-line status bar when the terminal has more than one row.
- Shows the active preset name, audio source label, signal meter, peak level, and dirty cell count in the status line.
