SoundVisualizer

mcp
Guvenlik Denetimi
Basarisiz
Health Uyari
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 6 GitHub stars
Code Basarisiz
  • 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 Gecti
  • Permissions — No dangerous permissions requested

Bu listing icin henuz AI raporu yok.

SUMMARY

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.

README.md
CAYADEV Visualizer logo

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.

Latest release
Downloads
License: MIT
Platform
Tests
Electron

Download for Windows
Download for macOS
Download for Linux

Run from source ·
Features ·
FAQ ·
Türkçe

CAYADEV Visualizer showreel: a MilkDrop preset, a tunnel, a 3D Lorenz attractor, a music video layout, synthwave and a drum & bass honeycomb, all reacting to music

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 on main; 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, on 127.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

MilkDrop preset Aurora Hyper Tunnel
Lorenz attractor in 3D Plasma
Synthwave Klein bottle
Music video layout: Label Card Now Playing with album art
Hyper Tunnel 3D attractor
Tunnel Geometry
Drum & Bass MilkDrop feedback
Drum and bass template MilkDrop

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
Centre bars with a logo on a neon plasma gradient Rainbow frequency bars on a soft gradient Circular spectrum with a logo
Mirrored bars Wave Sunset wave
Mirrored bars on an ocean gradient Rainbow waveform on a night gradient Warm mirrored waveform on a sunset gradient

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

  1. Pick one or several displays from the Displays menu at the top, then one or more
    audio sources under Audio.
  2. Click Open Visualizer. The visual opens full-screen on every selected display.
  3. Change anything on the right — it applies immediately and saves itself.
  4. Or start from a finished look: Library → Templates has 72 of them.
  5. For streaming, turn on Output → Streaming Output and paste the address into an OBS
    Browser Source.
  6. 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, then
npm run check:runtime. Behind a corporate proxy that breaks certificates, set
NODE_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

Live meters Chroma wheel
Deep analysis panel 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

Every visualizer mode

All 43 backgrounds

Every background

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
MilkDrop panel MilkDrop preset editor

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 in scripts/, 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.
  • .milk and .milk2 3.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:geiss finds Geiss's
    presets, #calm finds 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 textures folder, and launch
    milk_img.ini sprites 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
Layers panel Effects panel
  • 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

Modulation matrix

  • 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

Klein bottle Trefoil knot tube
Lorenz attractor Chladni figure

3D geometry panel

  • 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
Studio Caustics
  • 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, and sv_media for 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
  • MilkDrop Preset Generator and Editor live here too — see MilkDrop.

Scenes, templates, transitions and colour

Templates Scene transitions
Templates Transitions
Aurora Drum and bass
Gala Stained glass

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.

Label Card Minimal White
Baseline Bars Amber Room

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 with album art Audio-reactive 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 as
    sv_media.

Show control: timeline, clip deck, Auto VJ, MIDI and OSC

Timeline Clip Deck
Timeline editor 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.

MIDI, OSC and MCP on the Control page

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

Output page: streaming, Spout and Syphon, displays and the floating window

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=0 or ?transparent=1 to 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=1 to 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

Projection mapping

  • Corner pin as a true homography, with the denominator written into gl_Position.w so 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

Recording and 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 into
mcp-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_state returns 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_layer and sv_get_layer_stack return layer
    position, settings and per-layer effects.
  • sv_get_preview adds 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_audio returns level, bass, mid, treble, BPM and confidence from the same meter the panel
    draws. sv_get_now_playing returns the current track. sv_list_audio_sources lists the
    configured inputs.
  • sv_list_scenes and sv_get_scene read saved scenes. sv_list_modes lists every visualizer and
    background id, layer kind and blend mode; the mode and layer tools reject an id it does not list.
    sv_list_effects lists the global chain,
    each layer's chain, and the 40 built-in effect types. sv_list_presets lists library presets
    and user colour palettes. sv_list_displays lists screens.
  • sv_get_output_status reads which visualizer windows are open, the stream switch, port and LAN
    flag, and the Spout/Syphon name. sv_get_timeline, sv_get_clipdeck and sv_get_autovj read
    those panels. sv_get_config reads the whole configuration or one dotted path.

Apply

Uses what is already saved.

  • sv_apply_scene loads 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_template applies a built-in template by id or name. sv_set_visualizer_type and
    sv_set_background_type switch to an existing mode id. A Studio shader is shown with type
    custom and its presetId. sv_set_layer_enabled shows or hides a layer and turns the stack
    on. sv_set_crossfade sets the A/B fader from 0 to 1.
  • sv_trigger_clip fires one clip-deck slot by row and column. sv_stop_clips stops every playing
    slot. The grid stays as saved. Both need the admin window open.
  • sv_set_effect_enabled and sv_set_effect_param change a global effect already on the chain.
    The layer pair does the same for one layer. sv_set_modulation_enabled turns the modulation
    matrix on or off. sv_set_macro sets one existing macro fader.
  • sv_load_preset copies an existing library preset into the live MilkDrop source.
    sv_apply_color_preset paints an existing user or built-in palette onto the background gradient.
    sv_set_milkdrop_cycle sets how the library advances: auto next, order, source, tag, unit, bar
    count, track advance and hard cut.

Write

Creates and edits.

  • Scenes: sv_create_scene stores the current look under a new name, sv_update_scene overwrites
    one, sv_rename_scene renames, sv_delete_scene removes.
  • 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_text edits the text overlay, including a lyrics or now-playing source. sv_set_logo,
    sv_set_media and sv_set_geometry edit those blocks.
  • Effects: sv_add_effect and sv_remove_effect on the global chain, sv_add_layer_effect and
    sv_remove_layer_effect on 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_route and sv_remove_modulation_route edit routes.
  • Presets: sv_save_preset writes a file in the preset store. Shader text with no kind is saved as
    a Studio visualizer (kind visualizer, engine shader). Any other save with no kind is
    MilkDrop. sv_delete_preset removes a file. sv_set_milkdrop_source writes MilkDrop source into
    the live show. sv_create_color_preset saves a user palette of at least two colours.
    sv_delete_color_preset removes a user palette.
  • Auto VJ: sv_set_autovj sets enabled, source, interval, unit, order, BPM lock, palette source
    and per-layer visualizer targets.
  • Export and recording: sv_start_export renders 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_export stops a running export. sv_export_json
    writes the scene list, or the full settings, to a path, with no dialog. sv_save_snapshot writes
    the live picture to a path as a JPEG. These three tools take only an absolute local path with
    the matching extension: .mp4 for the video, .json for the settings, .jpg or .jpeg for the
    picture. Network paths and addresses such as tcp:// are refused. sv_record_start and sv_record_stop drive 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_output opens the visualizer on the chosen displays. Passing a display id replaces the
    selected set. sv_close_output closes visualizer windows. sv_set_displays chooses displays and
    leaves the windows as they are.
  • sv_set_stream changes the OBS and browser stream. sv_set_texture_share changes Spout and
    Syphon. sv_set_aspect changes aspect correction. sv_set_power changes the frame-rate cap,
    the render scale and keepAwake, which keeps the display awake while a visualizer window is open.
  • sv_set_floating changes floating-window preferences, including opacity and click-through.
    sv_set_floating_open opens or closes that same picture-in-picture window.
  • sv_set_window_mode sets a transparent background, the transparency threshold and taskbar cover.
  • sv_set_lighting changes Windows Dynamic Lighting. sv_set_openrgb changes OpenRGB.
    sv_set_artnet changes Art-Net. sv_set_audio_sources replaces the input mix.
  • sv_set_mapping writes 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_transport plays, pauses, stops or seeks the timeline through the admin transport.
    The admin window has to be open.
  • sv_set_blackout takes on, off or toggle and leaves the stored scene in place.
    sv_set_blackout_transition sets 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 and
transition objects need Full. A path the table does not know needs Everything. The paths
mcp.*, 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

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 to 127.0.0.1 only, 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_frame and per_pixel equations drive a real warp mesh with feedback, including
    megabuf/gmegabuf, loop, while, exec2/exec3 and 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.
  • .milk import, 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 eval and 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 in scripts/, 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 (fZoomExponent and fWaveParam, one of which
    66.6% of presets rely on); the warp mesh ran in a vertically mirrored space, so dy, cy and the
    direction of rotation were flipped (48.8% use dy or cy); the warp ripple used invented
    constants and ignored fWarpScale and fWarpAnimSpeed (79.9% and 44.0%); the waveform ignored
    fWaveSmoothing (79.0%), a custom wave's own smoothing, and bModWaveAlphaByVolume (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. rad is left
    unnormalised as MilkDrop leaves it, ang keeps 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. aspectx and aspecty were 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 is 1−(1−c)² and solarize 2c(1−c), not the
    sqrt(c) and 4c(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,
    megabuf and gmegabuf indices 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 and megabuf, and nothing they write leaks back. reg00..reg99 are
    shared by every block and preset, so shapes now see the random values init leaves there, and
    loop/while stop 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 as hue_shader, whatever the preset's fShader
    says; fShader only scales them on the fixed pipeline. The engine applied fShader to 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_main is point-sampled, sampler_fc_main is
    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_worms looks for worms.jpg. Preset packs do not ship these files, so point
    MilkDrop › Texture Pack at the textures folder 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 own fBlendTimeUser, 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 offers KHR_parallel_shader_compile the
    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", so
    author:geiss (or yazar:) 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
    .milk2 double 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's
    sampler_worms works 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 as 72-15-60-88-2n9c brings 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 .milk2 double presets load as a frozen blend of their two
    presets. Its new waveforms, new transitions and get_fft in 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 in milk_img.ini with 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 and burn (the sprite
    leaves its image in the feedback and flows with the preset) follow MilkDrop 2's source. Every
    screen shows the same sprite, rand included: 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 with rand sat 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's progress now 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 use above(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 and progress stays 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 four
    rand_preset numbers 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 same rand_preset and 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 draw rand_preset as 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, treb and
    their _att versions 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 put bass lower just after a
    kick than between kicks (0.93×, where MilkDrop gives 2.45×), while the _att values 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 _att and 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 before per_frame runs and returns q1..q32 to
    what per_frame_init left. Our pool persisted instead, so q1 = 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.
  • vol and vol_att are 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 reads
    0.3333f * (imm_rel[0], imm_rel[1], imm_rel[2]) — a comma operator, so the value is a third of
    treb, 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 no vol at all, and
    a custom wave or shape sees only the inputs MilkDrop registers for it: the engine also copied
    vol, 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 assigns vol as 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.15 multiplier 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 with
gh 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.

cayadev.com

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

Yorumlar (0)

Sonuc bulunamadi