SoundVisualizer
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 6 GitHub stars
Code Fail
- new Function() — Dynamic code execution via Function constructor in .github/workflows/test.yml
- fs module — File system access in .github/workflows/test.yml
- child_process — Shell command execution capability in scripts/after-pack.js
- spawnSync — Synchronous process spawning in scripts/after-pack.js
- fs module — File system access in scripts/after-pack.js
- child_process — Shell command execution capability in scripts/check-runtime.js
- spawnSync — Synchronous process spawning in scripts/check-runtime.js
- process.env — Environment variable access in scripts/check-runtime.js
- fs module — File system access in scripts/check-runtime.js
- fs module — File system access in scripts/gen-icons.js
- child_process — Shell command execution capability in scripts/milkdrop-compile-rate.js
- process.env — Environment variable access in scripts/milkdrop-compile-rate.js
- fs module — File system access in scripts/milkdrop-compile-rate.js
- fs module — File system access in scripts/milkdrop-corpus.js
- child_process — Shell command execution capability in scripts/milkdrop-render-rate.js
- process.env — Environment variable access in scripts/milkdrop-render-rate.js
- fs module — File system access in scripts/milkdrop-render-rate.js
- child_process — Shell command execution capability in scripts/milkdrop-switch-cost.js
- spawnSync — Synchronous process spawning in scripts/milkdrop-switch-cost.js
- fs.rmSync — Destructive file system operation in scripts/milkdrop-switch-cost.js
- process.env — Environment variable access in scripts/milkdrop-switch-cost.js
- fs module — File system access in scripts/milkdrop-switch-cost.js
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Free, open-source music visualizer & VJ software for Windows, macOS and Linux. Real MilkDrop engine, 59 audio-reactive modes, layers and 40 GPU effects, OBS overlay, Spout/Syphon, projection mapping, RGB lighting (Dynamic Lighting, OpenRGB, Art-Net), timeline & clip deck, and MCP control for AI agents.
CAYADEV Visualizer
Free, open-source music visualizer and VJ software for every screen you own
Turn whatever your computer is playing — Spotify, YouTube, a DAW, a DJ set, a game — into
audio-reactive visuals on one display or ten. A real MilkDrop engine, 59 visualizer modes,
layers and 40 GPU effects, an OBS overlay, Spout / Syphon, projection mapping,
RGB lighting, a timeline and clip deck for live shows, and AI control over MCP.
Windows · macOS · Linux — no account, no telemetry, MIT licensed.
Run from source ·
Features ·
FAQ ·
Türkçe
At a glance
| 59 visualizer modes | 43 backgrounds | 40 GPU effects | 18 scene transitions |
|---|---|---|---|
| 72 ready-made scenes | 98 formulas + 13 3D solids | 42 built-in GLSL shaders | 58 colour palettes |
| 10,347 MilkDrop presets tested | 96 MCP tools for AI agents | 17 layer blend modes | 2 languages (EN / TR) |
About the version labels. The current release is v3.1.4. Everything on this page is in
the source onmain; items marked 3.1.5 ship with the next release, v3.1.5, and are
not in the v3.1.4 download yet. Run from source to use them today.
Why CAYADEV Visualizer
- No Stereo Mix, no virtual cable on Windows. System audio is captured straight from your
speakers or headphones (WASAPI loopback), alongside microphones and line inputs — or from one
application only, so the visuals follow Spotify and ignore the game and the voice chat.
→ Audio - Every screen, one engine. Full-screen windows on every display you pick, a transparent
OBS browser source, Spout / Syphon for Resolume, TouchDesigner and MadMapper, and a
phone remote — all drawing the same picture. → Outputs - MilkDrop that really runs your presets. Per-frame and per-pixel equations, the warp mesh,
HLSL shaders translated to GLSL, measured against 10,347 real presets and frame by frame
against a reference MilkDrop 2 renderer. Import whole libraries, browse them as thumbnails, edit presets live,
or generate new ones 3.1.5. → MilkDrop - A compositor, not a single effect. Unlimited layers, 17 blend modes, masks, an A/B
crossfader, 40 GPU effects per layer or on the whole frame, and a modulation matrix that routes
LFOs, envelopes and live audio analysis to any setting. → Layers - Built for live shows. A timeline with automation lanes, a clip deck with beat-quantised
launching, Auto VJ that changes scenes on the bar, tap tempo, MIDI and OSC.
→ Show control - Ready for the stage. Projection mapping with corner pin, mesh warp and soft-edge blending
for multi-projector rigs, plus aspect correction for LED walls whose pixels are not square.
→ Stage - Your lights follow the music. Windows Dynamic Lighting, OpenRGB on every platform and
Art-Net / DMX, all fed by one renderer — they can even take their colours from the MilkDrop
picture 3.1.5. → Lighting - For creators. Frame-exact offline video export from an audio file, one-key recording,
music-video layouts, a Now Playing overlay with album art, and synced lyrics (LRC / SRT).
→ Export - AI-ready. A local MCP server with 96 tools lets Claude, Codex, Cursor and other agents
read the show, build scenes and run the outputs — behind five permission levels, on127.0.0.1
only 3.1.5. → MCP - Private and offline. No account, no telemetry, no cloud. The only call the application
makes on its own is GitHub's latest-release check, and you can switch it off.
→ Privacy
Gallery
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
| Hyper Tunnel | 3D attractor |
|---|---|
![]() |
![]() |
| Drum & Bass | MilkDrop feedback |
![]() |
![]() |
Classic looks
The spectrum bars, waves and rings the application started with — still one click away, on
fluid gradient backgrounds that move with the music.
| Layered scene | Frequency bars | Circular |
|---|---|---|
![]() |
![]() |
![]() |
| Mirrored bars | Wave | Sunset wave |
![]() |
![]() |
![]() |
Every scene image and clip on this page is rendered by the application itself with
npm start -- --shots, driven by a synthetic 120 BPM signal. With real audio the visuals follow
the music instead.
Quick start
Download
Get the latest build from Releases.
| Platform | File | Notes |
|---|---|---|
| Windows 10 / 11 | …-windows-setup.exe |
Recommended. Registers the Dynamic Lighting identity so lights keep running in the background, and can update itself. |
| Windows, portable | …-windows-portable.exe |
No installation. Dynamic Lighting works only while the app is focused. |
| macOS (Apple Silicon) | …-macos-arm64.dmg / .zip |
Unsigned — see macOS first launch. System audio needs a virtual device such as BlackHole. |
| Linux (x64) | …-linux-x86_64.AppImage / …-linux-amd64.deb |
Needs PulseAudio or PipeWire. The AppImage can update itself 3.1.5. |
Nothing else needs to be installed: the audio helper runs on the application's own binary.
First run
- Pick one or several displays from the Displays menu at the top, then one or more
audio sources under Audio. - Click Open Visualizer. The visual opens full-screen on every selected display.
- Change anything on the right — it applies immediately and saves itself.
- Or start from a finished look: Library → Templates has 72 of them.
- For streaming, turn on Output → Streaming Output and paste the address into an OBS
Browser Source. - Press ESC on any visualization window to close them all.
Run from source
You need Node.js 20 or newer (CI tests 20 and 22) and Git.
git clone https://github.com/CaYatur/SoundVisualizer.git
cd SoundVisualizer
npm install
npm start
npm install rebuilds the native audify audio module for Electron automatically (postinstall).
If the audio helper reports INVALID_HELPER_OUTPUT, run npm run rebuild:audio, thennpm run check:runtime. Behind a corporate proxy that breaks certificates, setNODE_OPTIONS=--use-system-ca before npm install. Developer mode with DevTools: npm run dev.
Who it is for
| You are… | What you get |
|---|---|
| A streamer | A transparent overlay for OBS as a browser source, a Now Playing card with album art, lyrics, and a phone remote to change scenes mid-stream. Runs on one PC while OBS runs on another. |
| A VJ or live performer | A timeline, a clip deck with beat-quantised launching, Auto VJ on the bar, MIDI and OSC control, blackout, Spout/Syphon into Resolume or TouchDesigner, and full-screen output on every projector. |
| A music producer or label | Frame-exact video export from your track, eight restrained music-video layouts with your logo and the track title, and a recorder for the live output. |
| A venue, event or installation | Projection mapping, edge blending, aspect correction for LED walls, accidental-close protection, crash recovery, and a display that never goes to sleep mid-show. |
| An RGB or ambient lighting fan | Windows Dynamic Lighting, OpenRGB and Art-Net/DMX driven by the music, with a screen-saver-style template group for background visuals. |
| A MilkDrop fan | A MilkDrop engine that loads .milk and .milk2, imports whole libraries, shows thumbnails, keeps favourites, ratings and tags, and lets you edit or generate presets. |
| A developer or AI tinkerer | A GLSL editor with Shadertoy and ISF import, an MCP server with 96 tools, a documented config, and 2,700+ tests that check answers rather than lines. |
Features in detail
The sections above are the short version. Everything below is the full list, by category.
- Audio capture and analysis
- Visualizer modes and backgrounds
- MilkDrop
- Layers, masks and effects
- Modulation
- 3D geometry and formulas
- Studio — write your own shader
- Scenes, templates, transitions and colour
- Text, lyrics and Now Playing
- Logo, images and the media layer
- Show control: timeline, clip deck, Auto VJ, MIDI and OSC
- Outputs: screens, OBS, Spout and Syphon
- Stage: projection mapping and aspect correction
- RGB lighting: Dynamic Lighting, OpenRGB and Art-Net
- Recording and video export
- MCP — control from an AI agent
- The control panel
- Reliability, power and updates
- Privacy and security
Audio capture and analysis
| Live meters | Chroma wheel |
|---|---|
![]() |
![]() |
Sources
- System output — speaker or headphone loopback. No "Stereo Mix" needed.
- Microphones and line inputs, captured the same way.
- Single applications (Windows) — WASAPI process loopback. Capture only the chosen apps, or
everything except one. Targets are stored by executable name, so a restarted app reattaches by
itself, and an app that is not running yet is picked up when it starts. Needs Windows build
20348 or newer. macOS and Linux report why it is not available there yet. - Several sources at once, mixed before analysis — "Spotify + microphone" is one selection.
- Both channels reach the visuals 3.1.5. Each frame carries the left and right
channels next to the mono mix, so stereo width, correlation and the Goniometer measure the real
stereo image. Until v3.1.5 the capture helper averaged the two channels away: width sat at 0,
correlation at 1, and the Goniometer drew a vertical line for every song. - Recovers by itself 3.1.5. If the capture helper exits or its frames stop (sleep and
resume, a device unplugged), capture is rebuilt with a growing back-off, and the panel says
"reconnecting" instead of pretending to capture. A device that drops in and out is not retried in
a tight loop. - Sensitivity, smoothing and bass emphasis, a mains-hum guard for 50/60 Hz, and live meters for
overall, bass, mid and treble.
How capture works. Capture runs in the main process, not in the browser window. A helper
reads the device — WASAPI loopback on Windows, CoreAudio on macOS, PulseAudio or PipeWire on Linux
— computes the FFT, and sends frames to every renderer.
- On macOS, system audio needs a virtual device such as BlackHole; microphones work
directly. macOS has no loopback of its own, so there is no way around this. - On Linux, system audio is the PulseAudio or PipeWire monitor of your output device. It is
an input device; the application marks it as loopback and prefers it by default.
Spectrum metering. Bars are measured, not guessed.
- Frequency scale — logarithmic, linear, mel or bark.
- Amplitude scale — linear or decibel, with a settable floor from −24 to −96 dB. dB is what
makes quiet detail visible instead of flattened against the baseline. - Ballistics — separate attack and release, so bars snap up and fall smoothly. Frame-rate
independent. - Neighbour spread (widens peaks without flattening them) and profile smoothing (a symmetric
neighbour average). - Spectral tilt in dB per octave, neutral at 1 kHz, so the top end is not permanently dead.
- Bands narrower than one FFT bin are interpolated at the band's centre frequency, so neighbouring
bars read their own values instead of sharing one bin. 27 tests cover the engine, including one
that asserts the bar profile has no step in it.
Deep analysis. Every measurement has a live meter and is available as a modulation source.
- Musical key and chord from a constant-Q chroma vector — a Goertzel filterbank rather than FFT
bins, because at 2048 samples the bass register is not resolvable by bins — with
Krumhansl-Schmuckler key profiles and chord templates. - Pitch tracking with YIN.
- Harmonic / percussive separation, and per-band onset detectors for kick, snare and hat.
- Spectral descriptors — centroid, rolloff, flatness, crest.
- Loudness, dynamics, true peak, stereo width, correlation and mid/side bands.
- Silence detection, auto-gain, and a rolling spectral history buffer.
Tempo. BPM is estimated from a period histogram (tested to ±0.5 BPM against 90, 120, 128, 140
and 174 BPM signals), with tap tempo and a BPM lock shared by Auto VJ, the clip deck and MilkDrop.
Visualizer modes and backgrounds
All 59 visualizer modes

All 43 backgrounds

These two sheets are generated from the mode catalogue itself, so a new mode appears in them the
next time the screenshots are rendered. Any visualizer can sit on any background, and with layers
you can stack as many of each as you like. Modes added since v3.1.4 are part of 3.1.5.
Visualizer modes — 59
- Basic — Bars · Center · Blocks (LED equaliser) · Dot Matrix · City Skyline (buildings with lit
windows) - Waveform — Wave (oscilloscope) · Ribbon (waveform history) · 3D Wave (history stacked in
perspective) · Lissajous (XY oscilloscope) · Strings (each string vibrates with its band) · Terrain
(perspective wireframe landscape) · Ridgelines · DJ Waveform - Radial — Circle · Radial Wave · Starburst · Arcs (one arc per band) · Pinwheel · Mandala (polar
rose curve) · Kaleidoscope · Vortex · Helix · Tunnel · Orb · Radar Chart - Particles and events — Particle · Fireworks (bursts on the beat) · Lightning (branching bolts
on bass) · Bubbles · Liquid Drop (metaballs) · Ripple Grid (rings spreading on the beat) ·
Spectrogram · Confetti · Beat Pads · Bouncing Balls - Generative systems — Flow Field (particles steered by a noise field) · Flock (boids driven by
the spectrum) · Voronoi · Truchet · Moiré · Wave Interference · Ropes (verlet physics kicked by
onsets) · Galaxy · DNA Helix · Isometric City · Attractor Field (discrete maps from the formula
library with two parameters bound to audio) · Pendulum Wave · Cardioid - Text — Text / Lyrics · Now Playing
- Metering — Oscilloscope (XY) · Goniometer (stereo phase scope) · Chroma Wheel (pitch classes in
circle-of-fifths order, highlighting the detected chord root) · VU Meter · Level Meter (PPM) - Advanced engines — 3D Geometry · MilkDrop · Feedback (the classic infinite-tunnel feedback
look) · Studio (your own GLSL shader)
Bar count, minimum and maximum frequency, gap, placement (bottom, centre or full), mirror, line
width, amplitude, sensitivity and glow appear whenever they mean something for the selected mode.
Colour comes from the scene palette, a custom colour pair, or rainbow.
Backgrounds — 43
- Fluid — Fluid Gradient (an audio-reactive mesh gradient with flow, wander, orbit, swirl, warp,
grain and audio hue shift) · Ink (liquid blobs that swirl as they flow) · Nebula (soft gas clouds)
· Wave Layers (crests that swell with the audio) · Northern Lights (undulating curtains) · Lava
Lamp · Underwater - Geometric — Retro Grid (a perspective grid to the horizon) · Honeycomb Grid (cells lit by a
wave from the centre and by the spectrum) · Mosaic (a cell per frequency band) · Corridor (rings
or polygons coming toward you) · Spiral · Pulse Rings (extra rings on bass hits) · Network
(drifting linked nodes) · Low Poly · Halftone · Isometric Cubes - Atmosphere — Starfield · Snow / Embers · Light Particles (bokeh) · Digital Rain · City (a
parallax skyline whose windows light up with the music) · Clouds · Stage Lights · Fireflies ·
Storm - Generative grounds — Liquid Metal · Plasma · Caustics · Ribbons · Contours · Wave Field ·
Embers · Sand · Stained Glass · Circuit Board · Prism · Globe Mesh · Wire Tunnel · Hex Pulse ·
Mirror Pattern - Other — Solid Colour · Studio (a GLSL shader you wrote yourself)
Transparent background. Turn on Background → Transparent Background and the desktop shows
through the visualizer window: a solid colour is not painted, and a background effect's dark parts
turn transparent below a Transparency Threshold. Transparency survives the effect chain, so
bloom and blur glow over empty pixels without turning the window into a black rectangle.
MilkDrop
| Preset library with thumbnails 3.1.5 | Live preset editor 3.1.5 |
|---|---|
![]() |
![]() |
A MilkDrop engine written for this application — it does not embed projectM or MilkDrop's code.
The preset language runs for real: a tokeniser, a parser and compilation to JavaScript closures;per_frame and per_pixel equations drive a warp mesh with feedback; the HLSL warp and composite
shaders are translated to GLSL and run on the GPU.
- Measured, not claimed. Over a 10,347-preset corpus from the projectM original and
cream-of-the-crop packs, every preset loads and runs, all 16,346 shader stages compile, and about
98% produce a live image. Fidelity is checked frame by frame against a reference renderer built
from BeatDrop's MilkDrop 2 sources. Both harnesses are inscripts/, so the numbers can be reproduced. - A MilkDrop Fidelity switch follows MilkDrop 2's own rules — its compiler, its audio chain, its
mesh transform, its default values and its fixed-function pipeline. The details are in
MilkDrop engine notes at the end of this page. - Five presets of our own ship with the app — Aurora, Molten Gold, Still Rings, Endless
Tunnel and Pulse Weave — so the engine shows what it does before you import anything. No
third-party preset pack is bundled. - Import a whole library 3.1.5 — from a ZIP pack, a folder, or by searching this
computer (Winamp, foobar2000 and projectM folders, Downloads, Desktop, Music, Documents). You see
what will be added before anything is copied; duplicates are skipped; textures come along; folder
names can become tags. A 9,795-preset folder imports in about six seconds. .milkand.milk23.1.5 — MilkDrop 3's double presets load as a frozen blend of
their two presets, and a Preset Format setting reads files with MilkDrop 2 or MilkDrop 3 rules
(16 custom waves and shapes,q1–q64), or picks automatically.- Thumbnails 3.1.5 — a Grid layout shows each preset as a small picture, drawn once
in the background and redrawn only when the preset or a texture it uses changes. - Favourites, tags, ratings and search by author 3.1.5 —
author:geissfinds Geiss's
presets,#calmfinds a tag; random order is weighted by rating as MilkDrop weights it; Previous
and Next walk a 64-step history of what was actually shown. - A live editor 3.1.5 — frame and pixel equations, waves, shapes, warp and composite
shaders each have a tab; a change shows in the running picture a moment after you stop typing;
errors point at the preset's own line. The original is never changed. - A preset generator and mash-ups 3.1.5 — write an original preset from four sliders
(energy, warmth, density, motion) and a seed that brings the same preset back, or build one from
parts of the presets you already have. Generated presets never flash. - Show control 3.1.5 — auto advance by seconds or on the bar, hard cuts on loud
moments, next preset on track change, a lock, and MilkDrop actions on MIDI and OSC. Every screen
shows the same preset with the same random seed. - User textures and sprites 3.1.5 — point at a MilkDrop
texturesfolder, and launchmilk_img.inisprites with MilkDrop's own keys or from a controller. - Safe to watch 3.1.5 — flash limiting at WCAG 2.3.1's general-flash value, held per
second so a 144 Hz screen is as safe as a 30 fps one, and the system's reduce motion setting
is honoured. - Survives a GPU reset 3.1.5 — a lost WebGL context is rebuilt on the same canvas,
and the running preset carries on with the same equation state and clock.
The Feedback engine is MilkDrop's family resemblance without presets: zoom, rotate, warp and
decay sliders, four wave styles, and bass-driven zoom and rotation for the classic infinite tunnel.
Layers, masks and effects
| Layers | Effect chain |
|---|---|
![]() |
![]() |
- Unlimited layers, each with its own source, blend mode, opacity, transform (scale, rotate,
X/Y, flip) and audio response (band, opacity, scale, rotate). The layer at the top of the list is
the topmost one in the output. - 17 blend modes — Normal, Add, Screen, Multiply, Overlay, Darken, Lighten, Colour Dodge, Colour
Burn, Hard Light, Soft Light, Difference, Exclusion, Hue, Saturation, Colour, Luminosity. - Masks — alpha from another layer, plus rectangle, ellipse, linear and radial gradients, with
position, size, angle, feather and invert. - Groups with a single fader, and an A/B crossfader on an equal-power curve.
- Solo, mute and lock — solo isolates a layer reversibly, mute hides one without losing its
settings, lock prevents accidental edits. - Copy, paste and duplicate layers across scenes. The whole stack can be switched off, returning
to the plain Background plus Visualizer setup without losing the list. - One broken layer no longer takes the frame with it 3.1.5, and layers hidden under
an opaque MilkDrop layer are not drawn at all.
Post-processing — 40 GPU effects, orderable, each with its own opacity, toggleable, and
available per layer as well as on the composite. An effect on a single layer keeps that layer's
transparency, so the layers below stay visible.
- Composition — Bloom · Vignette · Trails / Echo · Edge Highlight · Colour Grade
- Blur and focus — Gaussian Blur · Radial Blur · Directional Blur · Zoom Blur · Tilt-Shift ·
Depth of Field (Bokeh) · Sharpen · Emboss - Halftone and pattern — Dither (Bayer) · Halftone · ASCII Mosaic · Cross-Hatch (Pen) · Oil Paint
(Kuwahara) · Pixelate · Posterize / Invert · Threshold · Solarize - Analogue and damage — Film Grain · CRT / Scanlines · VHS / Analogue Tape · Glitch (Slice Shift)
· Datamosh (Block Shift) · Bad Signal · Chromatic Aberration - Distortion — Lens Distortion · Twirl · Polar Transform · Ripple Distortion · Slit-Scan ·
Kaleidoscope · Mirror - Colour and light — Gradient Map · Levels & Curve · God Rays · Star Filter
Any parameter of any effect can be driven by the modulation matrix.
Modulation

- Any source to any setting — routes go to any dotted configuration path, chosen from a live
tree of the current settings. - Sources — bass, mid, treble, level, onset envelope and onset trigger · eight spectrum bands ·
LFOs · envelope followers · sample-and-hold · random · the beat clock · macro knobs · and every
deep-analysis measurement (key, chord, pitch, loudness, drum bands…). - Eight LFO shapes — sine, triangle, saw up, saw down, square, pulse, random ramp and noise —
with rate in Hz or in beat divisions (1/16 up to 8 bars) locked to the detected tempo, plus phase
offset and pulse width. - Per-route shaping — minimum, maximum, amount, set or add, a curve (linear, exponent, S-curve,
quantise, invert), smoothing and slew limiting. - Eight macro knobs, exposed to MIDI learn.
- Values are applied copy-on-write, so modulation never alters your saved settings, and LFO phase
comes from the draw clock, so offline export is frame-exact.
3D geometry and formulas
![]() |
![]() |
![]() |
![]() |

- Plane curves (30) — rose curves, lemniscates, cardioids, epicycloids, hypocycloids, spirals,
roulettes, Lissajous figures, butterfly and superformula curves among them. - Space curves (12) — trefoil and torus knots, Viviani's curve, helices, conical spirals and
similar. - Surfaces (29) — torus, Klein bottle, Möbius strip, Boy's surface, Dini's surface, breather,
superellipsoid, Gielis supershapes, Chladni figures, trefoil tube and more. - Strange attractors (27) — Lorenz, Rössler, Chen, Halvorsen, Thomas, Aizawa, Chua, Dadras,
Sprott, Clifford, de Jong, Hénon and others, continuous and discrete. - Solids (13) — tetrahedron, cube, octahedron, dodecahedron, icosahedron, a geodesic sphere with
subdivision control, four L-systems (tree, fern, dragon curve, 3D Hilbert curve) and three iterated
function systems (Barnsley fern, Sierpinski tetrahedron, spiral). - Render as wireframe, points or shaded, with resolution, deformation, spin, colour mode and audio
binding on every parameter. - Own matrix maths — no third-party 3D library. Framing is measured, not declared: the first
iterations of an attractor are probed for their bounding box, and a test asserts every system
lands inside the view volume.
Studio — write your own shader
| Studio | Built-in shaders |
|---|---|
![]() |
![]() |
- A GLSL editor with live preview, error line reporting and sliders you declare yourself.
- Shadertoy and ISF import through local converters. No service is contacted.
- Shaders receive
sv_resolution,sv_time,sv_level,sv_bass,sv_mid,sv_treble,sv_beat,sv_spec(x),sv_waveAt(x),sv_col(x)for the scene palette, andsv_mediafor the
camera or video layer. - 42 built-in shaders, all compiled on a real GPU by the self-test:
- Backgrounds (25) — Cloud Layers · Curl Flow · Lava Lamp · Ink Bleed · Smoke Rings · Hex Flow
· Warped Grid · Truchet Weave · Moiré Interference · Crystal Cave · Mandelbrot Zoom · Julia Set ·
Burning Ship · Apollonian Gasket · Kaleidoscopic IFS · Menger Sponge · Mandelbulb · Light Tunnel
· Star Warp · Aurora Curtain · Liquid Metal · Neon Rain · Reaction Pattern · Water Caustics ·
Prism Glow - Visualizers (11) — Glowing Bars · Spectrum Ring · Wave Field · Beat Burst · Glowing
Oscilloscope · Frequency Mesh · Note Ring · Particle Flow · Kaleidoscope Spectrum · Pulse Grid ·
Liquid Bars - Six earlier presets — Plasma Sea, Frequency Rings, Liquid Metal, Star Gate, Wave Curtain,
Bass Sphere
- Backgrounds (25) — Cloud Layers · Curl Flow · Lava Lamp · Ink Bleed · Smoke Rings · Hex Flow
- MilkDrop Preset Generator and Editor live here too — see MilkDrop.
Scenes, templates, transitions and colour
| Templates | Scene transitions |
|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Scenes store the whole look — background, visualizer, layers, effects, logo, text, modulation,
MilkDrop and visual objects — under a name. Restore with one click, update from the current look,
export and import as JSON.
72 templates in nine groups. One click, and your audio device, display selection, streaming
and lighting settings are left alone — trying a template must not damage a working setup, and a
test asserts it.
- Club (8) — Strobe Wall, Hyper Tunnel, Laser Grid, Mandala Drop, Strobe Floor, Fireworks,
MilkDrop Flow, Strange Attractor - Ambient (9) — Aurora, Ink in Water, Topography, Underwater, Embers, Liquid Metal, Night Globe,
Flow Field, Interference - Streaming (6) — Corner Bars, Clean Wave, Ring Meter, Scope Overlay, Lower Third, Studio Meters
- Music Video (8) — Label Card, Artwork Card, Baseline Bars, Amber Room, Minimal White, Quiet
Frame, Corner Meter, Centre Strip - Music (6) — Chroma Wheel, Helix, Silk Ribbons, Strings, Spectrogram, Galaxy
- Screensaver (6) — Plasma, Stained Glass, Circuit, Wire Tunnel, Dunes, Prism
- 3D Geometry (8) — Klein Bottle, Lorenz, Supershape, Trefoil Tube, Chladni, Rose Curve, Chua
Circuit, Möbius - Genre (16) — Techno, House, Drum & Bass, Hip-Hop, Lo-Fi, Synthwave, Rock, Metal, Jazz,
Classical, Ambient, Pop, Trance, Dubstep, Chiptune, Experimental - Event (5) — Minimal Line, Corporate, Gala, Festival, Projection Test
Music video layouts. Restrained layouts for release videos and official channels, deliberately
separate from the club material: bar placement as a fraction of the frame, your logo beside the
bars rather than behind them, and the track title and artist as separate layers.
![]() |
![]() |
![]() |
![]() |
Scene Generator. Builds a scene from a description. It is not a neural network and is not
presented as one: it reduces the text to four axes with a weighted keyword dictionary and seeds a
deterministic generator from them. It runs entirely offline.
18 scene transitions — Cut · Crossfade · Dissolve · Wipe · Radial · Clock · Barn · Blinds ·
Stripes · Checker · Iris · Luma (keyed on the outgoing frame's own luminance) · Zoom · Push · Slide ·
Flash · Glitch · Blur. Six easing curves, a duration in seconds or in beats, and a switch to turn
them off. They fire on a change of scene, never on a slider, so dragging a control never starts
one.
Colour. Five colour stops, 58 built-in palettes in seven groups (Classics, Warm, Cool, Neon &
Cyber, Dark, Light, Monochrome Families) and your own saved palettes apply to every background, to
Studio and to the 3D engine. Every visualizer can follow the palette (theme colour mode).
Dynamic colour theme (Windows). The palette can follow the playing track: colours extracted
from the album cover, a harmony style (analogous, complementary, triadic, cyberpunk, synthwave,
aurora…), the mood of the title, or a cycle through presets — applied to the background, the
visualizer, or both.
Text, lyrics and Now Playing
| Now Playing | Text |
|---|---|
![]() |
![]() |
Now Playing. On Windows the application reads the system media session (SMTC), so the track
from Spotify, YouTube Music, a browser or most players appears on screen by itself: title, artist,
album, elapsed and remaining time, a progress bar and the album cover. It can stay on screen or
appear only when the track changes, with seven animations and Modern and OG styles. On macOS
and Linux the title, artist and cover are entered by hand. Now Playing also shows in the panel
preview and in exported videos 3.1.5.
Text. Audio-reactive typography with per-character response (scale, jitter, lift) · font,
weight, size, alignment, position, opacity, outline and shadow · animation presets · marquee and
ticker · karaoke highlighting.
Lyrics.
- LRC and SRT import, the format detected from the content, enhanced LRC word timings supported.
- A timing editor with a sync offset that writes back to LRC.
- Play, pause and stop for a loaded lyrics file while the screens are open; all screens and the
OBS overlay share one clock, corrected to the machine running the app. - Lyrics library (Windows) 3.1.5 — keep many LRC or SRT files, each with an artist and
a title. Follow the Playing Track finds the right file for the song from the system media
session and moves with seek and pause. Exact Match or Partial Match for small spelling
differences; timed lyrics from the player are used when the library has no match. Files open in a
tall editor with colouring for timestamps, word times and tags; removing one asks first. Nothing
is fetched from the network.
Logo, images and the media layer
- Logo — an image placed anywhere in the frame, automatically sized, with size, opacity, glow,
position and audio pulse; animated GIFs play. The logo can also show the album cover of the
playing track. Applying a template keeps your logo and only changes its placement. - Logo and video libraries 3.1.5 — imported files are copied into the app's own
folder and referenced by id, so the settings file stays small and a moved original does not break
a scene. - Visual objects — image sprites in front of or behind the visualizer, with count, size, drift,
rotation and audio response. - Media layer — a webcam or a video file, in front of or behind the visualizer, with fit (cover,
contain, stretch), mirror, kaleidoscope with 3–12 slices, hue shift, saturation, blend mode,
opacity, and audio-driven zoom and opacity. The same frame is readable inside Studio shaders assv_media.
Show control: timeline, clip deck, Auto VJ, MIDI and OSC
| Timeline | Clip Deck |
|---|---|
![]() |
![]() |
Timeline. Lay scenes and setting changes out along time, aligned to the bar or to the second;
one playhead drives every screen together, and offline export plays the same show.
- Clip tracks for scenes, templates, palettes, video, images, shaders and actions; automation
lanes for any setting, with curves; markers and a loop. - A full editor 3.1.5, modelled on Ableton's Arrangement View: a toolbar with
transport, clock (time and bar.beat), tempo, snap, loop, follow and zoom; track headers with
colour, mute, solo and lock; split at the playhead, duplicate, copy and paste, nudge, 100-step
undo; multi-select with box selection; a draggable loop brace and marker flags; per-clip
transition handles; tempo changes on the ruler; adjustable lane height and a full-window mode;
and keyboard shortcuts that only act while the editor has focus.
Clip Deck. Place scenes, templates, palettes and media on a grid and fire them on the beat.
- Beat-quantised launching with a global quantise setting, follow actions (next, random,
go-to, loop, stop) and durations. - Launch modes 3.1.5 — trigger, toggle and gate (plays while held).
- Several decks with tabs, named rows and columns, colours, progress bars, a blinking countdown
on queued cells, drag-and-drop to move or copy, and a Performance View for a second screen. - Keyboard play 3.1.5 — 1-9 or arrows pick the row, A-P fires a slot, Enter launches
the row. - Media and action slots 3.1.5 — video, image and shader slots apply to a chosen layer;
action slots run the same actions as MIDI and OSC mappings. - Fired slots can be recorded to the timeline, so an improvised set becomes an editable show.
Tempo and Auto VJ. The track's tempo is detected and Auto VJ changes scenes, visualizer
modes or colours by itself, aligned to the bar. Pick exactly which scenes, modes or palettes cycle
(or leave it empty for all), give each visualizer layer its own mode, and read a status line that
says what changed, what comes next, and why nothing can happen when a source is empty.
MIDI. Learn a control, then map any CC or note to any setting or action — including MilkDrop's
next, previous, random, cut, lock and rating.
OSC. A UDP listener with a hand-written OSC 1.0 parser, for TouchOSC, Resolume, Ableton or QLab.

Phone remote. A phone-sized page for scenes, colour palettes, Studio presets, visualizer and
background modes, audio sensitivity, blackout and the now-playing card, served by the same server
as the OBS overlay. Values sent from the phone are
range-checked before they are applied 3.1.5.
Blackout on Space or from any controller, with its own transition, leaving the stored
scene untouched.
Outputs: screens, OBS, Spout and Syphon

Multi-monitor. A separate full-screen window on every display you select. The chosen displays
are remembered by position and size, so a monitor that Windows renumbers after reconnecting is
found again 3.1.5.
Floating window 3.1.5. A picture-in-picture window with opacity, a 16:9 aspect lock,
a position lock and click-through, for keeping the visuals over your desktop while you work.
Streaming output — OBS and the browser. Turn on Output → Streaming Output and the
application serves an overlay page.
- Add it to OBS as a Browser Source. No plugin, and real transparency.
- The overlay runs the same engine as the desktop window, so what you see is what streams —
MilkDrop presets and their textures included. - Works across the network, so the visualizer can run on one machine and OBS on another.
- Transparency is the app's own switch; add
?transparent=0or?transparent=1to one source's
address to force it either way. - Lyrics follow the app, and the browser corrects its clock to the machine running the app.
- A diagnostics card 3.1.5 — add
?debug=1to the address to see the connection,
configuration, audio frame rate, canvas size, transparency, app version and last error. - Access is protected by tokens; the overlay and the phone remote have separate ones.
GPU output — Spout and Syphon. The picture can be handed to another application on the same
machine over the GPU: no window capture, no CPU copy.
- Spout on Windows, Syphon on macOS. Receivers include Resolume, OBS, TouchDesigner and
MadMapper — anything that speaks either protocol. - Pick the source name, resolution and frame rate.
- It renders in its own hidden window, so the feed keeps running even when no visualization window
is open. - Spout and Syphon stay opaque: a shared GPU texture cannot carry alpha without dropping the sender.
- Not available on Linux, which has no built-in equivalent. The panel says so and points at the
OBS browser source, which works everywhere.
Stage: projection mapping and aspect correction

Projection mapping
- Corner pin as a true homography, with the denominator written into
gl_Position.wso the
texture stays perspective-correct. - Mesh warp on a Catmull-Rom grid that passes through its control points.
- Soft edge blending for multi-projector rigs; the curves are tested to sum to exactly 1 across
the overlap. - Per-output crop, colour correction and Bézier polygon masks, plus alignment grids, crosses,
colour bars and focus rings, with drag, arrow-key nudge and exact numeric entry.
Aspect correction. A display's reported resolution does not always match its physical shape. A
panel driven at 1920×1080 that is really about 3:1 — a stage LED wall, a bar display, an anamorphic
projector, a TV forced into a stretched mode — draws every circle as an ellipse.
- The frame is never stretched. The scene is drawn on a square-pixel canvas matching the panel's
real shape and squeezed linearly into the framebuffer, where the panel's own distortion undoes
the squeeze. Nothing is cropped and nothing is pushed off the edge. - One setting corrects everything — background, visualizer, logo, text and sprites together.
- Calibrated by eye with a circle, square or grid, or from the panel size, the true aspect ratio
or the dimensions of an already-stretched image. - Per screen or all screens, composes with projection mapping without moving an existing corner
calibration, and leaves exported video, the stream and the web overlay alone.
RGB lighting: Dynamic Lighting, OpenRGB and Art-Net
Windows Dynamic Lighting
- Off by default, and available only when compatible devices are detected.
- Dynamic modes: visualizer colour flow, bar-spectrum mapping, bass/mid/treble zones,
background-light sync, synchronised beat flashes, frequency ripples, bar and background fusion,
cross-device colour flow, rainbow flow, and threshold-triggered bursts. - Manual modes: one colour, per-device colours, and per-LED or per-zone colours where the hardware
exposes them. - Brightness, audio reactivity, smoothing, update rate, LED layout, palette source, per-band colours
and sensitivity, flash threshold, strength and decay, ripple speed, direction and width, and
colour spread are all configurable. - The installer registers the Windows background-lighting identity, so lights keep running when the
app is not focused. Place the app near the top of Dynamic Lighting → Background light control.
OpenRGB — RGB everywhere else. Talks to a running OpenRGB server over its own protocol (TCP,
port 6742 by default) on Windows, macOS and Linux — no vendor software, and the server may sit on
another machine. Every device OpenRGB exposes, per-LED where the hardware allows, with the same
modes and colour maths as Dynamic Lighting.
Art-Net / DMX. ArtDMX output to fixtures and lighting desks; the packet layout is tested byte by
byte.
Colour sources. The lights can follow the background, the theme, or the live MilkDrop
picture 3.1.5 — sampled about 30 times a second into eight slices from left to right, so
the fixtures on the left take the colours on the left of the screen.
Recording and video export

- Offline video export (audio file → MP4). Renders a track frame by frame — not a screen
recording — at 720p, 1080p, 1440p or 4K, 30 or 60 fps, with quality, a CPU or GPU encoder, progress,
cancellation and a GPU-to-CPU fallback. It is deterministic: the same job gives the same video, the
property the visual regression tests rely on. Title, artist, album and cover are read from the
file and feed Now Playing and text layers. - Live recording of the output exactly as it appears — with the live audio, modulation,
transitions and effects — to MP4 or WebM, on one key. - GIF export with two-pass palette generation, because one pass bands visibly.
- PNG snapshot at up to 4×, on a shortcut.
- Export presets for common aspect ratios.
MCP — control from an AI agent
3.1.5
An agent drives the running application over the Model Context Protocol. The switch is on the
Control card and is off by default. The application stays open while the switch is on. The
setup dialog gives a stdio command for Claude Desktop, Codex, Cursor, Grok and Grok Bot. Ollama is
a local model behind an MCP client and uses that same command.
The server speaks JSON-RPC initialize, ping, tools/list and tools/call. It accepts protocol
versions 2024-11-05, 2025-03-26 and 2025-06-18, and answers 2024-11-05 for any other
version. The server name is soundvisualizer. There are 96 tools.
The client spawns the stdio bridge. The bridge posts to http://127.0.0.1:<port>/mcp with a bearer
token. The socket binds 127.0.0.1 only. The port is 38471 unless you set another. Port
8722 is refused, because that port belongs to the stream. A busy port stays busy: the server
does not move, and the card reports the failure. Each start writes a new token intomcp-endpoint.json in the application data folder, next to a copy of the bridge. On Linux and
macOS those two files are readable by this user only. A connection from anywhere else is refused,
and so is a missing or wrong token.
sv_get_config and the output-status read replace stream tokens with a redaction. sv_set_stream
drops token and remoteToken. A full-config sv_export_json writes the settings as stored, to a
path you name.
Five modes stack. The switch turns on in Read. A higher mode includes the ones below it. The
agent cannot raise its own access: sv_patch_config refuses any mcp.* path. A blocked call names
the mode it needs and tells the agent to leave the mode alone and leave the panel unclicked.sv_list_permissions and mcp_permissions report the active mode and, when you pass a tool name,
the minimum that tool needs.
A change the mode allows is saved and pushed the same way a click is. The admin panel, open
visualizer windows and the stream all receive it. After every call, success or error, the preset
folder is re-read and open windows receive the delta.
Read
The master switch is enough. These calls only read.
sv_get_statereturns the show: active preset, scenes, layers, effects that are on, displays,
BPM and levels, now playing, the layer stack, stream status, Spout/Syphon status and the live
analysis from the panel preview (empty while the preview has no sound).sv_get_visual_state,sv_list_layers,sv_get_layerandsv_get_layer_stackreturn layer
position, settings and per-layer effects.sv_get_previewadds a JPEG of the picture on screen, at most 480 pixels wide. It uses an open
visualizer window, then the floating window, then the preview rectangle in the admin panel.sv_get_audioreturns level, bass, mid, treble, BPM and confidence from the same meter the panel
draws.sv_get_now_playingreturns the current track.sv_list_audio_sourceslists the
configured inputs.sv_list_scenesandsv_get_sceneread saved scenes.sv_list_modeslists every visualizer and
background id, layer kind and blend mode; the mode and layer tools reject an id it does not list.sv_list_effectslists the global chain,
each layer's chain, and the 40 built-in effect types.sv_list_presetslists library presets
and user colour palettes.sv_list_displayslists screens.sv_get_output_statusreads which visualizer windows are open, the stream switch, port and LAN
flag, and the Spout/Syphon name.sv_get_timeline,sv_get_clipdeckandsv_get_autovjread
those panels.sv_get_configreads the whole configuration or one dotted path.
Apply
Uses what is already saved.
sv_apply_sceneloads a saved scene by id, or by name when that name is unique. The snapshot
covers background, visualizer, layers, groups, crossfade, geometry, effects, logo, images, media,
text, modulation, transition, Studio, MilkDrop and feedback. Window transparency and taskbar
cover stay as they were.sv_apply_templateapplies a built-in template by id or name.sv_set_visualizer_typeandsv_set_background_typeswitch to an existing mode id. A Studio shader is shown with typecustomand itspresetId.sv_set_layer_enabledshows or hides a layer and turns the stack
on.sv_set_crossfadesets the A/B fader from 0 to 1.sv_trigger_clipfires one clip-deck slot by row and column.sv_stop_clipsstops every playing
slot. The grid stays as saved. Both need the admin window open.sv_set_effect_enabledandsv_set_effect_paramchange a global effect already on the chain.
The layer pair does the same for one layer.sv_set_modulation_enabledturns the modulation
matrix on or off.sv_set_macrosets one existing macro fader.sv_load_presetcopies an existing library preset into the live MilkDrop source.sv_apply_color_presetpaints an existing user or built-in palette onto the background gradient.sv_set_milkdrop_cyclesets how the library advances: auto next, order, source, tag, unit, bar
count, track advance and hard cut.
Write
Creates and edits.
- Scenes:
sv_create_scenestores the current look under a new name,sv_update_sceneoverwrites
one,sv_rename_scenerenames,sv_delete_sceneremoves. - Layers:
sv_add_layer,sv_update_layer,sv_set_layer_position,sv_set_layer_settings,sv_remove_layer,sv_reorder_layers. A layer carries kind, type, preset, opacity, blend,
transform (x, y, scale, rotate, flip), audio response, mask, solo, mute, lock and group. Effects
on a layer go through the effect tools. Adding or showing a layer turns the stack on. sv_set_textedits the text overlay, including a lyrics or now-playing source.sv_set_logo,sv_set_mediaandsv_set_geometryedit those blocks.- Effects:
sv_add_effectandsv_remove_effecton the global chain,sv_add_layer_effectandsv_remove_layer_effecton one layer. The built-in types are bloom, chroma, glitch, grain, crt,
pixelate, kaleido, mirror, grade, vignette, trails, edge, zoomblur, ripple, posterize, blur,
radialblur, motionblur, tiltshift, dof, sharpen, emboss, dither, halftone, ascii, hatch, paint,
vhs, datamosh, slitscan, lens, twirl, polar, gradientmap, levels, threshold, solarize, godrays,
badtv and starfilter.sv_add_modulation_routeandsv_remove_modulation_routeedit routes. - Presets:
sv_save_presetwrites a file in the preset store. Shader text with no kind is saved as
a Studio visualizer (kindvisualizer,engineshader). Any other save with no kind is
MilkDrop.sv_delete_presetremoves a file.sv_set_milkdrop_sourcewrites MilkDrop source into
the live show.sv_create_color_presetsaves a user palette of at least two colours.sv_delete_color_presetremoves a user palette. - Auto VJ:
sv_set_autovjsets enabled, source, interval, unit, order, BPM lock, palette source
and per-layer visualizer targets. - Export and recording:
sv_start_exportrenders an audio file that exists on disk to a video path
you name. Resolution, 30 or 60 frames per second, a CPU or GPU encoder, speed and quality are the
same options as the export panel.sv_cancel_exportstops a running export.sv_export_json
writes the scene list, or the full settings, to a path, with no dialog.sv_save_snapshotwrites
the live picture to a path as a JPEG. These three tools take only an absolute local path with
the matching extension:.mp4for the video,.jsonfor the settings,.jpgor.jpegfor the
picture. Network paths and addresses such astcp://are refused.sv_record_startandsv_record_stopdrive the admin recorder.
Stopping opens the same save dialog as the Record card. The recorder needs the admin window open.
Full
Opens the live surfaces.
sv_open_outputopens the visualizer on the chosen displays. Passing a display id replaces the
selected set.sv_close_outputcloses visualizer windows.sv_set_displayschooses displays and
leaves the windows as they are.sv_set_streamchanges the OBS and browser stream.sv_set_texture_sharechanges Spout and
Syphon.sv_set_aspectchanges aspect correction.sv_set_powerchanges the frame-rate cap,
the render scale andkeepAwake, which keeps the display awake while a visualizer window is open.sv_set_floatingchanges floating-window preferences, including opacity and click-through.sv_set_floating_openopens or closes that same picture-in-picture window.sv_set_window_modesets a transparent background, the transparency threshold and taskbar cover.sv_set_lightingchanges Windows Dynamic Lighting.sv_set_openrgbchanges OpenRGB.sv_set_artnetchanges Art-Net.sv_set_audio_sourcesreplaces the input mix.sv_set_mappingwrites one display's projection map: enable, corners, crop, edge blend, masks,
mesh, colour and test pattern, and turns mapping on. It binds no new network port.sv_timeline_transportplays, pauses, stops or seeks the timeline through the admin transport.
The admin window has to be open.sv_set_blackouttakeson,offortoggleand leaves the stored scene in place.sv_set_blackout_transitionsets the blackout transition type and duration.
Everything, and the general patch
sv_patch_config sets any other dotted path. The mode follows the path: scene content, effects
and presets need Write; export paths need Write; displays, stream, lighting, mapping,
windows and the timeline need Full; control.* (MIDI and OSC bindings) needs Everything.
A path that holds a stricter one needs that mode too: the whole stream object needs
Everything because it holds the tokens, and the whole power, audio, background andtransition objects need Full. A path the table does not know needs Everything. The pathsmcp.*, version, __proto__, prototype and constructor are refused.
sv_updates_download and sv_updates_install download and install an update the app has found.sv_rotate_stream_token replaces the OBS or remote token. sv_repair_audio restarts capture when
the audio component is healthy; when it is missing it says so, because installing it needs the
user's consent. All four need Everything. The reads sv_diagnose_audio and sv_get_analysis
return the capture diagnosis and the live analysis (key, chord, pitch, loudness, drum bands).
The control panel

- Eight categories — Scene, Audio, Lighting, Output, Control, Studio, Library and Settings.
- Live everywhere — every change reaches the output windows immediately and saves itself.
- A live preview with its own demo signal, audio meters and saved scenes beside every page.
- Modified badges on each card and category, with a reset for the section or the whole category.
- Search across every setting in every category (Ctrl + K).
- Advanced toggles hide rarely used controls until you want them; extended ranges raise the
slider limits 5×. - Turkish and English, switchable at runtime; the self-test fails if any interface string is
left untranslated.
Reliability, power and updates
- Accidental-close protection — a visualizer window that closes unexpectedly (a crash, Alt+F4)
reopens at once; Prevent accidental quit asks before the app closes during a show; an optional
ESC lock, with Ctrl + Shift + Q as the way out. - Keeps the display awake 3.1.5 — on by default while a visualizer window is open and
not minimised, on Windows, macOS and Linux; minimising or closing hands control back to your power
settings. - Every GPU surface recovers from a lost context 3.1.5 — a driver reset no longer
leaves black layers until a restart. - Main-process faults are contained 3.1.5 — an unexpected error is logged and shown in
the panel instead of freezing the app behind an error dialog. - Two copies at once 3.1.5 — a second copy names the one already running and offers to
switch to it; a copy never silently writes over settings someone else changed. - Updates 3.1.5 — Library → Updates checks GitHub Releases, shows the notes, and
lets you skip a version. The Windows installer and the AppImage download and install in place;
nothing runs unless the size and the SHA-256 match exactly. Off, notify (default) or automatic. - Settings backup and restore — every setting in one JSON file; palettes and scenes have their
own export and survive an import. Files written by 1.3 and 2.0 load without losing a value. - Power and performance — Match Display frame rate or a cap of 120, 60 or 30 FPS, background
resolution scale, pause on silence, hide cursor, always on top, and cover the taskbar.
Privacy and security
- No account, no telemetry, no analytics. Settings live in your user folder.
- One network call of its own: GitHub's latest-release API for the update check, with no
identifiers. Set updates to Off and there are none. - Everything else is opt-in and local: the stream server (LAN, token-protected; it refuses
pages from other origins and host names it does not know 3.1.5), OSC, OpenRGB, Art-Net
and MCP (bound to127.0.0.1only, with a bearer token). - Converters and generators run offline — Shadertoy and ISF import, the scene generator, the
MilkDrop preset generator, lyrics. - The camera is never opened by automation, and a fuzzing test asserts that no MilkDrop preset can
smuggle JavaScript into the engine.
FAQ
Is it free?
Yes. CAYADEV Visualizer is open source under the MIT licence. There is no paid tier, no account and
no watermark.
Do I need Stereo Mix or a virtual audio cable?
Not on Windows: system audio is captured straight from the output device. On macOS, system audio
needs a virtual device such as BlackHole (microphones work directly). On Linux, the PulseAudio or
PipeWire monitor source is used automatically.
Does it work with Spotify, YouTube, Apple Music or a DAW?
Yes — it visualizes whatever your computer plays. On Windows you can capture one application only
(say, Spotify) and ignore everything else, and Now Playing reads the track title and cover from the
system media session.
Can I use it as an OBS overlay?
Yes. Turn on Streaming Output and add the address as a Browser Source. Transparency works, and OBS
can run on a different computer on the same network. Spout (Windows) and Syphon (macOS) are there for
GPU sharing as well.
Can it load my MilkDrop presets?
Yes: single .milk files, MilkDrop 3 .milk2 double presets 3.1.5, ZIP packs, folders, or
a search of your computer. Point the app at a MilkDrop textures folder for presets that use images.
No third-party preset pack is bundled; five original presets are.
Is it a Winamp or projectM plugin?
No. It is a standalone application with its own MilkDrop-compatible engine in WebGL2. It does not
embed projectM or MilkDrop.
Does it support several monitors and projectors?
Yes — a full-screen window on every selected display, plus projection mapping, edge blending and
aspect correction for projectors and LED walls.
Can I make a music video from a track?
Yes. Video Export renders an audio file to MP4 frame by frame, up to 4K at 60 fps, using the current
scene. It is not a screen recording, so the result does not depend on how fast your computer is.
Can AI agents control it?
Yes 3.1.5. Turn on MCP on the Control page and connect Claude Desktop, Codex, Cursor or any
MCP client with the command the setup dialog gives you. Access starts at read-only.
Will it slow my computer down?
It needs a GPU with WebGL2. Use the frame-rate cap, the background resolution scale and pause on
silence on laptops; the MilkDrop panel shows mesh density and internal resolution.
Can it be a screen saver?
There is a Screensaver template group, and the display is kept awake while the visuals run, but the
application does not register itself as an operating-system screen saver.
How well are macOS and Linux supported?
Both are built on CI runners and the audio engine loads there, but neither build has yet been run on
real hardware by the project. Windows is where everything is measured. Reports from Mac and Linux
users are very welcome.
Is my data sent anywhere?
No. See Privacy and security.
MilkDrop engine notes
The engine's fidelity work, measured preset by preset. MilkDrop Fidelity is on by default; switching
it off restores the engine's earlier look.
- The preset language actually runs — tokeniser, parser, and compilation to JavaScript
closures.per_frameandper_pixelequations drive a real warp mesh with feedback, includingmegabuf/gmegabuf,loop,while,exec2/exec3and compound assignment. - Measured against 10,347 real presets from the projectM original and cream-of-the-crop packs:
every one loads and runs, 10,344 of them with no skipped statement at all. .milkimport, including multi-file packs with per-file compile errors reported.- Five presets of our own ship with the application. Kutup Işığı (a flowing nebula),
Erimiş Altın (the loud one), Dingin Halkalar (slow and nearly black), Sonsuz Tünel (the
classic tunnel) and Nabız Örgüsü (squares on the beat over a motion-vector weave) — written
here, so the engine shows what it does before you import a pack of your own. They join auto
advance like any other preset. The two pictures on this page are rendered from them. - No preset text is copied into generated code. There is no
evaland no generated source:
each node becomes a closure, identifiers become pool indices, and function names are resolved
against a fixed table at compile time. - The HLSL warp and composite shaders are translated to GLSL and run on the GPU. Measured in a
real WebGL2 context over the 10,332-preset corpus: all 16,346 shader stages compile, and every
one of the 8,485 presets that carries a shader has every stage clean. A separate harness renders each preset and reads the pixels back,
because a shader that compiles can still draw black: ~98% produce a live image. The seeded slice resolves to about a preset either way: the harness deliberately carries the feedback buffer between presets, so one preset sitting on a class threshold can move the last digit without anything in the engine changing. Both
harnesses are inscripts/, so the numbers can be reproduced rather than believed. - The picture uses MilkDrop's own values, not an approximation of them. Each of these was found
by diffing the corpus against what the engine actually reads, and each is measured: two header
settings never reached the equations at all (fZoomExponentandfWaveParam, one of which
66.6% of presets rely on); the warp mesh ran in a vertically mirrored space, sody,cyand the
direction of rotation were flipped (48.8% usedyorcy); the warp ripple used invented
constants and ignoredfWarpScaleandfWarpAnimSpeed(79.9% and 44.0%); the waveform ignoredfWaveSmoothing(79.0%), a custom wave's ownsmoothing, andbModWaveAlphaByVolume(38.9%);
and the outer/inner borders (37.8%) and the centre darkening (6.9%) were never drawn at all.
A MilkDrop Fidelity switch restores the engine's earlier look. - The mesh transform is MilkDrop's own, read from MilkDrop 2's source.
radis left
unnormalised as MilkDrop leaves it,angkeeps its(-π, π]range with the centre node pinned,
aspect is applied at the start of the transform and undone at the end so a circle stays a circle
on a wide screen, and the steps run in MilkDrop's order — zoom about the centre of the screen,
then stretch, warp, rotate, translate.aspectxandaspectywere swapped, so a preset
correcting for a wide screen corrected the wrong axis. The blurred copy is darkened at its edges
(b1ed, 68.6% ask for it), and a custom wave is drawn at MilkDrop's amplitude and reads the
spectrum when it asks for the spectrum (23.2% do). - Presets without a shader of their own look as they do in MilkDrop 2. MilkDrop picks a preset's
warp and composite shaders by the file's version, not by whether shader text is present, and
draws the rest with a fixed pipeline built from blend passes. Checked against MilkDrop 2's source
and the original D3D9 code: brighten there is1−(1−c)²and solarize2c(1−c), not thesqrt(c)and4c(1−c)the engine used (410 and 83 presets of a 10,332-preset corpus turn them
on); echo orientation is(int)x % 4; gamma below 1 is ignored while echo is on; and when two
presets whose echoes point different ways blend, the echo fades out and back in instead of
flipping. A preset that leaves out its decay or gamma gets MilkDrop's 0.98 and 2.0 instead of 0,
and so do the other values it leaves out — down to MilkDrop's quirk of reading a missing wave
colour as 0; a rotation centre of 0 stays in the corner. The values MilkDrop keeps out of the
equations (wave scale and smoothing, the volume fade, warp speed and scale) come from the file as
they do there, so a wave scale of 0 flattens the wave (102 presets of the corpus). Rendered
through the engine, every case matches MilkDrop's formula within 2/255. - Preset files are read the way MilkDrop reads them. With fidelity on, keys are case-sensitive,
a key written twice takes the value MilkDrop finds (usually the first), numbered code ends at the
first missing number, integer settings drop their fractions, and equation lines are glued the way
MilkDrop glues them,\\comments included. 32 presets of the corpus read differently; with
fidelity off the old parser stays. - Equations run by MilkDrop 2's compiler rules. With fidelity on, truth and equality tests use
its 0.00001 tolerance,%works on whole numbers without sign,&and|on 64-bit integers,megabufandgmegabufindices are rounded and bounded the way it does,rand(n)returns a
real number (5,361 corpus presets call it), and the compiler's internal names such as_aboeq
run. With fidelity off nothing changes. - Each block keeps MilkDrop's own variables. With fidelity on, per-pixel code and a wave's
per-point code run in their own variable space the way MilkDrop's separate machines do: they see
only what MilkDrop hands them (time, audio, the mesh size, q1..q32 and for waves t1..t8), keep
their own variables andmegabuf, and nothing they write leaks back.reg00..reg99are
shared by every block and preset, so shapes now see the random values init leaves there, andloop/whilestop at MilkDrop's 1,048,576 turns a call. - Composite shaders get the hue colour MilkDrop gives them. MilkDrop passes every composite
shader four slowly drifting corner colours ashue_shader, whatever the preset'sfShader
says;fShaderonly scales them on the fixed pipeline. The engine appliedfShaderto shaders
too, so about 950 presets of the corpus drew without their colour or with part of it, and the
corners were mirrored top to bottom. On the fixed pipeline the colour now goes through MilkDrop's
own draw passes, the wraparound of out-of-range colours included. - Textured shapes, motion vectors, rotation matrices, mesh density, internal resolution scale,
mouse input and preset transitions are all implemented, and each sampler is read with the
filtering and wrapping its name asks for (sampler_pw_mainis point-sampled,sampler_fc_mainis
filtered and clamped — 22.7% of presets read one texture through two different prefixes). - User textures load from your own texture folder. 16.9% of presets ask for an image by name —
sampler_wormslooks forworms.jpg. Preset packs do not ship these files, so point
MilkDrop › Texture Pack at thetexturesfolder of a MilkDrop installation. Without one the
preset still runs, with noise in place of that texture. The textures load wherever the preset is
drawn: the visualizer windows, the panel's live preview, the web overlay — which fetches each
image by name from the stream server, behind its token, and is sent a short digest of the folder
rather than its path — and video export, which waits for a texture before drawing the next frame,
so the same job still gives the same video. - Flash limiting holds on every screen. On by default, it limits how fast the picture's mean
brightness may change, at WCAG 2.3.1's general-flash value: 0.10 of relative luminance per frame
at 30 fps, the frame step it was measured at. The limit used to be per frame, so a faster display
let flashes through faster — measured with a preset that flips between black and white three
times a second, the swing per cycle was 0.714 in the panel's 45 fps preview but 1.000 on a 74 Hz
display, the flash untouched. It is now held per second: 0.43–0.49 in the preview, in 60 Hz and
74 Hz windows, in a 35 fps window and on the web overlay alike. - MilkDrop follows the system's reduce-motion setting. When the operating system asks for
reduced motion (on Windows, Animation effects turned off under Accessibility › Visual effects),
the flash limiter stays on even if it was turned off, loud moments no longer hard-cut, and every
change blends over 5 seconds. Auto advance plans with that longer blend, so a preset is still
shown in full for the time you set. A manual Cut now still cuts. The MilkDrop panel says
whether it is on and why, and Reduce Motion overrides it either way: Always, or Off even
when the system asks. Each screen reads its own system — a web overlay on another machine follows
that machine — and video export follows only Always, so a video never depends on the machine
that made it. Checked in an isolated copy with the setting emulated in the browser engine; the
system's own setting was left alone. - A lost GPU context comes back. A driver reset or a GPU process crash takes every WebGL object
with it, and MilkDrop stayed black until the application was restarted: nothing in the code
listened for it. The engine now holds the loss, asks the browser for the context back and rebuilds
its programs, textures and buffers on the same canvas when it arrives; if it does not arrive
within three seconds — a browser that gave up, or a context lost by hand — it starts again on a
fresh canvas. The running preset survives either way: the same object, the same equation state and
the same clock, so it carries on from where it stopped instead of restarting. What cannot come
back is the feedback buffer's content, which lived in GPU memory, so the picture flows again from
black. Chromium's habit of blocking 3D for a page whose GPU process crashed is turned off, because
that block would leave the recovery with nowhere to go. The GPU self-test loses the context on the
running engine both ways and checks that frames, pixels and the preset's own state come back. - So does every other GPU surface. A real GPU reset takes every context at once, so MilkDrop
coming back was not enough while the gradient background, the 3D geometry mode, the shader modes,
the effect chains and projection mapping stayed black. None of them carries feedback or built-up
state, so each now reports a lost context and its owner builds a fresh one with the same settings:
a layer is rebuilt in place, in the same position and with the same blend, opacity and z-order;
the effect chain keeps its effects. A surface is rebuilt at most every two seconds, so a GPU that
is still restarting does not get a new canvas every frame. The GPU self-test loses the context of
a gradient background and of the effect chain on the running stage and checks both come back with
a picture (brightest sample 175 and 206 of 255, the same as before the loss). - Preset transitions are MilkDrop's dual pipeline. The previous preset does not stop when a new
one loads: it keeps its own object, its own compiled shaders and its own clock, and both presets
run their frame and vertex equations every frame. The two warp meshes are blended per node along a
ramp — a directional wipe, a plasma or a radial sweep, picked at random as MilkDrop picks it — so
one part of the screen turns over before another, and the same ramp is the per-node alpha the two
presets' shaders are drawn with. There is still one feedback buffer and one blur chain, which
is what MilkDrop has. Values that do not move pixels (decay, wave and border colours, blur ranges,
gamma) are blended numerically on a cosine curve; the boolean ones snap. Approximate: if the two
presets use different waveform modes, MilkDrop morphs one shape into the other; here the new
preset's mode is shown for the transition. - What a transition costs, measured. Running two presets is close to exactly twice the work, so
the default is only defensible with a number behind it. At 1280×720 against a 60 fps budget of
16.67 ms, the median frame goes 2.70 ms → 5.20 ms at the default mesh of 64 (31% of the
budget), 0.90 → 1.70 ms at mesh 32, and 5.80 → 11.10 ms at the densest mesh of 96 (67%).
Separately, the first frame of any preset change compiles the new preset's shaders — 9.10 ms at
mesh 64 with a hard cut, 12.10 ms with a transition; at mesh 96 that one frame goes 12.00 → 18.00
ms and drops a frame. So the default is 1.7s, MilkDrop's ownfBlendTimeUser, and automatic
preset advance stays off by default, which means a transition only ever runs when you ask for one. - A preset change no longer stalls the frame. Measured across 900 presets at 1280×720, the
frame that loaded a preset ran a median 17 ms and at worst ~119 ms over its neighbours, and six
changes in ten dropped a frame that would otherwise have held — nine tenths of it the GPU compiling
the new shaders while the frame waited. Where the driver offersKHR_parallel_shader_compilethe
compile now runs in the background and the running preset keeps drawing; the change, transition
included, starts once the new programs are ready, a median two or three frames later. With auto
advance the next preset is chosen a second early and compiled in advance, so the change still
lands on time — on the bar in bar mode — and the other screens prepare the same one. At the
default mesh the changes that drop a frame fell from 61.9% to 4.9% with a hard cut and from 61.7%
to 8.1% with a transition. Video export still waits for each compile, so the frame a preset
appears on never depends on the machine. - A new track can bring the next preset. Next to auto advance, On Track Change moves to the
next preset — in the chosen order, random included — when Now Playing sees a new track. It works
with the timer off, the lock stops it too, and only the leading screen picks, so every screen
changes together. The track already playing when the app opens does not count, nor does the gap
between two tracks. - Favourites, tags and search by author. Star presets in the MilkDrop panel's list, or the one
on screen with Favourite (also from a MIDI or OSC mapping), and give them tags of your own.
Search matches the name, the author and the tags. MilkDrop names are mostly "Author - Title", soauthor:geiss(oryazar:) finds Geiss's presets but not a title that mentions him, and#calm
finds a tag. Show narrows the list to favourites or one tag, Author to one author. Pool
limits auto advance — the timer, hard cuts and track changes — to favourites or one tag, while Previous,
Next, Random and the list still reach every preset. Favourites and tags live in the settings next to
your ratings, not in the preset files, and a pack carries all three: Pack What Is Shown writes
the presets in view with them, and importing the pack attaches them to the new copies. Checked in
an isolated copy: with the pool set to three favourites, the visualizer window went round those
three and nothing else. - Large preset libraries stay light. Every save or delete used to re-read every preset file
and send the whole list, sources included, to the panel, each window and every web client. With
the 10,347 presets of a full MilkDrop library (116 MB) one delete held the app for about 2.4
seconds and the panel used 631 MB. Presets are now read once and kept; a change sends only what
changed. At the same size a save now takes 91 ms and the panel uses 273 MB. Deleting or adding
MilkDrop presets no longer restarts the MilkDrop picture on screen. Web clients get MilkDrop
presets without their sources (271 KB instead of about 30 MB for 2,000 presets), and the web
overlay fetches the source of a preset only when it is about to draw it. - Import a whole MilkDrop library. Import from ZIP Pack, Import from Folder and Search This
Computer in the MilkDrop panel bring in a library in one go: nested folders, the pack's
textures, and — if you want — the pack's category folders as tags. Nothing is copied until you
have seen what will be added (presets, textures, MB, and what will be skipped: MilkDrop 3's.milk2double presets, oversized files, encrypted ZIP entries) and confirmed. Presets with the
same name and content are skipped, so importing a pack twice adds nothing. Textures go into the
app's own folder and are looked up after the texture folder you chose, so a pack'ssampler_wormsworks without choosing a folder. The search looks in the usual Winamp,
foobar2000 and projectM folders and in Downloads, Desktop, Music and Documents, wherever the
system keeps them, and stops after a few seconds; a library it could not finish counting is
scanned in full before you are asked. No preset pack ships with the app. Measured with real
packs: a 9,795-preset folder was scanned in 1.1 s and imported in 6.2 s, and importing it again
added nothing. - Preset thumbnails. The MilkDrop panel's list has a Grid layout: every preset shows a small
picture of itself, so a preset can be found by its look. Each thumbnail is drawn once in the
background — the first two seconds of the preset with the demo sound, from a black screen — kept
in the app's data, and drawn again when the preset or a texture it uses changes. Only the
presets you scroll to are drawn. A visualizer window drawing MilkDrop at the same time barely
noticed: none of its frames took longer than 27 ms. Found while building this: when another
MilkDrop window was drawing and the computer was busy, a MilkDrop picture that had just set up its
buffers (a new window, a resize, a thumbnail, a video export) could start from the other window's
picture. Buffers now start from zeros. - A preset generator of our own. Studio → MilkDrop Preset Generator writes an original
MilkDrop preset from four sliders — energy, warmth, density and motion — and a seed. It runs
offline, and every motion, wave, shape and shader pattern it uses was written for this app: no
line of it longer than 30 characters appears in a 10,332-preset corpus. The preset loads straight
away as a preview without being saved; Save to Library keeps it. Moving a slider keeps the
seed, so you get the same preset with more energy or warmer colours rather than a different one,
and a code such as72-15-60-88-2n9cbrings the same preset back. Nothing in a generated preset
flashes: its colours stay in range at any volume, and invert, solarize and brighten are never
used. Measured on 200 generated presets with silence, the demo sound and a loud bass line: every
shader compiled, and none went black, washed out to white, flashed more than twice a second or
froze. - Mash-ups from your library. The same card builds a preset out of pieces of the presets you
already have: the look (decay, echo, gamma, the main wave), the motion equations, the custom
waves, the custom shapes, the warp shader and the composite shader — each taken whole from one
preset and copied line for line. New Mash-up draws every part at random from the presets the
MilkDrop panel's list shows, so its search and filter apply, and only from presets that have that
part. A single part can be drawn again, or all six can start from the preset on screen; the arrows step
back through earlier mash-ups, and Save to Library keeps one. A mash-up inherits its donors'
looks, so it can come out brighter or darker than any of them. Checked on a 10,332-preset corpus:
a mash-up of one preset is that preset again, and in 5,000 random mash-ups every part was
exactly its donor's. 300 random mash-ups ran in the engine without a single shader failure. - An editor for presets. Studio → MilkDrop Preset Editor opens the preset on screen: frame and
pixel equations, custom waves and shapes, the warp and composite shaders and the main values each
have a tab, and a change shows in the running picture a moment after you stop typing. Errors point
at the preset's own line (per_frame_14) with its own text, not at generated code; shaders are
compiled as you type. Sliders for zoom, warp, rotation, decay and echo say when the preset's
equations rewrite the value every frame. The original is never changed: Save as a New Preset
keeps your version, and only what you changed is written — the rest of the file keeps its bytes. - MilkDrop 2 and MilkDrop 3 rules. A Preset Format setting — Automatic, MilkDrop 2 or
MilkDrop 3 — picks whose file rules a preset is read with: MilkDrop 3's 16 custom waves and shapes
and q1–q64, or MilkDrop 2's four and q1–q32. Automatic reads a preset with MilkDrop 3 rules when
it uses those extensions, and the panel names them. MilkDrop 3's hard-cut modes 1–6 are offered
with its thresholds and delays. Its.milk2double presets load as a frozen blend of their two
presets. Its new waveforms, new transitions andget_fftin shaders are not here yet: nothing
describes how they behave. - Sprites from
milk_img.ini. MilkDrop 2 draws images of your own over the picture during a
show: each one is defined inmilk_img.iniwith an image, code that runs once and code that
runs every frame, and launched by number. Choose the file in the MilkDrop panel and launch from
its list, from a MIDI or OSC mapping, or with MilkDrop's own keys in the visualizer window — K
and two digits launch, SHIFT+K and two digits remove that number, DELETE removes the newest. Up
to 16 run at once; the five blend modes, the colour key, tiling, flipping andburn(the sprite
leaves its image in the feedback and flows with the preset) follow MilkDrop 2's source. Every
screen shows the same sprite,randincluded: the launch carries its seed. Measured in an
isolated copy with three displays, the web output, Spout and the panel preview: all six drew the
probe image at every sample point, a sprite placed withrandsat at the same x/y on all of
them, and a burnt sprite's image stayed where the sprite was after it died. Sprites are a live
tool and are not part of video export. - Auto advance advances. The panel's Auto Advance slider had been there since the engine landed
and nothing ever read it: set to two seconds, the same preset stayed on screen (measured in the
running app — nine seconds, no change). It now moves on every n seconds, in order or at random,
and random never picks the preset already showing, since a "transition" to the same preset changes
nothing on screen. The visualizer does the switching on its own frame clock, so it keeps going
while the panel is closed or covered, and the preset it moves to is not written into the settings
file, which is rewritten in full on every change. The panel's Loaded Preset row shows what is on
screen, and the panel preview follows the visualizer instead of running a sequence of its own. - Preset timing is MilkDrop 2's. Three things MilkDrop 2 does around auto advance were missing,
and now follow its source. The next change comes after the transition time, the interval and a
random extra of up to n seconds, drawn once per preset (MilkDrop's own default is 16 s plus up
to 10 s; ours adds nothing unless asked). A lock stops auto advance and hard cuts, and releasing
it carries on with the time that was left. And a hard cut — off by default, as in MilkDrop —
changes preset with no blend when bass, mid and treble, each against its own long average,
together pass three times a threshold; the threshold doubles on each cut and then falls back, so
a run of bursts is not a run of cuts. MilkDrop calls that fall-back a 60-second half-life, but its
coefficient is 2·ln 2, so the excess actually halves in 30 s; the formula is kept as it is, so a
preset cuts as often here as it does there. A preset'sprogressnow means what it means in
MilkDrop — how far through its scheduled life the preset is — instead of a ten-second sawtooth.
10 of the 23 corpus presets that read it useabove(progress, 0.99)to fade out just before a
change, and the sawtooth made them fade every ten seconds; with auto advance off there is no
scheduled change andprogressstays at 0, as it does in MilkDrop for a locked preset. - Ratings and a history, as MilkDrop keeps them. Every preset carries a rating in its own file
(fRating, 3 when it is missing), and MilkDrop draws its random order from the cumulative
distribution of those ratings: a preset rated 1 comes up a fifth as often as one rated 5, and one
rated 0 never comes up on its own. Random order now works the same way — on by default, as in
MilkDrop, with a switch — and the panel shows the rating you gave the preset on screen as stars you
can change; a preset you have not rated shows none, while random order keeps weighting it by its
own file's rating. Your rating goes into the settings rather than into the preset, because saving a preset
re-sends the whole library, sources included, to every window. Previous and Next now walk the history of
what was actually shown, including what auto advance and hard cuts picked, instead of stepping
through the list from the preset you last clicked; the history keeps MilkDrop's 64 steps. One
difference is deliberate: after going back, a new preset drops the forward part, as a browser
does, where MilkDrop's auto advance would replay it — the history lives in the panel and the pick
is made in the visualizer. - MilkDrop on MIDI and OSC. Controllers could drive the rest of the application but nothing in
MilkDrop. They now have seven MilkDrop actions — next, previous, random, cut now (MilkDrop's H:
the next preset with no blend), lock, rating up and rating down — which run the panel's own code,
so the history, the rating weights and the lock behave the same from a controller; and six
settings: transition time, auto-advance interval, random spread, hard-cut threshold, mesh density
and internal resolution. The last two only ever take the panel's own values: a knob's travel is
split into equal steps, because every value in between would rebuild the mesh or the frame
buffers. - Preset changes on the bar. Auto advance can count bars instead of seconds: every n bars, the
preset changes on the first beat of a bar, and the transition is rounded to whole beats so it
also ends on a beat (1.7 s at 120 BPM becomes three beats, 1.5 s). The tempo is estimated from
the visualizer's own audio, not the panel's — the panel's loop stops while the visualizer covers
it, which is why auto advance runs in the visualizer in the first place — and the BPM lock and
tap tempo are the ones in Tempo & Auto VJ, so there is one tempo lock in the application, not
two. With no tempo to be found the change falls back to time the way Auto VJ does, every twice
as many seconds as bars and at least every 4 s, and the panel says so; otherwise it shows the
visualizer's BPM and bar count. - Every screen shows the same preset. With auto advance or hard cuts on, each visualizer
window, the Spout/Syphon output and the web overlay ran a sequence of its own, so random order
put a different preset on every screen — and even the same preset differed, since its fourrand_presetnumbers and the transition's pattern were drawn separately in each. Now one engine
picks — the first visualizer window, else the Spout/Syphon window, else the panel preview — and
the others show its pick with the same seed, so the samerand_presetand the same transition.
Measured across three windows, Spout, the web overlay and the preview with random order every
2 s: all six agreed on the preset in 58 of 60 samples, the other two falling on a switch, and
presets that drawrand_presetas a flat colour matched to the pixel; before, the six showed 5.7
different pictures per sample on average. MilkDrop › Displays › Each display picks its own brings
back separate sequences. Randomness drawn every frame (rand_frame) still differs from screen to
screen. - The lights can take MilkDrop's colors. The lights could follow the background or the theme,
not what MilkDrop draws. A new color source, MilkDrop picture (live) — in Lighting › Color Source
or straight from the MilkDrop panel — reads the current frame about 30 times a second: shrunk to
64×16 and cut into eight slices from left to right, each slice's color weighted by brightness so
a small bright detail on a dark background still counts, its hue kept and its brightness left to
the lighting mode. Dynamic Lighting, OpenRGB and Art-Net all take it, and OpenRGB now uses the
sampled palette the same way Dynamic Lighting does, where it used to draw the configured
gradient. Measured over Art-Net with a picture red on the left and blue on the right: the first
four of eight fixtures red and the last four blue, where before all eight showed the fallback
color; the window ran at 75.2 Hz with the sampling and 75.0 Hz without. - A MilkDrop layer survives scene transitions. A scene transition used to build every layer of
the arriving scene from scratch, which for MilkDrop means the preset restarting, its feedback trail
vanishing and auto advance falling back to the preset you picked by hand. The dynamic colour theme
changes the palette on every track and the palette counts as a scene change, so with both switched
on this happened on every track — for colours MilkDrop never reads. The layer now stays in the
arriving scene and the leaving one shows the same canvas through a proxy, so MilkDrop keeps
running while the layers around it cross-fade. Measured in the running app, one run, the same
palette change: without the fix a new instance appeared on the hand-picked preset, with it the same
instance kept the preset it was showing. - Presets hear the music the way MilkDrop hears it. MilkDrop computes
bass,mid,treband
their_attversions with a chain of its own, and presets are written against how that chain
behaves. We were deriving them from the visualizer's bands — smoothed twice and divided by a
six-second average — and, fed the same synthetic drum track, that putbasslower just after a
kick than between kicks (0.93×, where MilkDrop gives 2.45×), while the_attvalues did not rise
on a hit at all. With MilkDrop Fidelity on, all six now come from MilkDrop's own chain: the newest
576 samples, a Hann-windowed 1024-point FFT with MilkDrop's equaliser, three bands summed across
the lower half of the spectrum, a fast asymmetric average for_attand a four-second one to
divide by. It matches an independent reference implementation to within 3.2e-6. Two differences
are deliberate and measured: the averages start from the first frame that has sound in it rather
than from zero (MilkDrop's own start throws every value to about 250 for a moment when the layer
was created in silence), and values are capped at 30 — on the test track the music itself peaks
at 11.2 and a drop after an eight-second breakdown at 18.6, so the cap only touches the first
frames back from a long silence, where MilkDrop reaches 234. The Sensitivity slider still scales
how far the values move away from 1: its default of 0.7 is 30% less than MilkDrop, 1 is MilkDrop. - The per-frame variables reset every frame, as MilkDrop resets them. MilkDrop re-seeds every
built-in per-frame variable from the preset file beforeper_frameruns and returnsq1..q32to
whatper_frame_initleft. Our pool persisted instead, soq1 = q1 + x— written by 19.5% of the
corpus — grew without bound instead of giving the same answer each frame. Preset authors' own
variables still persist, as they do in MilkDrop. volandvol_attare what MilkDrop hands a shader, bug included. MilkDrop's shader header
makes them the fourth component of the bass/mid/treb constants, and the line that fills it reads0.3333f * (imm_rel[0], imm_rel[1], imm_rel[2])— a comma operator, so the value is a third oftreb, not the average of the three bands the engine passed. 96 presets (0.93%) read them in a
shader and were tuned against MilkDrop's value. In the equations MilkDrop has novolat all, and
a custom wave or shape sees only the inputs MilkDrop registers for it: the engine also copiedvol,vol_att, the mesh size, the aspect pair and the pixel size into every wave and shape. Run
through the equations with the switch on and off, 19 presets (0.18%) draw a wave or shape
differently, all for one reason — the per-frame code assignsvolas its own variable and a shape
reads it, where MilkDrop gives that shape its own zero. Both follow the MilkDrop Fidelity switch.- A spectrum wave gets MilkDrop's spectrum at MilkDrop's scale. The
0.15multiplier in
MilkDrop was chosen for the magnitude its own FFT produces, so a normalised 0..1 array draws the
right shape at the wrong size. The chain is rebuilt from the source: ±128 sample units, the
two-tap damping, a 576-point Hann envelope, an unnormalised 1024-point FFT and the-0.02·ln((512-i)/512)equaliser, over the newest 576 samples as MilkDrop takes them — it had
been reading the oldest 576 of the 2048-sample buffer, about 30 ms behind the sound.
Approximate: the bin-to-frequency axis, because our samples arrive at the AudioContext rate
rather than MilkDrop's. - Waves read the newest audio, from both channels, aligned the way MilkDrop aligns them. The
default and custom waves were reading the oldest 576 samples of the 2048-sample buffer, about
30 ms behind the sound, with the same mono buffer 128 samples further on standing in for the
right channel. With MilkDrop Fidelity on, each channel's newest 576 samples now go through
MilkDrop's alignment: the window is compared with the previous frame's, coarse to fine over six
halvings, and shifted by up to 95 samples, so a steady tone stands still on screen instead of
starting wherever the window happened to fall. The 96 samples past the 480 that are drawn are
zeroed, as MilkDrop does, and the default wave's vertex counts start from those 480 rather
than 512. A spectrum wave's two values are now the left and right spectra. A third of the
corpus (33.1%) has a custom wave with more than 480 samples, which in MilkDrop reads before the
start of its array; where that read lands on the other channel it is reproduced exactly, and
beyond both channels it reads zero.
Building and distribution
npm run icons
npm run dist:win
npm run dist:mac:arm64
npm run dist:linux
| Platform | Output | Built on |
|---|---|---|
| Windows | CAYADEV Visualizer Setup ….exe (installer), …-portable.exe |
Windows |
| macOS | ….dmg and ….zip (the .app inside) — Apple Silicon |
macOS |
| Linux | ….AppImage and ….deb — x64 |
Linux |
Every platform builds on itself. audify is a native module and cannot be cross-compiled: a
macOS package produced on Windows shows the interface but captures no audio. The GitHub Actions
workflow therefore builds macOS on macos-latest and Linux on ubuntu-latest. Windows is built
locally instead of in CI, because the installer registers the Dynamic Lighting identity and that
needs a certificate the runner does not have — a CI-built installer would be a different product.
macOS first launch
macOS packages are unsigned and not notarised. macOS quarantines unsigned downloads and reports
them as damaged and can’t be opened; right-clicking and choosing Open does not clear that on
macOS 15 or later. Drag the app to Applications and remove the flag once:
xattr -dr com.apple.quarantine "/Applications/CAYADEV Visualizer.app"
It then opens normally every time. Capturing system audio there also needs a virtual device such as
BlackHole.
Linux needs PulseAudio or PipeWire. The .deb declares libpulse0 among its dependencies; the
AppImage expects the same library to already be present.
Publishing the files to a release
The description next to each file in a release's asset list is written withgh release upload file#label. The table lives in a script:
npm run release:assets -- v3.1.3 --dir=<the folder CI artifacts were downloaded into>
It looks for every expected file in dist/ and in the folders given with --dir, refuses to upload
anything unless all of them are present, and re-reads the release afterwards to confirm each label
was written. Add --dry-run to see what would be uploaded, --check to audit a published release,
and --partial when a partial upload really is intended.
Regenerating the screenshots
npm start -- --shots
Renders every panel, scene, clip and mode sheet on this page into docs/screenshots/, in English,
from a synthetic signal. It never captures real audio, never opens the camera, never writes your
settings, and uses typed-in track details rather than whatever is playing. --only=<name> limits it
to matching files.
Tests
npm test
npm start -- --smoke
2787 unit tests, all passing. They are written to check answers, not to exercise lines:
- Formulas are checked against values derived by hand from their definitions — Viviani's curve
staying on its sphere, the torus tube radius, Chladni's m↔n antisymmetry, every attractor staying
bounded and landing inside the view volume. - Tempo is measured against synthetic signals of known BPM (90/120/128/140/174 →
89.8/120.4/127.9/140.0/173.7). - Analysis is tested against signals with known answers: a known chord must come back as that
chord, a 220 Hz tone as 220 Hz. - Art-Net is verified byte by byte against the ArtDMX header.
- Config migration loads 1.3 and 2.0 settings files without losing a value.
- Fuzzing the preset and pack loaders asserts no MilkDrop preset can smuggle JavaScript.
- MCP coverage fails when a new setting or feature is added without a matching tool or path rule.
The GPU self-test runs the real application on a real GPU. It draws every registered visualizer
mode and background and checks that each one builds its canvas and that shader-based modes compiled;
measures that every effect and every 3D formula leaves a non-blank picture; compiles every built-in
Studio shader; loses and restores the WebGL context of MilkDrop, the gradient background and the
effect chain; loads the OBS overlay from the real stream server; switches the interface to English
and scans for untranslated strings; and asserts that automation never opens the camera.
CI runs the unit tests on Windows and Ubuntu with Node 20 and 22 on every pull request.
Project structure
src/
main/ Electron main process: windows, audio capture, IPC, stream and MCP servers
admin/ Control panel
visualizer/ Output window: layer stack, modes, effects
exporter/ Offline, deterministic video export
shared/ Engines with no DOM: spectrum, modulation, analysis, formulas,
transitions, warp, MilkDrop, templates, lyrics, timeline, clip deck
web/ OBS overlay and the phone remote
native/ Audio helpers (per-application capture, Dynamic Lighting identity)
scripts/ Build, release, MilkDrop corpus and render harnesses
tests/ Unit tests, run by `npm test`
docs/ Screenshots
Shared engines are plain arithmetic with no DOM, GPU or audio device, so their tests run in Node.
Shortcuts
| Key | Action |
|---|---|
ESC |
Close every visualization window |
F11 |
Toggle full screen |
Space |
Blackout |
Ctrl + S |
PNG snapshot |
Ctrl + R |
Start / stop recording |
Ctrl + K |
Search all settings (panel) |
Ctrl + Shift + Q |
Close the visualizer when the ESC lock is on |
K + two digits |
Launch a MilkDrop sprite (visualizer window) |
The timeline editor and the clip deck have their own shortcuts, listed in their panels.
Roadmap
ROADMAP.md records what has actually shipped and what each planned release is for —
Timeline and Clip Deck in v3.1.0, cross-platform builds with OpenRGB and Spout/Syphon in v3.1.1, the
MilkDrop shader engine in v3.1.2, per-application audio capture and aspect correction in v3.1.3, and
the streaming overlay and transparency fixes with MilkDrop fidelity in v3.1.4. Next are MilkDrop and
streaming refinements in v3.1.5, a far broader and much faster video export in v3.1.6, the broadcast
layout editor in v3.1.7 and redundancy with frame sync in v3.2.0. It also keeps an honest list of
what is not done, and why.
License
MIT — see LICENSE. Copyright (c) 2026 Çağan Turgut (CaYatur) — CaYaDev.
Keywords: music visualizer · audio visualizer · sound visualizer · VJ software · MilkDrop · projectM alternative · OBS overlay · Spotify visualizer · desktop visualizer · multi-monitor · projection mapping · Spout · Syphon · WebGL · Electron · MCP
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found







































