Custom Theming System
The BloomSpark Maps SDK features a comprehensive, token-based theming engine. Styling variables are declared as TypeScript interfaces, compiled, and injected as CSS Custom Properties (variables) onto the document's :root node, enabling instant application-wide theme flips.
🎨 Theme Tokens Interface
export interface SpatialTheme {
/** Mode name */
mode: 'light' | 'dark';
/** Core application styling hex declarations */
colors: {
primary: string; // default '#2393d4' (BloomSpark Blue)
primaryReshape: string; // default '#086bb7' (Focused/hovered active blue)
secondary: string;
accent: string;
surface: string;
background: string;
text: string;
border: string;
alarm: string; // default '#dc2626'
warning: string; // default '#c77a15'
ok: string; // default '#3aa655'
nodata: string; // default '#6a6c6c'
};
/** Vector floor plan layer stylings */
map: {
wallFill: string;
floorFill: string;
doorLine: string;
amenityIcon: string;
};
/** Floating controls UI panel background cards styles */
controls: {
floorSwitcherBg: string;
toolbarBg: string;
infoCardBg: string;
};
/** Sensor kind standard color fallbacks */
sensorDefaults: Record<SensorKind, string>;
/** Heatmap aggregation colors */
heatmap: {
palette: string[];
};
/** Typography settings */
font: {
family: string;
sizeBase: number; // in pixels
};
/** Rounded corners radii */
radius: {
sm: number;
md: number;
lg: number;
};
/** Animation timings */
motion: {
duration: number; // in milliseconds
easing: string; // CSS transition-timing-function e.g. cubic-bezier
};
}
export type SensorKind = 'temperature' | 'humidity' | 'co2' | 'voc' | 'pressure' | 'peopleCounter';⚡ Instant High-Performance Light/Dark Diffing
Swapping themes in mapping libraries often causes a severe "style-flash" because all vector sources and layers are completely destroyed and re-loaded.
BloomSpark avoids this by leveraging MapLibre's internal style diffing algorithms. When the theme swaps from light to dark:
- Style Diffing Execution: The SDK calls:typescript
map.setStyle(newThemeStyleUrl, { diff: true }); - No Layer Unmounting: MapLibre parses the difference between the two vector sheets and updates only changed paint properties (e.g. background fill-color).
- Preserved Assets: Existing IMDF sources, data layers, wayfinding vectors, and current camera zoom positions remain completely intact and unaffected.
- UI Syncing: CSS Custom Variables update on
:rootconcurrently, causing the HTML floating panels (like the Floor Switcher or info cards) to glide smoothly into their dark-mode variables using standard CSS transitions.
🛠️ The <ThemeBuilder> Dev Tool
To help designers and developers tune custom color schemes, the SDK includes an interactive ThemeBuilder component:
import { SpatialProvider, SpatialMap, ThemeBuilder } from '@bloomsparkagency/core';
export function DevSandbox() {
return (
<SpatialProvider>
<SpatialMap buildings={[]}>
{/* Adds an interactive floating control pane to tune custom colors */}
<ThemeBuilder />
</SpatialMap>
</SpatialProvider>
);
}The ThemeBuilder allows you to edit color values, test light/dark transitions live in the browser, and click "Export Tokens" to download a compiled theme.ts file that can be plugged directly back into your production application configurations.
