A high-performance home for the music you already own.
Luminous is a fast, local-first player for your own audio library. Built for anyone who wants the convenience of a modern streaming app without giving up ownership of their music. Turn a folder of files into a library you'll enjoy browsing and listening to.
Issues - file a bug report or a feature request
Luminous Discussion - announcements, general discussion, Q&A, Show and Tell
Luminous doesn't accept PRs as this is a hobby project that I enjoy working on in my spare time.
| Platform | Download |
|---|---|
| Windows | Microsoft Store (recommended — installs and updates automatically) .exe / .msix (manual/sideloaded install) Portable .zip (no install; keeps your library and settings in a data folder beside the app) |
| Linux | .deb / .rpm / Flatpak for your distro AppImage (runs on any distro; add an empty portable file beside it for portable mode) |
- Ten UI locales: English (CA/US/UK), French (CA/FR), Spanish, German, Italian, Russian and Ukrainian
- Cosmetic add-on themes, including the free Mothman theme on the Microsoft Store
- Large-library performance: faster scanning and WebDAV sync on network drives, with remote-deletion detection
- Parametric EQ editor: free-frequency bands, drag-to-edit response graph, user presets and AutoEq headphone profile import
- Auto Continue, richer lyrics (word-by-word sync,
.srt/.vttsidecars, timing offset) and Love plus 5-star ratings with ListenBrainz/MusicBrainz sync - Portable mode and a portable ZIP release for Windows
- AppImage release for Linux
"Isn't this just a web wrapper?" Not in the Electron sense. Tauri renders the UI in the OS's own webview (WebView2 on Windows, WebKit on Linux/macOS) instead of bundling a full Chromium, so there's no shipped browser engine inflating the binary or idling in RAM. And the UI is the only part that's web tech — audio decoding/output, DSP, the library scanner, and the SQLite index all run as native Rust off the UI thread, driving the frontend through events rather than the other way around. See below for how the two sides split.
Luminous splits cleanly along the Tauri boundary: a Svelte 5 frontend handles UI, state, and rendering, while a Rust backend owns everything performance- or system-sensitive — audio decoding and playback, the SQLite-backed library index, file scanning, and OS media integration. The two sides talk over Tauri's IPC layer, with the frontend invoking commands and the backend emitting events for things like playback position, scan progress, and now-playing metadata. Keeping decoding, DSP, and disk I/O in Rust off the UI thread is what lets a multi-thousand-track library scan, gapless-playback, and real-time visualizers stay smooth at once.
The IPC commands are deliberately deep: each one owns a whole workflow rather than forwarding a single field. The backend owns the built-in Queue (bootstrapped at startup, exposed via an is_queue flag — the frontend never infers it from a name), applies equalizer changes as one whole-config call, and keeps every dynamic playlist — genre/decade/BPM auto playlists and user smart playlists alike — always complete: whenever the library or a song's stats change, a backend reconciler immediately appends newly-matching songs and evicts stale ones, syncing the live play order without ever reshuffling it. There is no refill logic, and no such setting, anywhere in the frontend.
luminous/
├── crates/ # Engine crates with no Tauri/SQLite dependency
│ ├── luminous-audio/ # Playback engine: Symphonia decode, CPAL output, gapless/crossfade, spectrum
│ └── luminous-equalizer/ # Biquad DSP: 10-band graphic & up-to-20-band parametric filters
├── features/ # BDD Gherkin Feature Specifications
├── src/ # Svelte 5 + TypeScript Frontend
│ ├── lib/
│ │ ├── components/ # PlayerBar, Visualizers, Equalizer, LyricsView, TagEditor, etc.
│ │ ├── locales/ # UI translations (English CA/US/UK, French CA/FR, Spanish, German, Italian, Russian, Ukrainian)
│ │ ├── stores/ # Global stores (player, collection, navigation, windowLayout, playlists, theme, i18n, prefs)
│ │ ├── types/ # Frontend interfaces
│ │ └── utils/ # Shared utilities (color parsing, filter parsing, lyrics, stats, etc.)
│ └── routes/ # Layouts and navigation views
└── src-tauri/ # Tauri + Rust Backend Core
├── src/
│ ├── addons/ # Cosmetic add-on themes: signed bundles, Store entitlement, key cache
│ ├── audio.rs # Edge of the playback engine: Song → Track, pipeline info
│ ├── band_waveform.rs # Layered low/mid/high frequency-band waveform analysis scanner
│ ├── collection.rs # Lofty scanner & folder watcher (query/reconcile/watcher split into collection/)
│ ├── covermanager.rs # Cover art extractor and iTunes search API fallback
│ ├── db.rs # SQLite schema migration & connection pool
│ ├── filter_parser.rs # Search filter syntax parser (artist:, album:, year:, etc.)
│ ├── install_format.rs # Distro/package format detection for the updater
│ ├── lib.rs # Library entry point, background loops, & IPC registry
│ ├── loudness.rs # EBU R128 loudness analysis & ReplayGain fallback
│ ├── lyrics.rs # LRCLIB & Lyrics.ovh client integrations
│ ├── main.rs # Binary entry point invoking luminous_lib::run()
│ ├── media_session/ # OS media transport integration (SMTC, MPRIS2, Now Playing)
│ ├── models.rs # Shared structs and types
│ ├── musicbrainz.rs # MusicBrainz lookups, OAuth2 login, artist events
│ ├── organizer.rs # Tag-based file/folder reorganizer
│ ├── player.rs # Playback controller (Shuffle, Repeat, Next/Prev)
│ ├── playlist.rs # Playlist manager & Queue abstraction (auto-sync/dynamic/import-export/undo split into playlist/)
│ ├── playlist_parsers.rs # M3U, M3U8, PLS, and XSPF import/export
│ ├── ratings_sync.rs # Two-way rating/Love sync with ListenBrainz & CritiqueBrainz
│ ├── stats.rs # Play counts, ratings, and history tracking
│ ├── subsonic/ # Subsonic/Navidrome media-server sync
│ ├── tageditor.rs # lofty tag reader & writer
│ ├── tags.rs # Genre/tag browsing over the existing songs.genre column
│ ├── tray.rs # System tray icon, menu, and minimize-to-tray behavior
│ ├── waveform.rs # Background audio peak analyzer
│ ├── webdav/ # WebDAV library sync and tag probing
│ └── commands/ # Tauri IPC command handlers
└── Cargo.toml # Rust dependencies (cpal, symphonia, rusqlite, lofty, rustfft)
Luminous is a cross-platform application that can be built and run on both Linux and Windows.
Ensure the required build tools, GTK, WebKit, ALSA, and SSL development headers are installed:
- Ubuntu/Debian:
sudo apt update sudo apt install -y build-essential curl wget file libssl-dev libgtk-3-dev libwebkit2gtk-4.1-dev libsoup-3.0-dev libayatana-appindicator3-dev librsvg2-dev libasound2-dev pkg-config cmake
- Arch/CachyOS:
sudo pacman -S --needed base-devel curl wget file openssl gtk3 webkit2gtk-4.1 libappindicator-gtk3 librsvg pkg-config alsa-lib cmake
- Bun: Install the JavaScript runtime & package manager:
curl -fsSL https://bun.sh/install | bash - Rust: Install the Rust toolchain:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
bun install
bun run install:git-hooks # sets core.hooksPath to use the repository's tracked .githooks/pre-commit hook
bun run tauri devProduction bundles include updater artifacts, which must be signed. If you haven't generated a signing keypair yet, see Generating an Updater Signing Key below first.
bun run tauri buildThis produces .deb/.rpm/AppImage on Linux.
Download and install the Visual Studio Installer. Select the Desktop development with C++ workload and ensure the MSVC C++ build tools are checked.
Install the JavaScript runtime, package manager, and Rust toolchain
winget install Oven-sh.Bun Rustlang.RustupRun the following commands in your terminal (e.g., PowerShell or Command Prompt):
bun install
bun run tauri devProduction bundles include updater artifacts, which must be signed. If you haven't generated a signing keypair yet, see Generating an Updater Signing Key below first.
bun run tauri buildLuminous's tauri.conf.json has bundle.createUpdaterArtifacts set to true, so bun run tauri build signs every bundle it produces. Without a signing key in the environment, the build fails. Official releases are signed with a repository secret (see .github/workflows/release.yml), but for local builds you need your own keypair:
- Generate a keypair (you'll be prompted to set a password, or pass
--cito skip it):This writes the private key tobunx tauri signer generate -w ~/.tauri/luminous.key~/.tauri/luminous.keyand prints the corresponding public key. - Set the private key and its password as environment variables before building:
On Windows (PowerShell):
export TAURI_SIGNING_PRIVATE_KEY="$(cat ~/.tauri/luminous.key)" export TAURI_SIGNING_PRIVATE_KEY_PASSWORD="your-password"
$env:TAURI_SIGNING_PRIVATE_KEY = Get-Content -Raw "$HOME\.tauri\luminous.key" $env:TAURI_SIGNING_PRIVATE_KEY_PASSWORD = "your-password"
- Run
bun run tauri buildas usual. Your own key won't match theupdater.pubkeybaked intotauri.conf.json, so a locally-built app can't verify updates signed by the official release key (and vice versa) — that's expected for local builds and only matters if you're testing the updater flow itself.
Luminous uses automated tests at both the frontend (Svelte 5) and backend (Rust) layers.
Frontend tests are written with Vitest and test component rendering, Svelte 5 stores, and state updates with mocked Tauri APIs.
To run the frontend test suite:
bun run test:runTo run the standard cargo unit test suite:
cd src-tauri
cargo testThis also runs the Gherkin feature specs under features/ — each .feature file has a matching test in src-tauri/tests/, so no separate command is needed to exercise them.