A real-time, audio-reactive kaleidoscope / tunnel visualizer for Windows and Linux. It listens to whatever is playing on the system (Spotify, browser, foobar2000, a live mic, …), analyses it in real time, and drives a huge library of GLSL shaders whose motion, colour and structure follow the music's rhythm, timbre and mood — beat-driven Rock/Pop/EDM and beatless ambient/drone alike, calming down automatically for speech.
⬇ Download the latest release — no Qt / Visual Studio needed, just run the installer or unzip the portable build. See Quick start.
![]() |
![]() |
![]() |
![]() |
Four of the 1,415 scenes in the scene catalogue — a photograph folded into a kaleidoscope, a loaded 3D model used as a mirror, one used as a shadow puppet, and a hardware-tessellated fjord under the northern lights.
Highlights
- 1,415 scenes + 30 overlay effects + 110 scene transitions, all audio-reactive and image-driven — see the scene catalogue.
- Real signal analysis (beat/onset detection, key & mood, song-structure tracking) drives the visuals, not a generic FFT bar graph — see how it listens to the music.
- A photo library and 157 3D models it can fetch and install for you — see Extra content.
- Synced lyrics, artist photos and the official music video can play alongside the visuals — see Optional online features.
- Control it from a phone: a web remote with zero-config LAN pairing, plus an Android app — see Remote control.
- Stereo-3D output, MIDI control, Spout output for OBS/VJ software, a German or English UI, and an unattended kiosk mode with a crash watchdog.
- Quick start
- Extra content: photos and 3D models
- Controls
- Mood detection, and OSC output for VJ tools
- Presets
- Recording
- Video export
- Setup tool
- Remote control
- Optional online features
- Language
- Build
- Deployment
- Project layout
- Credits and license
- Further reading
KaleidoscopeVisualizer-Setup.exe— regular installer, Start-menu shortcuts for the visualizer, the Preset editor and the Setup tool. It installs for your user, without administrator rights, into%LOCALAPPDATA%\Programs\KaleidoscopeVisualizer, where the program can keep its settings; an older installation under Program Files is offered for removal, and its settings come along.KaleidoscopeVisualizer-portable.zip— unzip anywhere, double-clickKaleidoscope-starten.bat. No installation, nothing written outside the folder.
The installer offers the photo and model packs as ticked options and installs
them for you; see Extra content for the
portable build and for pointing it at your own pictures. It runs without them
either way. Press h any time for the full keyboard reference in-app.
The scenes that fold photographs need photographs, and some scenes place a real 3D model in the shot — a station against a nebula, a capital ship making a slow pass, a chrome torus on a plinth. Both are optional downloads rather than part of the installer: together they run to about 2.5 GB, thirty times the program, and most of it is of no use to someone who only wants the classic visualizer.
The installer offers all four packs as ticked options and puts them in place
for you. Afterwards — or for the portable build, which has no installer —
Download extra content in the Setup tool does the same. By
hand: unpack into the program's Images and Models folders and restart.
| Pack | Contains | |
|---|---|---|
| Photos | 977 images, 593 MB | agate, rust, pigment, soap film, sediment, aurora, craquelure, woven fibre |
| Models: ships | 77 models, 699 MB | capital ships, freighters, couriers, drones |
| Models: stations | 30 models, 259 MB | space stations — the six station families |
| Models: objects | 62 models, 517 MB | sculptures, hi-fi gear, sea creatures, eroded rock, gongs, pierced lattices, and the real-object scenes: rocket and pad, peacock, organ, aqueduct, bells, candles, gears, pendulums, metronomes, seismograph, foundry |
Nothing breaks without them. A scene whose model is missing is skipped when the catalogue is read, the photo scenes fall back to a procedural texture, and the startup log says how many and which folder it looked in. Once the models are there, every genre preset simply has more scenes to draw from.
All of it is generated for this purpose, so there are no rights questions, no
faces and no recognisable subjects to be mangled by a mirror. The models were
mostly generated FOR the scene family that uses them, which is why the fit is
close: the resonant bodies are thin-walled because ModalVibration displaces
along a plate's thickness, and the pierced lattices exist because a shadow play
wants a complicated shadow.
Your own pictures instead: set Photo folder in the Setup tool. That
writes imageDirectory into kaleidoscope_settings.ini, which outranks the
presets — the right place for it, since Presets\*.xml are generated
and would lose the change. Subfolders are searched; .jpg, .jpeg and .png
are recognised. For one run only, Kaleidoscope.exe -f <folder> beats both.
What actually suits this program — format, tone, contrast, composition — is
written down in docs/photo-set-spec.md, with a
checker that scores any folder against it (Tools/check_image_set.py).
Building the packs yourself, from folders you have filled:
.\Tools\make_image_pack.ps1
.\Tools\make_model_pack.ps1| Key | Action |
|---|---|
Q |
Quit |
Esc |
Quit after asking (closes the help box first if it is up) |
Enter, Menu |
Open the on-screen menu (remote control, see below) |
| media keys | ⏭/⏮ next scene, ⏯ freeze, ⏹ blackout |
h |
Toggle the on-screen help (keyboard reference) |
0 |
Open/close the preset menu (see below) |
↑ ↓ |
Move the cursor in whichever overlay menu is open |
Enter |
Take the highlighted entry (cross-fades) |
| type | Narrow an open menu to matching entries |
| wheel | Scroll an open menu; click picks, click outside closes |
i |
Toggle the live audio-feature overlay (incl. FPS) |
d |
Choose the audio source (output / microphone) — overlay; remembered for the next start, and a capture on the default follows a new default output |
↑ ↓ |
Also drive the audio-source cursor while that overlay is open |
p |
Toggle the now-playing track title display |
w |
Lyrics (Internet): off / credits scroll / karaoke — on by default |
Shift+w |
Toggle the karaoke kinetic line-slam pop-in (off by default) |
o |
Artist images (Internet): rotating inset + colour grade — on by default |
n |
Manually advance to the next effect (musical scene change) |
v |
Show the active shader names (debug overlay) |
l |
Toggle the stage lamps / light show (corner cones etc.) |
[ / ] |
Reactivity — less / more audio-driven motion |
, / . |
Trails — shorter / longer feedback trails |
- / = |
Mood — weaker / stronger colour grading |
; / ' |
Latency — visuals earlier / later vs. the heard beat |
b |
Blackout — soft fade to black and back (VJ) |
e |
Freeze — hold the picture (VJ) |
t |
Tap tempo — tap the beat to override tempo detection |
u |
Pin — hold the current effect (no automatic switches) |
f |
Favourite the current effect (persistent selection bonus) |
Space |
Mark / unmark the current scene (shortlist for review) |
Shift+Space |
Save all marked scenes as the Marked preset |
z |
Stereo 3D — cycle off / side-by-side / top-bottom / anaglyph |
c / m |
Stereo depth — weaker / stronger |
a |
Toggle auto-config-by-mood (auto-switch configs) |
g |
Toggle adaptive render scale (auto-FPS) |
j |
MIDI learn — bind knobs/pads to the controls; nothing is bound until learned. midiDevice=<part of its name> in the ini picks the device (the log lists them) |
r |
Toggle recording (full render resolution → mp4) |
y / x |
Arm the instant replay ring / save it as an mp4 |
k |
Save the current look and UI state as the startup default |
s |
Save a PNG screenshot of the picture (no overlays) to Pictures\Kaleidoscope |
| mouse drag | (when not fullscreen) trackball / interaction |
Everything can also be reached from a hardware remote on a living-room PC. Such remotes send ordinary keys: arrows, OK (Enter), Back (Back or Backspace), Esc, usually a Menu key, and the media keys.
OK or the Menu key opens the on-screen menu, drawn large enough to read
from the sofa. ↑/↓ select a row, OK opens a submenu, runs an action or
flips a switch, ←/→ change sliders and choices (and → also opens
submenus), Back goes one level up, Esc closes it. It hides itself after
20 seconds without a key.
| Menu | Contains |
|---|---|
| Presets | every preset; the running one is marked, OK switches to it |
| Scene | next scene, hold scene, favourite, mark, save marked, never show again, undo favourite, forget this song's cues, banned scenes (each one allowed again with OK) |
| Picture & overlays | blackout, freeze, stage lamps, strict light protection, now-playing title, lyrics mode, line slam, artist images, music videos |
| Fine tuning | reactivity, trails, mood colour, latency lead (sliders) |
| Audio | audio source, tap tempo |
| Stereo 3D | mode, depth |
| Automation | pick preset by mood, adapt resolution, rest after silence (off/5/15/30/60 min), sleep timer (off/15/30/60/90 min) |
| Capture | record, instant replay armed / save, screenshot |
| Info & diagnostics | shader names, audio analysis + FPS, keyboard shortcuts, the remote's address (OK shows its QR code), mesh scenes skipped for missing models |
| System | language, save settings as default, install update (when one is found), quit |
The menu works on the same state as the keys and the web remote, so all three
always agree. Esc outside the menu asks before quitting, because on a remote
it sits right next to Back; Q on a keyboard still quits at once. The keyboard
shortcuts all stay as they were -- the menu is for the remote, the letters are
for debugging and live work.
A key whose effect cannot be seen says what it did in a short line at the
bottom of the picture: preset by mood, adaptive resolution, hold scene,
latency, saved as default, favourite (with the taste it has now), tap tempo,
stereo, the overlays' switches, the screenshot's file -- and why n did
nothing when the scene is held or frozen. MIDI learn shows its target until it
is learned. keyFeedback=false in the ini keeps them in the log only. The key
help (h) is sized by the window and breaks into two columns when it has to.
Never again. A scene you do not want in a preset is banned from the menu (Scene) or the remote (it stays out of the rolls for good; a song cue, a jump from the browser or a section replay can still show it). The banned scenes are listed in the menu and dimmed in the remote's browser, and one press allows a scene again. Enough stays in: a ban that would leave fewer than twelve scenes (or a twentieth of the preset) is refused. The favourite can be taken back, and the cues a favourite pressed during a song set can be forgotten.
Light protection. The brightness limiter holds how fast the picture's mean
may rise; since 16.10.2026 it also watches the picture in cells: when a quarter
of the frame flashes three times a second or more -- the threshold of the
photosensitivity guidelines, which a steady mean of two halves flashing against
each other never showed -- the picture dims to 60 % until it stops. The strict
mode (menu, Setup tool, lightProtectionStrict=true) halves the rise and takes
the beat flashes out of the stage lamps and the title.
Both overlay menus — the preset picker (0) and the audio-source picker
(d) — scroll, so they reach entries the digit keys cannot. Anything past
the ninth used to be unselectable, and in the audio menu it was not even
drawn: the hidden-preset debug switch and a saved Marked preset both push
the preset list past nine, and a machine with a few virtual audio cables has
well over nine sources. Each opens on the entry that is currently in use, ↑/↓ (plus PgUp/PgDn/Home/End) move the cursor,
Enter selects, and Esc (or 0 / d) closes without changing anything.
The highlight bar is where Enter would take you; the marker shows what is
actually in use.
Typing narrows a menu to entries containing what you typed — useful once the
device list runs past twenty. Backspace takes a character back, Esc clears
the filter first and closes on the second press. The mouse works too: the wheel
scrolls, a click takes an entry, a click outside closes.
1–9 used to jump straight to a preset and are now unbound: the menu reaches
every entry, so nine keys no longer have to be spent on a shortcut that only
covered part of the list.
Double-click toggles fullscreen. It used to quit the app outright, which
made a slip of the hand end the show; quitting is Esc or q.
Press k to persist the tuning keys (plus render scale) to
kaleidoscope_settings.ini, so they're restored next launch. The i
overlay shows the current FPS — handy for tuning render scale on a target
machine.
One key in that file has no hotkey: calmMotion (default true) keeps the
host's virtual camera completely still — no downbeat punch-in, no kick shake,
no bar sway, no drop rewind, no bass shockwave, no beat-pumped trail warp.
It is on by default because whole-frame jolts make some viewers ill; set
calmMotion=false for the older, livelier camera.
The analyzer estimates the music's mood on Russell's two axes — valence (positive/negative) and arousal (calm/energetic) — and uses it everywhere: scene selection is biased toward matching mood tags, pacing follows arousal, and a global colour grade follows the empirically grounded mapping canon (happy = warm and vivid, sad = bluish and muted, dissonant = harder edges). Every ingredient was measured against an 80-track corpus rather than guessed.
Other software can consume the analysis live: set oscPort in the settings
(or the Setup tool) and the visualizer streams OSC/UDP — /mood/valence,
/mood/arousal, /mood/quadrant, /beat, /audio/bands, /tempo/bpm and
more — to TouchDesigner, Resolume, Max/MSP or anything else that speaks OSC.
The show's state goes along: /scene/name, /preset, /transition/start,
/blackout, and /color/mean — the picture's mean colour for lights that
follow the image, held to the same brightness-rise limit as the picture.
The full story, with the literature and the measurements, is in docs/mood-and-mapping.md.
Everything above is an estimate of music the visualizer only ever hears. A software generator playing its own composition does not have to be guessed at: it knows the bar line exactly and it knows a drop is coming before it lands. If one is driving the sound, it can say so over OSC/UDP, and the scheduler stops guessing:
[General]
cuePort=9000
cueBind=0.0.0.0cuePort=0 (the default) means the feature is off and nothing listens.
cueBind is the interface — 127.0.0.1 for a generator on the same machine,
0.0.0.0 to let one on the LAN (a headset, say) reach it.
Five messages are understood, and nothing else on that port is acted on:
| message | effect |
|---|---|
/phos/bar i |
the bar line a due scene change is quantized to |
/phos/beat i |
keeps the time (tempo and beat phase); never causes a cut |
/phos/section s f |
a section starts (type and energy 0..1) → a scene change |
/phos/drop |
a drop lands on this instant → a hard cut |
/phos/key s |
the key from here, e.g. F# Phrygian |
An external clock. Beat cues keep the time: while they come, tempo and
beat phase follow them (as a tap that keeps tapping), and two seconds after the
last one the analysis takes over again. MIDI clock from a DAW or a DJ program
does the same on the MIDI input (midiDevice): the tempo from its ticks, the
phase once Start or a song position has said where the song is. Both arrive
before the sound the visualizer hears; clockDelay (seconds, default 0.06)
places the beat that much later. externalClock=false leaves the time to the
analysis alone.
The cues feed the same two rising-edge triggers the audio analysis has always
fed, so everything that guards them still guards them: a cue that lands during
a cross-fade cannot retarget it, a cut still has its minimum solo, and camera,
zoom and rotation remain untouched by anything the music does. If the sender
stops — or was never there — the audio analysis takes over again after two
seconds and the program behaves exactly as it did before. Kaleidoscope.exe -q
checks all of that and exits 0 or 1, without opening a window.
The sender this was built for is the Phosphene psytrance generator (its
docs/PLAN.md, section 8.3); the wire format is plain OSC 1.0, so anything
that can send those five messages works. The rest of its family is understood
in its own words as well: Totality (/tot/...), Parhelion (/parh/...),
Ephemeris (/eph/...) and Noctuary (/noct/...) -- their blocks, phases and
scenes become sections, their Camelot keys keys, a Return, a Drop or a PEAK a
drop (Source/CueReceiver.h has the table).
From a file, for a batch render. A rendered track can carry its cues in a
text file instead: one message per line, tab-separated — the second in the WAV,
the address, the arguments (# starts a comment):
0.000 /phos/key F# Phrygian
0.000 /phos/section Intro 0.20
0.000 /phos/bar 0
59.077 /phos/section Drop 0.90
59.077 /phos/drop
Kaleidoscope.exe -x track.wav -k track.cues.tsv then renders the video with
every cut placed by the score: each cue goes in when the WAV reaches its time.
The demo videos of the VRAudio generators (Noctuary, Ephemeris, Phosphene,
Totality, Parhelion) are made this way; their Tools/demo/make_demos.py
writes the file from what each generator's renderer knows about its track.
Presets\*.xml define which shaders are in rotation, their
probabilities, mood tags, and the photo folder (ImageDirectory, shipping as
..\Images) they draw on. These files are GENERATED, so change the folder in
the Setup tool rather than in here — see
Extra content. Switch between them in
the preset menu (0) or from the remote. Included presets, one per kind of
music, each with at least 400 scenes picked by a rating of how well they fit:
- Allround — everything, balanced; a safe default
- Ambient — music without a beat: calm drift, fluid ink, lava, slow light
- Downtempo — the slow beat (chillout, trip-hop, lounge): warm, flowing, colourful
- SpaceAmbient — sci-fi & deep space: starships, planets, space stations, nebulae, black holes, alien worlds
- Cinematic — classical, film music, piano: landscapes, architecture, painting and slow flights, with long scenes and long fades
- Club — aggressive & bright: tunnels, godrays, lattices, analyzers
- Electronic — the synthetic look for techno and electronica: grids, lasers, neon, spectra, data streams, hard geometry
- Psytrance — the driving psychedelic look: tunnels, fractal flights, kaleidoscopes, hard patterns
- Psychedelic — breathing fractals, pills, chrome, plasma, mushrooms
- Noir — dark, high-contrast: noir fractals, dark tunnels, deep drones
- Komplett (hidden) — every scene and overlay in one rotation: the master list the other presets are generated from, and where the editor starts
Every scene re-rolls its own parameters each time it's picked, so one shader yields many different looks over a session rather than repeating itself identically.
Browse the full scene catalogue — all 1,415
scenes, 30 overlay effects and 110 transitions, each with a description and
three example frames. A printable Katalog.pdf ships with every release.
Building your own presets: PresetEditor.exe (its own small Qt app,
bundled with every release) edits Presets\*.xml with a live shader
preview — browse every scene, add it to a preset with its timing/probability,
tune per-parameter ranges against a real preview, and save. It also carries
the project's self-tests (--validate, --roundtrip, --transcheck,
--render) used to catch broken presets and transitions before they ship.
Build it with msbuild PresetEditor\PresetEditor.vcxproj /p:Configuration=Release /p:Platform=x64.
A handful of shaders (ChromeDreams, DiscoGodrays, FlowingWires,
FractalBloom, InsideSystem, NeonTubes, PsychedelicPills, SphereGrid,
TheCore, Vortex, Voyager) are adapted from community shaders by
kishimisu on Shadertoy, CC
BY-NC-SA 4.0 — see Credits and license.
When you want to look at the shaders rather than enjoy them, play
Komplett (start it with -c Komplett, or show hidden presets) and mark what
you see. A preset whose name starts with Test switches the engine into
review mode: every scene in a fixed order (2D alphabetically, then 3D), 25 s
each. The checked-in bench TestAlle was retired in v1.18; make your own by
copying a preset under such a name.
- Marking — press
Spacewhile a scene is up to shortlist it, andShift+Spaceto write every marked scene toPresets\Marked.xmlas a playable preset. Both are on the remote too, so you can mark from a phone while the show runs on a TV. Marks live inkaleidoscope_settings.iniand survive restarts, so an inspection pass can span several sessions. Thevoverlay shows whether the current scene is marked.
So: run Komplett, tap Space on anything that looks wrong, then
Shift+Space and switch to Marked to work through the shortlist.
Recording captures at the full render resolution (not a fixed 720p) and
encodes once, in hardware where available: raw frames are piped straight into
a running ffmpeg, and on stop the video is copied into the container beside
the audio rather than re-encoded. ffmpeg must be on the PATH; without it
the recorder falls back to writing JPEG frames plus a make_video.bat you can
run by hand.
The encoder is probed at runtime, preferring the discrete GPU's block, then
Intel Quick Sync, then software. The output codec defaults to H.264 —
the one every player and editor opens — and can be changed in the Setup tool
or via the videoCodec key in kaleidoscope_settings.ini:
videoCodec |
Notes |
|---|---|
h264 (default) |
Plays everywhere |
hevc |
Roughly 2.5–3× smaller at the same quality; needs the HEVC extension on Windows |
av1 |
Smallest in principle, but on NVIDIA hardware HEVC beat it on both size and quality in our measurements |
If the requested codec has no working encoder on the machine, it says so and
falls back to H.264 rather than failing the recording. KALEIDO_VIDEO_CODEC
overrides the setting for one run, KALEIDO_VIDEO_ENCODER forces one specific
encoder (still verified before use).
KaleidoscopeExport.exe (Start-menu shortcut Video-Export, or
Video-Export-starten.bat in the portable build) turns an audio file into a
video of the show: pick a preset and a file — WAV, MP3, OGG, FLAC or anything
else ffmpeg reads — choose Full HD or 4K and 24, 30, 60 or 120 frames
per second, and it writes an MP4 with the audio in it — named like the audio
file and beside it unless you choose otherwise. The file can simply be dragged
onto the window.
An export is not a recording of the screen. The engine runs on a frame
clock: frame n shows the show at exactly n / fps seconds however long it
took to render, so the frame rate is constant by construction — a shader
compile or a model load costs render time, never picture — and it runs as
fast as the GPU and the encoder allow. On an RTX 5090, Full HD at 60 fps
renders at about 4× real time, 4K at 60 fps at about 2×. The music is analysed
block by block exactly as far as each frame, by the same analyser the live
show uses, and the look is the one kaleidoscope_settings.ini describes
(reactivity, trails, mood, …). An export writes nothing back to it.
| Option | |
|---|---|
| Codec | Automatic takes H.264 up to Full HD (plays everywhere) and H.265 above (half the size at 4K); AV1 for newer devices |
| Quality | Highest, High, Compact — constant-quality levels of the encoder |
| Fade | in from black over the first second, out over the last two (on by default) |
| Title | weaves the file's title and artist tags in at the start — the live show's title reveal |
| Motion blur | renders at 120 Hz and averages the sub-frames of each frame, like a camera shutter: smoother at 24 or 30 fps, but 120 frames to render per second of video |
ffmpeg is required and not bundled: the tool looks on the PATH and in the
usual package-manager folders (winget, scoop, chocolatey), takes the newest
and shows which; winget install Gyan.FFmpeg installs one. The export also
runs from the command line:
Kaleidoscope.exe -c Psychedelic -e track.flac -g 3840x2160 -p 60 -j hevc,title -d video.mp4
-e <audio> exports that file, -g <WxH> sets the size (fullhd and 4k
work too), -p <fps> the frame rate, -d <file> the output (default:
<audio name>.mp4 beside the audio), and -j takes a comma list
of h264, hevc, av1, blur, nofade, title, q=max|high|compact and
cq=N. A score-cue file (-k) works as in a batch render. The window shows a
preview; Esc, closing it, or quit on stdin finishes the file with the frames
so far. Exit code 0 done, 1 cancelled, 2 error; the progress comes as
[export] progress <done> <total> <seconds> <speed> lines on stderr.
Build it with msbuild ExportTool\ExportTool.vcxproj /p:Configuration=Release /p:Platform=x64.
How the frame clock works, and what the encoder settings are based on:
docs/engine-internals.md.
KaleidoscopeSetup.exe (Start-menu shortcut Setup, or
Setup-starten.bat in the portable build) is a small standalone editor for
kaleidoscope_settings.ini — the optional extras have grown numerous enough
(lyrics, artist images, music video, language, web-remote port, render
tuning, …) to deserve a proper on/off panel instead of hunting through
keyboard shortcuts. Changes are saved to the same settings file the main app
reads on startup and take effect the next time it launches, except the
language dropdown, which retranslates the Setup tool's own form immediately
so you can see the result before saving.
Download extra content lives here: tick the photo pack and whichever model
packs you want, and it fetches them from the release page and unpacks them
into Images\ and Models\. Packs already on disk show as installed and are
unticked, so a second visit does not propose re-downloading two gigabytes.
This is the portable build's route to them, since it has no installer.
Photo folder lives here too, and this is the only sensible home for it:
the presets carry a default (..\Images) but they are regenerated from the
catalogue, so a path typed into them would not survive. Leave the field empty
for the bundled images.
Debug: show hidden presets puts the Komplett master back into the menu
and into the remote, so you can reach it without a command line. It is out of
the way by default because it is a reference catalogue, not something to land
on while enjoying the show. The same switch is one line in the ini if
you would rather not open the tool:
[General]
showHiddenPresets=trueRest after silence (Setup tool, or idleMinutes in the ini; off by
default): after that many minutes of digital silence — every band below
about −60 dB, so a quiet drone or a spoken passage never counts — the picture
fades to black, the scenes stop and the window redraws five times a second.
A second of sound, a key or a remote action brings it back with a fade.
idleDisplayOff=true also lets the display sleep while resting; many
projectors fall into standby without a signal and wake only with their own
remote, hence off. The sleep timer in the menu dims the picture over its
last two minutes and then rests the same way, until a key or the remote.
Half the panel's rate for long shows on a shared GPU: frameDivisor=2 in
the ini renders every second refresh (60 fps on a 120-Hz panel). Trails and the
simulations follow the frame time, so the picture moves the same, in fewer
frames.
The settings file is resolved relative to the working directory, one level up from the exe:
Release\Kaleidoscope.exereads the copy in the repository root, the packagedbin\Kaleidoscope.exethe one in the package root. A copy sitting next to the exe is never read. The startup log names the file it actually used (Settings: <full path>), so check there first if an edit seems to have no effect.
Build it with msbuild SetupTool\SetupTool.vcxproj /p:Configuration=Release /p:Platform=x64
(no GL/audio dependency — a plain Qt Widgets app).
A phone-friendly web remote (-t <port>, on by default at
http://<pc>:8080/) gives you a live preview image, preset buttons,
next-effect, blackout, favourite, mark/save-marked, replay, a scene browser you can tap
straight into, and sliders for reactivity/trails/mood/latency — plus all the
toggles from the Setup tool (lyrics mode, artist images, music video,
auto-preset, auto-scale, …). LAN convenience only — no auth, don't expose it
to the internet. Other web pages cannot drive it: an action needs the header
X-Kaleido: 1 (the page and the app send it; a script calling /api/... must
too), reading the state and the preview does not, and a request has to name
this PC — an IP address, localhost or its own name — as its host.
Finding it: the menu's Info page names the address(es) a phone reaches it at -- the PC's real network adapters, cable first, never a VPN tunnel or a virtual switch -- and OK on one shows a card with its QR code: point the phone's camera at it. The very first start shows the card by itself. The remote's screenshot button saves the picture and shows it on the phone.
Zero-touch pairing: the running instance broadcasts itself on the LAN (UDP discovery), so a client never needs the PC's IP typed in by hand. Several PCs or several instances on one PC show up as a picker.
Android app (AndroidRemote\, build instructions)
wraps the same remote in a fullscreen WebView with its own icon and
auto-discovery — no typing an address, and it never needs updating when the
remote grows new controls, since all the logic lives on the PC. Requires
Android 8.0+; allow Kaleidoscope.exe through the Windows firewall
(private networks) the first time so the phone can reach it.
All on by default, all individually switchable from the Setup tool or the web remote, all cached locally so a repeat play needs no network:
- Now playing (
p): the track title/artist is woven through the picture with one of 24 reveal styles, matched to the music's mood. Reads the Windows system media session (Spotify, browsers, most modern players); foobar2000 needs its free Media Controls component; VLC is read from its window title as a fallback. - Lyrics (
w): synced lyrics fetched from a fallback chain of free services (no API key), shown as a scrolling credits band or karaoke-style with the active line highlighted. - Artist images (
o): photos of the current artist, fetched and deduplicated from a few free services, rotating as a small inset with a colour grade pulled from the image. - Music video: for tracks under 20 minutes, the official video is
searched on YouTube (matched by duration and channel, official-video
scoring) and, if found, downloaded once via
yt-dlpand played in sync in the same corner artist images use. Needsyt-dlponPATH; the app runs normally without it, it just skips this one feature.
The UI (on-screen overlays, the web remote page, and the Setup tool) speaks German or English, switchable from a dropdown in the Setup tool — German is the default. The Android app isn't part of that switch; it follows the phone's own system language, the standard Android behaviour.
Windows is the reference build and the only one the releases are made from. Linux and macOS build from CMake; see below.
Requirements
- Qt 6.11 (kit
msvc2022_64), installed atC:\Qt\6.11.1\msvc2022_64 - Visual Studio 2026 (or 2022) — platform toolset v145, target x64
Visual Studio: open Kaleidoscope.sln, select Release | x64, build.
QTDIR defaults to C:\Qt\6.11.1\msvc2022_64 (set in the project); override
it if your Qt is elsewhere.
Command line
$env:QTDIR = "C:\Qt\6.11.1\msvc2022_64"
cmd /c '"C:\Program Files\Microsoft Visual Studio\18\Community\VC\Auxiliary\Build\vcvars64.bat" && msbuild Kaleidoscope.vcxproj /p:Configuration=Release /p:Platform=x64'Qt Creator — Kaleidoscope.pro mirrors the VS project, so the code can
also be browsed and built from Qt Creator with a Qt 6 / MSVC kit; the VS
project remains the primary build (it also runs the auto-deploy).
python Tools/check_build_lists.py keeps the .pro and CMakeLists.txt in step
with it (release_check and the CI run it).
Run — the exe needs the Qt 6 DLLs on PATH (or run windeployqt):
$env:Path = "C:\Qt\6.11.1\msvc2022_64\bin;" + $env:Path
.\Release\Kaleidoscope.exe # windowed 1920×1080
.\Release\Kaleidoscope.exe -b # fullscreen (2nd monitor if present)
.\Release\Kaleidoscope.exe -c darkambient -s 0.5 # named config, half render scaleCommand-line options
| Option | Meaning |
|---|---|
-b |
Start fullscreen (2nd monitor if present) |
-s <factor> |
Internal render scale 0.25–2.0 — lower for weak GPUs, adapts automatically at runtime (key g) |
-c <name> |
Start with the named configuration (e.g. darkambient, normal) |
-m <index> |
Fullscreen on monitor <index> (0-based; implies -b) |
-l |
Log to kaleidoscope.log instead of the console (kiosk) |
-r |
Start recording immediately on launch |
-w <wav> |
Offline: analyze this WAV instead of capturing live audio (test) |
-o |
Spout output: publish the displayed frame (brightness limiter, blackout, titles) as sender "Kaleidoscope"; spoutSource=clean in the ini sends the raw render |
-t <port> |
Web remote port (default 8080; -t 0 disables it) |
-x <wav> |
Batch render: record this WAV to an mp4, then exit |
-k <file> |
Score cues for the -w/-x WAV, from a file (see Score cues) |
-i <sender> |
Spout input: a live sender replaces the photos |
-v <path> |
Play a video (or folder of videos) as the image source |
-3 <mode> |
Stereo 3D: sbs, tb or ana(glyph) |
-f <dir> |
Photo folder for this run (outranks the Setup tool's setting) |
-h |
Print usage and exit |
--schedule <preset> <wav|silence> <hours> <out.tsv> |
The scene plan of a long run, from the real scheduler without a window (first argument; Tools/check_schedule.py checks it) |
For an unattended installation/kiosk, combine -m, -c, -s and -l; the
app suppresses the screensaver/standby while it runs. The fullscreen shortcut
and the packaged fullscreen launcher go through a watchdog that restarts it
after a crash or a hang (the app ends itself when its render timer stands still
for a minute): after 5 s, longer after repeated crashes (up to 5 min) — it no
longer gives up. Every restart is written to watchdog.log; a crash leaves a
crash-<time>.dmp beside the log, which keeps three generations
(kaleidoscope.log.1 … .3). The installer can also start the show at
sign-in. screenName=<part of the screen's name> in the ini picks the output
by name rather than by index, and a projector that is switched off and on
again gets the show back. If the default output device changes
(headphones unplugged, outputs switched), audio capture reconnects on its
own — no manual restart needed. A missing image folder or Presets
folder degrades gracefully (fallback texture / clear error) instead of
crashing.
Shaders and
Presets\*.xmlload from the exe's parent folder, so run it fromDebug\/Release\.
Kaleidoscope.vcxproj stays the Windows build; everywhere else there is a
CMakeLists.txt, which refuses to configure on Windows so the two cannot
drift apart.
Debian/Ubuntu:
sudo apt install qt6-base-dev qt6-base-dev-tools qt6-multimedia-dev \
libgl1-mesa-dev libglu1-mesa-dev libpulse-dev cmakecmake -S . -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build -jThe program looks for its assets one level above the working directory, the
same convention the Windows package uses, so run it from a subfolder:
cd build && ./Kaleidoscope.
What differs from Windows:
| Linux | macOS | |
|---|---|---|
| Audio capture | the default sink's PulseAudio monitor (PipeWire's pulse server serves it too) | needs a virtual loopback device (e.g. BlackHole) plus PulseAudio; without one, use -w/-x |
| Compute-shader effects | yes (OpenGL 4.3) | no — macOS froze OpenGL at 4.1, so those effects take their fragment fallbacks |
Spout in/out (-o, -i) |
no — Windows-only technology | no |
| Track title / lyrics / artist images | no — these read the Windows now-playing service | no |
| MIDI input | no | no |
Everything else — the full scene catalogue, the 3D models, recording, the web remote, the OSC output — is the same.
macOS is untested: the code compiles for it and the platform branches are written, but no one has run it on a Mac yet.
deploy.ps1 builds a fully self-contained package that runs on any 64-bit
Windows PC without Qt or Visual Studio installed:
powershell -ExecutionPolicy Bypass -File .\deploy.ps1 -BuildThis produces dist\KaleidoscopeVisualizer\ (verified to run with Qt
removed from PATH) and dist\KaleidoscopeVisualizer-portable.zip. If
Inno Setup is installed, it also compiles
installer.iss into dist\KaleidoscopeVisualizer-Setup.exe; otherwise build
that later with ISCC.exe installer.iss. The Preset editor, the Setup tool
and the video export tool are bundled automatically when their own Release
builds exist.
Top-level folders:
Source\— the C++ core: audio capture/analysis (AudioAnalyzer), now-playing/lyrics/artist-image/video fetching (NowPlaying,TrackMedia,VideoPiP), MIDI, the render pipeline (RenderPipeline,EffectShader), config loading, the web remote (WebRemote), Spout I/O, and the shared UI-string table (Strings).Scene2D\/Scene3D\— 352 + 241 scene shaders (fragment-only effects vs. real vertex/geometry/tessellation-shader 3D scenes).FX\— 29 full-time overlay passes (incl.FxPlain, the neutral pass-through most of the time uses).Transitions\— 83 shaders that blend outgoing → incoming scene on a scene change.Engine\— internal pipeline passes (mood grade, feedback trails, bloom, the GPU fluid/reaction-diffusion/smoke simulations, compute kernels).PresetEditor\,SetupTool\andExportTool\— the standalone companion tools (see above, above, above).AndroidRemote\— the Android remote app (no Gradle; plain SDK tools).Presets\*.xml— presets;ThirdParty\SpoutGL\— vendored Spout2 SDK;docs\— this repo's documentation and the scene catalogue;Tools\—verify.ps1(smoke/roundtrip/transition self-tests) and the catalogue/icon generators.
Full engine architecture and per-technique notes (OIT, shadow maps, compute → indirect draw, tessellation, …): docs/engine-internals.md.
MIT, with one exception: the eleven adapted Shadertoy shaders
named in Presets remain
under kishimisu's original CC BY-NC-SA 4.0 (non-commercial, share-alike);
see LICENSE and each file's own header.
External services used by the optional online features: lyrics from LRCLIB, NetEase, and lyrics.ovh; artist images from Deezer, TheAudioDB, and iTunes; music videos via yt-dlp against YouTube; Spout output/input via the vendored Spout2 SDK (BSD-2).
Built and tested on Qt 6.11.1 / Visual Studio 2026 (toolset v145), x64, NVIDIA OpenGL 4.6. Rendering targets OpenGL 4.3 core; all shaders are GLSL 330 core.
- docs/engine-internals.md — how the audio analysis actually works (beat/onset/key/mood/section detection, the mapping layer), and per-scene engineering notes (graphics techniques, debugging stories) for contributors and the curious.
- docs/Catalog/Katalog.md — every scene, overlay and transition with a description and example frames.



