Config template variables: {{product_name}} resolves from project-config.json and {{version}} resolves from project-config.json.
LumaScope is a production-minded example project demonstrating how to build a Windows spectrum-analyzer audio product with JUCE 8. It ships as a VST3 plug-in and a standalone application, uses a React/TypeScript Material UI interface hosted in JUCE's WebView2, and demonstrates a portable Lemon Squeezy and Cloudflare Workers-based activation system.
Core value: A developer can clone the project and build, understand, provision, and run the complete analyzer and licensing stack without reconstructing hidden infrastructure or architecture decisions.
| Phase | Status | What it delivers |
|---|---|---|
| 1 | ✅ Complete | Reproducible Windows build shell, embedded React/MUI WebView, typed native/web bridge |
| 2 | ✅ Complete | End-to-end VST3 spectrum analyzer — windowed FFT, log-mapped bins, smoothing, canvas renderer |
| 3 | ✅ Complete | Standalone Windows device capture (input + WASAPI loopback) |
| 4 | ✅ Complete | Cloudflare Worker + D1, Lemon Squeezy webhook ingestion |
| 5-6 | Complete | Lemon Squeezy cloud activation, one-machine licensing, offline grace |
| 6.5 | Complete | Centralized product/build/cloud configuration with generated native, UI, Worker, and PowerShell consumers |
| 7 | 🔜 Planned | Release hardening, CI, documentation, handoff proof |
Both the VST3 plug-in and standalone application are fully functional. The VST3 analyzes host audio with passthrough; the standalone monitors selectable input devices or Windows system output through WASAPI loopback. A compact source strip lets you choose between Input Device and System Output modes.
The Cloudflare-based activation infrastructure and native offline licensing flow are implemented and documented. See cloud infrastructure, activation API, and configuration reference for provisioning, deployment, and rebranding instructions.
Host DAW ──→ LumaScopeAudioProcessor (VST3)
Standalone ──→ SourceController ──→ LumaScopeAudioProcessor
├── JuceInputSourceAdapter (input devices)
└── WasapiLoopbackSourceAdapter (system output)
│ Audio callback (real-time safe)
│ ├── Windowed FFT (juce::dsp)
│ ├── Log-frequency bin mapping
│ ├── One-pole smoothing/decay
│ └── Lock-free SPSC mailbox
│
└── LumaScopeAudioProcessorEditor
Message-thread poller ──→ WebView (React/MUI canvas)
Typed JSON bridge (protocol v1)
- Real-time safety: The audio callback never allocates, blocks, performs I/O, or touches the WebView. Analyzer data crosses threads through a bounded lock-free atomic mailbox.
- Snapshots: The processor owns the analyzer and publishes complete
SpectrumSnapshotstructs. The editor polls these on a timer (not the audio thread) and converts them to closed JSON bridge events. - Bridge protocol: Versioned, typed, closed-schema JSON events over JUCE native events. No string-built JavaScript evaluation. See bridge protocol.
| Technology | Version | Purpose |
|---|---|---|
| JUCE | 8.0.14, pinned | VST3/standalone shell, audio, DSP, WebView |
| C++ | C++20 | Real-time DSP, host integration, licensing |
| CMake | 3.22+ | Reproducible native builds |
| MSVC | VS 2019 toolset | Windows compiler (Ninja presets also work with VS 2022) |
| React + TypeScript | Pinned | Embedded application UI |
| Material UI | Current @mui/material |
Accessible controls, layout, theming |
| Vite | Pinned | Frontend dev/build |
| WebView2 | Pinned SDK, Evergreen runtime | Windows WebView backend |
| Technology | Purpose |
|---|---|
| Cloudflare Workers + D1 | Webhook ingestion, activation, validation, entitlement storage |
| Wrangler | Worker deployment, migrations, secrets |
| Lemon Squeezy | Purchase and entitlement authority |
| Ed25519 (Web Crypto) | Signed local entitlement tokens |
The project uses one Context7 MCP server with three pinned library IDs:
/websites/juce_master— AudioDeviceManager, FFT/windowing, WebView, thread handoff/janwilczek/juce-webview-tutorial— CMake, WebView2, embedded assets, JUCE modules/websites/mui_material-ui— TypeScript, theming, responsiveness, CSP
├── plugin/ JUCE VST3 + Standalone target (CMakeLists.txt, sources)
│ ├── include/ Public headers (Processor, Editor, Analyzer, Bridge, Standalone, WebResources)
│ ├── source/ Implementation files
│ │ └── Standalone/ Standalone-only source (controller, adapters, WASAPI loopback)
├── ui/ React/TypeScript/Vite frontend workspace
├── worker/ Cloudflare Worker activation service
├── cmake/ CMake modules (Config, CPM, Dependencies, WebBundle, templates)
├── infra/ Cloudflare infrastructure scripts (bootstrap, deploy, teardown, verify)
├── scripts/ Build, test, validation, and packaging scripts
├── docs/ Design docs (DSP, bridge protocol, activation API, cloud infra, development)
├── tests/ Native (CTest), frontend (Vitest), and Worker (Vitest) tests + fixtures
├── .planning/ GSD phase plans, state, and roadmap
├── project-config.json Centralized product identity and branding
└── project-config.schema.json JSON Schema for project configuration
From a fresh PowerShell terminal at the repository root:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/check-environment.ps1
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/bootstrap.ps1 -Preset vs2019-debug
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/test-all.ps1The bootstrap checks prerequisites, runs npm ci, downloads pinned JUCE 8.0.14 and WebView2 SDK 1.0.4022.49, configures CMake, and builds the Standalone, VST3, and native tests. It does not install system software. Pinned dependencies are cached in ignored .deps/ and ui/node_modules/ directories.
Launch the authoritative embedded Debug application:
& .\build\vs2019-debug\plugin\LumaScope_artefacts\Debug\Standalone\LumaScope.exeExpected footer: Embedded UI · Bridge ready. Use the source strip to select an input device or system output and start monitoring.
The standalone application supports two source modes:
- Input Device — Monitor a microphone, audio interface, or other recording device managed by JUCE.
- System Output — Monitor Windows render endpoints through shared-mode WASAPI loopback without requiring a "Stereo Mix" device.
Source preferences persist between launches. If the saved source is unavailable, the app starts in a stopped state and asks you to choose a source. See standalone startup guide for details.
Start the fixed loopback server in one terminal:
npm.cmd --prefix ui run dev -- --host 127.0.0.1 --port 5174 --strictPortThen configure, build, and launch the explicit development preset in another terminal:
cmake --preset vs2019-vite
cmake --build --preset vs2019-vite --target LumaScope_Standalone --parallel 4
& .\build\vs2019-vite\plugin\LumaScope_artefacts\Debug\Standalone\LumaScope.exeExpected footer: Vite development · Bridge ready. Edit ui/src/components/AnalyzerStage.tsx while both processes run to verify hot reload.
See development for the full workflow and troubleshooting for diagnostics.
| Target | Format | Description |
|---|---|---|
LumaScope_Standalone |
Standalone EXE | Analyzer as a desktop app — owns device capture |
LumaScope_VST3 |
VST3 DLL | Analyzer as a DAW plug-in — consumes host audio |
LumaScope_All |
Both | Convenience target for building everything |
LumaScopeNativeTests |
Executable | Native CTest suite for DSP, licensing, bridge, and analyzer core |
| Preset | Build type | Dev server | Use case |
|---|---|---|---|
vs2019-debug |
Debug | None (embedded) | Default development and testing |
vs2019-vite |
Debug | http://127.0.0.1:5174 |
Frontend hot-reload development |
vs2019-release |
Release | None (embedded) | Production builds |
Target names, artifact directory names, branding, version strings, local storage filenames, Worker names, and token type values come from project-config.json. Run node scripts/generate-all-config.mjs after edits; see configuration reference.
Phase 2 VST3 validation uses the automated suite plus pluginval when available:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/test-all.ps1
cmake --build --preset vs2019-debug --target LumaScope_VST3 --parallel 4
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scripts/validate-plugin.ps1The test suite covers:
- DSP correctness: Deterministic tone frequencies within expected bins, full-scale level within ±1.5 dB, silence at configured floor, no NaN/infinity output
- Robustness: Zero-sized blocks, sample-rate changes, channel-layout changes, denormals, overlapping hops
- Profiles: Distinct behavior across Musical (default), Measurement, and Fast profiles
- Lifecycle: Audio continues correctly while editor is closed, reopened, resized, or destroyed
- pluginval: Automated VST3 validation with headless CI support
scripts/test-all.ps1 allows missing pluginval for local development but prints that validation was skipped, not passed. For release evidence, provide pluginval with -PluginvalPath or PLUGINVAL_EXE, then complete the Ableton-preferred smoke in VST3 smoke test.
| Decision | Rationale |
|---|---|
| Windows-only v1 | Reduces host, device, WebView, installer, and licensing test scope |
| VST3 + Standalone | Plug-in consumes host audio; standalone owns device capture |
| React/MUI in WebView2 | Modern UI stack with JUCE 8 native integration |
| CMake (not Projucer) | Reviewable, automatable, CI-friendly builds |
| Lock-free SPSC mailbox | Bounded audio-thread → UI-thread handoff without allocation or blocking |
| Canvas spectrum renderer | Bounded renderer nodes instead of hundreds of DOM elements per frame |
| Ed25519-signed local entitlements | Offline verification without embedding server secrets |
| Cloudflare Workers + D1 | Small operational footprint, portable account provisioning |
| Pinned dependencies | Reproducible builds — no floating master/latest |
| No secrets in Git | Account IDs, credentials, signing keys stay server-side |
For implementation details see analyzer DSP contract, bridge protocol, and development workflow.
| Phase | What it delivers | Depends on | Status |
|---|---|---|---|
| 1 | Reproducible build shell, embedded WebView2, typed bridge | — | ✅ Complete |
| 2 | End-to-end VST3 spectrum analyzer | Phase 1 | ✅ Complete |
| 3 | Standalone Windows device capture (input + WASAPI loopback) | Phase 2 | ✅ Complete |
| 4 | Cloudflare Worker + D1 provisioning, Lemon webhook ingestion | Phase 1 | ✅ Complete |
| 5 | One-machine activation service (signed entitlements) | Phase 4 | Complete |
| 6 | Native offline licensing with 7-day grace | Phase 5 | Complete |
| 6.5 | Project configuration centralization | Phase 6 | Complete |
| 7 | Release hardening, CI, documentation, handoff proof | Phases 3, 6 | 🔜 Planned |
See roadmap and requirements for complete details.
GNU General Public License v3.0 — see LICENSE.
This project uses JUCE, which is available under the GPLv3 in its open-source edition. Both the example code and the linked JUCE library are GPLv3-compatible. Commercial use of the combined work requires a JUCE Pro license.