A JUCE 8 standalone GUI application that doubles as a reference implementation of the Moonbase C++ activation SDK.
HALO is presented as if it were a harmonic saturator plug-in — it has a transfer-function display, a Drive knob, stage toggles, Tone/Mix knobs, an animated I/O meter — but it does not process audio. Everything visible is decorative. The point of the project is the surrounding license-gate workflow: how a JUCE app talks to Moonbase to activate, persist a JWT, validate it on startup, and revoke it.
On startup the bridge runs a synchronous local check of the cached JWT
(signature + device fingerprint + expiry) so the UI unlocks immediately, then
kicks off an online re-validation against the Moonbase API on a background
thread. Within a configurable throttle window (online_validation_min_interval,
default 5 minutes) the API call is skipped; beyond it the SDK refreshes the
token. A online_validation_grace_period (default 7 days) lets the app stay
unlocked through transient transport failures — past that, the user is bounced
back to the activation screen.
The build produces a single drag-and-droppable artefact — no installer:
| Platform | Output |
|---|---|
| macOS | build/HALO_artefacts/Release/HALO.app |
| Windows | build/HALO_artefacts/Release/HALO.exe |
| Linux | build/HALO_artefacts/Release/HALO |
moonbase::juce_bridge::MoonbaseUnlockStatus— JUCE-side wrapper around Moonbase's JWT/browser activation flow, subclassingjuce::OnlineUnlockStatus.MoonbaseJuceFingerprintProvider— sources the device fingerprint fromjuce::SystemStats::getUniqueDeviceID().applyJuceMetadata(options)— populates Moonbase metadata from JUCE's system/host helpers.tryLoadStoredLicenseAsync— non-blocking startup validation.beginActivation()→pollPendingActivation()— the browser-based activation handshake.revokeActivationAsync()— wired to a Sign out menu item behind the settings cog.file_license_store— persists the validated JWT under the platform's per-user app data directory (~/Library/Application Support/Corino/HALO/on macOS).
The SDK is configured against the Corino demo tenant API at
https://corino-demo.moonbase.sh (product halo). When the user clicks
Activate, the Moonbase merchant routes the browser to the customer-facing
landing page at corino.moonbase.sh for sign-in / purchase / trial
fulfilment — the API host and the landing host are intentionally different.
brew install cmake ninja openssl@3 nlohmann-json
cmake -B build -S . -G Ninja
cmake --build build -jThe first configure pulls JUCE 8.0.4 and moonbase-cpp v3.0.0 via FetchContent (~80 MB). First build takes a few minutes while JUCE compiles. Subsequent rebuilds are fast.
On systems where /usr/bin/c++ is paired with a stale macOS SDK you may need
to point CMake at a working sysroot, e.g.:
SDKROOT=$(xcrun --sdk macosx --show-sdk-path) cmake -B build -S . -G NinjaOpenSSL is statically linked (OPENSSL_USE_STATIC_LIBS=TRUE) so the resulting
.app does not depend on Homebrew paths — the only non-system dependency is
/usr/lib/libcurl.4.dylib, which ships with macOS.
The build is unsigned; macOS will quarantine it on download. For local use, ad-hoc sign it:
codesign --force --deep -s - build/HALO_artefacts/Release/HALO.appRequires Visual Studio 2022 + vcpkg for libcurl/OpenSSL/nlohmann_json:
vcpkg install curl[ssl] openssl nlohmann-json --triplet x64-windows-static
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=path\to\vcpkg.cmake `
-DVCPKG_TARGET_TRIPLET=x64-windows-static
cmake --build build --config Releasesudo apt install build-essential cmake ninja-build libcurl4-openssl-dev libssl-dev nlohmann-json3-dev
cmake -B build -S . -G Ninja
cmake --build build -j- Launch the app. The activation screen appears (no stored license).
- Click Activate → a browser window opens at
corino.moonbase.sh(the Corino landing page, served by the Moonbase merchant). - Sign in / fulfil the activation in the browser.
- Within ~1 second the app flips to the plugin UI.
- Quit and relaunch — the app skips the activation screen, running the local
JWT check synchronously and then revalidating against the API in the
background. The license lives at
~/Library/Application Support/Corino/HALO/license.mb. - Open the cog menu → License details… to inspect the active license, or Sign out (revoke activation) to release the seat on the server and clear the local license.
.github/workflows/ci.yml runs on every pull request (and on push to main)
and builds HALO on both macos-14 and windows-2022, including the same
portability checks the release pipeline runs (otool -L on macOS; dumpbin /DEPENDENTS allow-list on Windows). It doesn't publish anything — it's purely
a "this branch can still ship" gate.
CI and release share the underlying build logic via composite actions under
.github/actions/build-halo-{macos,windows}/, so a green CI run is a real
guarantee the release workflow can produce binaries.
.github/workflows/release.yml builds HALO on a macOS runner and publishes it
straight to the Moonbase tenant as a new product release, following the
GitHub Actions guide.
- In the Moonbase tenant dashboard, create a merchant API key with permission to manage product downloads.
- In this repository → Settings → Secrets and variables → Actions, add a
secret named
MOONBASE_API_KEYcontaining that key. - Confirm
MOONBASE_TENANT_HOSTandMOONBASE_PRODUCT_IDat the top of the workflow match the SDK config insrc/license/HaloLicenseBridge.cpp(default:corino-demo.moonbase.sh/halo).
git tag v1.0.1
git push origin v1.0.1The workflow
- Builds
HALO.apponmacos-14, ad-hoc signs it, and zips it withditto -c -k --keepParentso the bundle structure and xattrs survive. POST /api/downloads/prepare?contentType=application/octet-stream→ gets a signed upload URL and content key.PUTthe zipped bundle to the signed URL.POST /api/products/halo/releases/new?publishImmediately=truewith the release payload (version: { major, minor, patch },downloads: [{ name, platform: "Mac", key }]).
You can also run the workflow manually from the Actions tab — supply the
version (1.2.3) and choose whether to publish immediately or leave the
release as a draft for review in the Moonbase dashboard.
Builds run in parallel on macos-14 (arm64) and windows-2022 (x64). The
publish job waits for both, then posts a single release with two downloads
attached. Windows uses vcpkg in manifest mode (vcpkg.json at the repo
root) with the x64-windows-static triplet so the .exe is a single file
with no runtime DLL dependencies. A vcpkg GitHub-Actions binary cache makes
repeat installs of curl/OpenSSL/nlohmann-json fast.
A Linux build can be added as another build-* job following the same
pattern; the publish-release payload just grows another entry in the
downloads array.
CMakeLists.txt # FetchContent JUCE + moonbase-cpp, juce_add_gui_app
resources/fonts/ # Bundled fonts (Space Grotesk, JetBrains Mono, Inter)
src/
Main.cpp # START_JUCE_APPLICATION(HaloApplication)
HaloApplication.{h,cpp} # DocumentWindow at 760×460, non-resizable
MainComponent.{h,cpp} # Owns the bridge, swaps Activation ↔ Plugin
HaloLookAndFeel.{h,cpp} # Bundled-font wiring
Branding.h # Palette + font names + background painter
ActivationScreen.{h,cpp} # CTA → bridge.beginActivation() → poll
PluginScreen.{h,cpp} # Transfer curve + knobs + footer
license/
MoonbaseJuceBridge.h # Vendored copy from moonbase-cpp v3.0.0
HaloLicenseBridge.{h,cpp} # Demo-tenant wrapper around MoonbaseUnlockStatus
ui/
HaloKnob.{h,cpp} # Conic-gradient knob (segmented approximation)
TransferCurve.{h,cpp} # tanh curve + animated dot
StageToggle.{h,cpp} # Preamp / Head / Bias pill row
MiniMeter.{h,cpp} # Footer IN/OUT animated meter
PresetSelector.{h,cpp} # Header preset row
The visual identity is recreated from the Corino Plugins design canvas:
warm-dark gradient background, amber accent (oklch(0.78 0.16 65)), Space
Grotesk for display type, JetBrains Mono for technical labels, Inter for body.
This sample is MIT-licensed — see LICENSE. JUCE 8 is licensed separately — see JUCE's
licensing terms; this project consumes JUCE under the GPLv3 path implicit in
FetchContent. The Moonbase SDK is MIT-licensed. Bundled fonts ship under
their respective SIL OFL licenses.
