Feature Flags
iRaceDeck ships two plugins — the Elgato Stream Deck plugin and the Mirabox VSD Craft plugin. They share most code, but the two hosts use different SVG engines (Stream Deck is QT 6.7+, Mirabox is QT 5), so some features work on one platform and are silently ignored on the other.
Feature flags let us gate those features at build time: unsupported code is stripped from the bundle, and Property Inspector controls that would have no effect are hidden. Flags also provide a lightweight way for contributors to test in-development features locally without shipping them to everyone.
How the flags are structured
Section titled “How the flags are structured”Each plugin has a committed platform-features.json:
packages/iracing-plugin-stream-deck/platform-features.jsonpackages/iracing-plugin-mirabox/platform-features.json
The file has two top-level keys:
capabilities— raw SVG engine support (svgFilters,svgMasks,svgPatterns). Source of truth.features— product-level flags that depend on one or more capabilities (e.g.,borderGlow). These are the ones you’ll typically toggle.
Example (Mirabox, glow disabled):
{ "capabilities": { "svgFilters": false, "svgMasks": false, "svgPatterns": false }, "features": { "borderGlow": false }}Where the flags take effect
Section titled “Where the flags take effect”The plugin build pipeline reads the merged flags once and fans them out to three places:
- Bundle code —
@rollup/plugin-replacesubstitutes__FEATURE_BORDER_GLOW__withtrue/falseat compile time. Terser then drops unreachable branches, so disabled code doesn’t ship. - Property Inspector HTML — the same flags are passed into EJS templates as
locals.platform. Controls wrapped in<% if (locals.platform?.features?.borderGlow !== false) { %>disappear from the compiled HTML. - Runtime
config.json— the merged flags are written tocom.iracedeck.sd.core.sdPlugin/bin/config.jsonas afeatureFlagsfield. Readable at runtime viagetFeatureFlag("borderGlow")/getPlatformFeatures()from@iracedeck/deck-coreif a dynamic check is ever needed.
Overriding flags locally
Section titled “Overriding flags locally”For local testing — without editing committed files — create feature-flags.local.json at the repo root:
{ "features": { "borderGlow": false }}Each plugin’s build deep-merges this file on top of its own committed platform-features.json. Any keys you don’t include fall through to the committed values. The file is listed in .gitignore, so it never lands in a commit.
You must rebuild for the override to take effect (pnpm build or restart pnpm watch:*). There’s no runtime reload — flags are baked into the bundle.
Always restart the watcher after editing a flag file. Rollup resolves the flags once when its config module loads, and that resolution is held for the lifetime of the watcher — editing platform-features.json or feature-flags.local.json mid-watch will trigger a rebuild but the output will still reflect the flag values from watcher startup.
Unknown keys in the local file are ignored with a warning during the build — watch the console for [platform-features] feature-flags.local.json has unknown keys (ignored): … to catch typos.
A committed feature-flags.local.json.example at the repo root documents the shape; copy it if you’d like a starting point.
Typical use cases
Section titled “Typical use cases”- Test a Mirabox-only scenario on your Stream Deck build. Set
features.borderGlow: falsein the local file, rebuild Stream Deck — the glow code and controls disappear from your Stream Deck build too. Flip it back and they return. - Develop a beta feature locally without shipping it. (Once issue #363 lands.) Commit the feature with its flag defaulting to
falseeverywhere. Testers opt in viafeature-flags.local.json. - Strip an unsupported capability when experimenting with a new host or SVG engine — set the relevant
capabilities.*flag tofalseand see what still works.
Current flags
Section titled “Current flags”| Flag | Category | Stream Deck | Mirabox | Purpose |
|---|---|---|---|---|
svgFilters | capability | true | false | SVG <filter> support (required by feGaussianBlur, etc.) |
svgMasks | capability | true | false | SVG <mask> support |
svgPatterns | capability | true | false | SVG <pattern> support |
borderGlow | feature | true | false | The glow halo around border overlays — uses feGaussianBlur and only renders on Stream Deck |
Adding a new flag
Section titled “Adding a new flag”Short version (see the in-repo rule .claude/rules/platform-feature-flags.md for full details):
- Add the flag to both
platform-features.jsonfiles with the correct per-platform default. - For a new
features.*flag, add it to thePlatformFeatureFlagsinterface inpackages/deck-core/src/plugin-config.ts. For a newcapabilities.*flag, add it to thePlatformCapabilitiesinterface in the same file. - Declare the
__FEATURE_*__or__CAPABILITY_*__ambient global inpackages/icon-composer/src/platform-features.d.ts. - Add a replace entry in both plugin
rollup.config.mjsfiles. - Gate the affected code and/or PI partials (
locals.platform?.features?.yourFlag !== false, orlocals.platform?.capabilities?.yourCapabilityfor capability checks). - Seed the default in
test-setup.tsand cover both thetrueandfalsepaths withvi.stubGlobal.