Events & State
Engine events
WeatherEngine (from @openweather/maps-core, reached via controller.engine or WeatherMapHandle.on)
emits these events:
| Event | Payload |
|---|---|
ready |
{ engine } |
layerchange |
{ code } |
datetime |
{ date } |
layer:locked |
{ code, entitlementKey?, status: 403 } |
windtoggle / wavestoggle |
{ enabled } |
cyclonetoggle / lightningtoggle / contourtoggle |
{ enabled } |
layerconfigchange |
{ config } |
error |
{ message, cause? } |
map.on('layer:locked', ({ code, entitlementKey }) => {
// 403 — this specific layer needs an entitlement upgrade
});
map.on('error', ({ message, cause }) => {
// Everything else that isn't a locked layer: an invalid API key (401, from the tile
// probe), a lost WebGL context, a MapLibre style/sprite/glyph fetch
// failure, or `createWeatherMap` finding no WebGL support at all.
});
error and layer:locked are deliberately different channels: a 403 means one layer needs an
entitlement upgrade and the rest of the map keeps working, so it gets its own per-layer UI hook. A
401 means the whole API key is invalid — every layer would fail identically — so it (along with
MapLibre's own internal error event) routes to the generic error event
instead of being mistaken for a single locked layer.
Naming note: events mix bare-word (layerchange, windtoggle) and colon-namespaced
(layer:locked) styles. This is a known, frozen inconsistency rather than a
typo — see docs/API_CONVENTIONS.md in the repo for why it's left alone pre-GA.
The store pattern
Every stateful piece of the SDK — the engine, SettingsStore, LayerRegistry, TimelineController
— follows the same shape:
interface ExternalStore<T> {
getSnapshot(): T;
subscribe(listener: () => void): () => void; // returns an unsubscribe function
}
const unsubscribe = store.subscribe(() => {
const snapshot = store.getSnapshot();
// …
});
This is exactly the shape React.useSyncExternalStore expects, which is why @openweather/maps-react's
hooks (useLayers, useTimeline, useSettings, …) are thin wrappers with no parallel React state
of their own — business state always lives in core, never duplicated in a component.
Naming conventions
- Layer codes — camelCase or snake_case matching the catalog (
temperature,windSpeed,wave_height). - Controller methods — verb + noun (
setActiveLayer,addWeatherLayer). - Hooks —
use+ domain (useLayers,useTimeline,usePointQuery,useSearch).
Full conventions, including the public-vs-@openweather/maps-core/internal split and semver policy, live in
the repo's docs/API_CONVENTIONS.md.