Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@ available and unchanged.
| | Native module | `OnlineUnlockStatus` bridge |
| --- | --- | --- |
| **Form** | Drop-in JUCE module | Copy-paste reference header |
| **Built-in UI** | Yes (polished, animated, themeable) | No (you build it) |
| **Built-in UI** | Yes (polished, animated, themeable: `config.palette` + `config.fonts`) | No (you build it) |
| **JUCE integration** | Native Moonbase API | `juce::OnlineUnlockStatus` wrapper |
| **JUCE version** | 8.0.4+ | 7+ |
| **Device fingerprint** | Spec v2 (`mbd2_`), cross-SDK; scoped `mbd2s_` on mobile | Spec v2 (`mbd2_`), cross-SDK; scoped `mbd2s_` on mobile |
Expand Down
35 changes: 32 additions & 3 deletions docs/juce-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,9 +159,38 @@ gating decisions (read it on the message thread).
Everything in `ActivationConfig` after the connection fields is brand/UI: product +
manufacturer name, `accent` colour, the Moonbase co-brand badge (`showMoonbaseBadge`), the
`trialLengthDays` + `trialFeatures` list (shown on the Trial / Expired screens),
`enableOffline`, and the `activationUrl`. For deeper re-skinning, mutate `ActivationLookAndFeel::palette`
(every colour is a token) or bundle real Inter / Space Mono typefaces and point the
`heading` / `body` / `mono` font helpers at them.
`enableOffline`, and the `activationUrl`.

For a deeper re-skin, `config.palette` holds every other colour in the UI as its own
token, and `config.fonts` takes your typefaces for the three font roles:

```cpp
config.accent = juce::Colour(0xffe4a03c);

config.palette.backgroundTop = juce::Colour(0xff2a1c12); // see ActivationTheme.h
config.palette.panelTop = juce::Colour(0xff1e1610); // for the full token list
config.palette.textPrimary = juce::Colour(0xfff7ecdc);
config.palette.onAccent = juce::Colour(0xff2a1a08); // text drawn on the accent

// Bundle faces with juce_add_binary_data and hand them over per role. Do this
// rather than setting a default LookAndFeel: inside a DAW that one is shared
// with the host and every other plugin in the process.
config.fonts.heading = juce::Typeface::createSystemTypefaceFor(
BinaryData::InterBold_ttf, BinaryData::InterBold_ttfSize);
config.fonts.body = juce::Typeface::createSystemTypefaceFor(
BinaryData::InterRegular_ttf, BinaryData::InterRegular_ttfSize);
config.fonts.mono = juce::Typeface::createSystemTypefaceFor(
BinaryData::SpaceMono_ttf, BinaryData::SpaceMono_ttfSize);
```

Set both before you construct the `ActivationComponent` (or pass the config to
`ActivationDialog::show`, which also frames its window in `palette.backgroundBottom`).
The component reads the theme once, when it builds its LookAndFeel and pre-renders its
icons, so a palette changed afterwards would only reach half the screen.

Leave any token alone and it keeps the built-in design's value, so a single line is a
valid theme. `config.fonts.makeFont` is the escape hatch when one typeface per role is
not enough: set it and it decides every font the UI asks for, by role and height.

## Device identity

Expand Down
4 changes: 3 additions & 1 deletion modules/moonbase_licensing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,9 @@ richer gating, and `onActivationChanged` fires whenever it changes.
- **Branding** — everything in `ActivationConfig` after the connection fields is UI:
names, accent colour, logo `Drawable`, overridable copy (`config.strings`), trial
length + feature list, the removable Moonbase badge, and the activation URL.
Re-skin deeper via `ActivationLookAndFeel::palette`.
Re-skin deeper with `config.palette` (every other colour, one token per role) and
`config.fonts` (your typefaces for heading / body / mono). Both are read when the
component is built, so set them on the config rather than after the fact.
- **Refresh entitlements** — `controller().refreshLicense()` re-validates online so a
freshly purchased sub-product/upgrade loads without a restart (async, silent, with an
optional completion callback).
Expand Down
16 changes: 15 additions & 1 deletion modules/moonbase_licensing/juce/ActivationConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

// Everything needed to wire up + brand an activation flow. The connection
// fields configure the Moonbase SDK; the branding fields drive the built-in UI
// (the Solstice design's product name, accent, trial copy, co-brand badge).
// (the Solstice design's product name, accent, palette, typefaces, trial copy,
// co-brand badge).

#include <chrono>
#include <functional>
Expand All @@ -20,6 +21,7 @@
#include <juce_graphics/juce_graphics.h>
#include <juce_gui_basics/juce_gui_basics.h>

#include "ActivationTheme.h"
#include "JuceMetadata.h"
// Named by resolvedDeviceIdResolver(). Included here rather than relied on from
// the module umbrella so this header stays usable on its own.
Expand Down Expand Up @@ -85,6 +87,18 @@ struct ActivationConfig
juce::String manufacturerName; // defaults to JucePlugin_Manufacturer; shown under the product name
juce::Colour accent = juce::Colour(0xff186cdc); // Moonbase blue

// Every other colour in the UI, one token per role, and optional typefaces
// for its three font roles (heading / body / mono). Both default to the
// built-in design, so override only what you want to change:
//
// config.palette.backgroundTop = juce::Colour(0xff1a1512);
// config.fonts.body = juce::Typeface::createSystemTypefaceFor(...);
//
// See ActivationTheme.h for the full token list. Read once, when the
// ActivationComponent is constructed.
ActivationPalette palette;
ActivationFonts fonts;

// Where the customer exchanges their machine file for a license file during
// offline activation. Defaults to "{endpoint}/activate" when left unset.
juce::URL activationUrl;
Expand Down
105 changes: 105 additions & 0 deletions modules/moonbase_licensing/juce/ActivationTheme.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#pragma once

// Colour + typeface tokens for the built-in activation UI, from the "Solstice
// Activation" design.
//
// Set them on ActivationConfig (config.palette, config.fonts) before you build
// an ActivationComponent. The component reads the theme once, when it creates
// its LookAndFeel and pre-renders its icons, so a theme handed over afterwards
// would only reach half the screen.

#include <functional>

#include <juce_graphics/juce_graphics.h>

namespace moonbase::juce_integration {

// Every colour in the UI except the accent, which stays its own
// ActivationConfig field because it is the one-line way to brand the flow.
// Override the tokens you care about and leave the rest at the design's values:
//
// config.palette.backgroundTop = juce::Colour(0xff1a1512);
// config.palette.textPrimary = juce::Colour(0xfff7f2ea);
struct ActivationPalette
{
// Backdrop + plugin window.
juce::Colour backgroundTop { 0xff0e1626 };
juce::Colour backgroundMid { 0xff070a11 };
juce::Colour backgroundBottom { 0xff04060b };
juce::Colour panelTop { 0xff0d121c };
juce::Colour panelMid { 0xff080b13 };
juce::Colour panelBottom { 0xff06090f };
juce::Colour panelBorder { 0x14ffffff };
juce::Colour hairline { 0x1affffff };
juce::Colour panelShadow { 0x73000000 }; // soft drop shadow under the panel
juce::Colour overlayDim { 0x94000000 }; // scrim when config.overlayBackdrop is set

// Surfaces inside the panel.
juce::Colour cardFill { 0x06ffffff }; // license/seat/notes cards, drop zone, feature field
juce::Colour trackFill { 0x12ffffff }; // unfilled part of a progress bar
juce::Colour skeleton { 0x10ffffff }; // loading placeholder bars
juce::Colour scrollThumb { 0x80ffffff };
juce::Colour scrollTrack { 0x1affffff };

// Text.
juce::Colour textPrimary { 0xfff5f8fb };
juce::Colour textBody { 0xffcdd8e6 };
juce::Colour textBright { 0xff9fb3cc };
juce::Colour textSecondary { 0xff768aa4 };
juce::Colour textMuted { 0xff5a6b82 };

// Controls.
juce::Colour ghostFill { 0x0affffff };
juce::Colour ghostBorder { 0x21ffffff };
juce::Colour ghostHover { 0x14ffffff };
juce::Colour link { 0xff6aa8ff };
juce::Colour onAccent { 0xffffffff }; // text + icons drawn on an accent fill
juce::Colour seatEmpty { 0x1affffff }; // seat pips this license has not used

// Motion: the panel's breathing top-edge glow and the activation spinner.
juce::Colour glow { 0xff82cef1 };
juce::Colour spinnerTrack { 0x26ffffff };

// Status.
juce::Colour success { 0xff34d27b };
juce::Colour successFill { 0x2416a34a };
juce::Colour successBorder { 0x5916a34a };
juce::Colour trial { 0xffeab308 };
juce::Colour trialBright { 0xfff5c542 }; // bright end of the trial progress gradient
juce::Colour onTrial { 0xff131519 }; // text drawn on top of a `trial` fill
juce::Colour error { 0xfff08a8a };
juce::Colour errorStrong { 0xffdc5050 }; // expired bar + the pill washes derived from it
juce::Colour errorDeep { 0xffb9444c }; // dark end of the expired progress gradient
juce::Colour dangerFill { 0x14dc5050 };
juce::Colour dangerBorder { 0x4cdc5050 };
};

// Optional typefaces for the UI's three font roles. Leave a role null and it
// falls back to the platform default (sans, sans Bold, monospaced).
//
// Bundle your own with juce_add_binary_data and hand them over here rather than
// setting a process-wide default LookAndFeel: inside a DAW that default is
// shared with the host and every other plugin loaded in the same process.
//
// config.fonts.body = juce::Typeface::createSystemTypefaceFor(
// BinaryData::InterRegular_ttf, BinaryData::InterRegular_ttfSize);
struct ActivationFonts
{
enum class Role
{
heading, // titles, buttons, pills. Supply a bold face: no style is applied on top.
body, // paragraphs, labels, links
mono // device id chip, license file names
};

juce::Typeface::Ptr heading;
juce::Typeface::Ptr body;
juce::Typeface::Ptr mono;

// Last-word hook, for when a single typeface per role is not enough (a
// variable font, per-size style choices, your own juce::Font cache). When
// set it decides every font the UI asks for, and the fields above are unused.
std::function<juce::Font(Role role, float height)> makeFont;
};

} // namespace moonbase::juce_integration
Loading
Loading