OpenWeather Maps SDK v0.0.0 docs
Guides

Core-only / Custom Renderer

@openweather/maps-core has zero MapLibre, React, or WebGL dependency — it's the option for a completely custom renderer (Canvas 2D, a different map library, a non-map UI, a test harness) or for driving @openweather/maps-react's hooks/compounds over your own map implementation.

createCoreMapController

import { createCoreMapController } from '@openweather/maps-core';

const controller = createCoreMapController({
  apiKey: 'YOUR_KEY',
  defaultLayer: 'temperature',
  availableLayers: DEFAULT_LAYER_CATALOG, // optional override
  wireTimelineToEngine: true, // default; false to drive setDate() yourself
  pointQuerySample: async (request) => {
    // Your renderer's pixel sampler — see "Point query" below.
    return [];
  },
});

await controller.engine.initialize();

CreateCoreMapControllerOptions also accepts defaultModelId, defaultRadarModel, initialActiveLayers, dataBaseUrl, and timelineRange ({ start, end, transitionAt?, initialTime? }) to override the default ±TIMELINE_HOURS_EITHER_SIDE-hour window.

What you get back

CoreMapController extends the base MapController with:

Member Purpose
engine The WeatherEngine instance — active layer/date state, resolve, events
addWeatherLayer(code) / removeWeatherLayer(code) Manage the registry's active-layer set
getWeatherLayer(code) / getLayerMetadata(code) / listLayers() Read the layer catalog
setLayerModel(layerCode, modelId) Per-layer model switch (e.g. radar nowcast)
setActiveLayer(code) Activate a layer and resolve its asset
settings, layers, timeline, search (via base MapController) The other stores — see @openweather/maps-core API reference

wireTimelineToEngine (default true) subscribes the timeline's currentTime to engine.setDate() automatically, and keeps the timeline's frame step in sync with whichever layer/model is active (e.g. radar's 10-minute cadence vs. temperature's hourly one). Set it false if you want to drive engine.setDate() yourself on a different cadence.

Rendering the resolved asset

Subscribe to the engine and hand resolvedAsset to your own renderer:

const unsubscribe = controller.engine.subscribe(() => {
  const { resolvedAsset } = controller.engine.getSnapshot();
  if (resolvedAsset) renderIntoYourCanvas(resolvedAsset);
});

await controller.setActiveLayer('pressure');
await controller.engine.setDate(new Date());

ResolvedLayerAsset includes url, date, locked?, modelId?, tileGrid?/tilePyramid?, and scalarConfig? — everything @openweather/maps-maplibre's ScalarFlowRenderer/MultiTileScalarManager use to paint a MapLibre layer. A custom renderer follows the same contract: load the image at url, decode/colorize it against scalarConfig, and re-render whenever the store notifies you.

Point query

PointQueryController is renderer-agnostic — core has no pixel access of its own, so you supply a pointQuerySample function (see the options above) that maps a PointQueryRequest (lng/lat + layer list) to a value per layer. This is exactly what @openweather/maps-maplibre's PointQuerySampler does for the MapLibre adapter: texel lookup in the active texture, then decodeScalarValue. See Architecture — Point query for the full four-step contract.

Driving React hooks/compounds over a custom map

Pass your CoreMapController straight to <MapsProviders> — every hook (useLayers, useTimeline, usePointQuery, useSearch, useSettings) and compound (Timeline, Layers, Search) works against it exactly as it would against a WeatherMapHandle's controller, since <WeatherMap> does nothing more than construct one of these and wrap it in the same provider. See Providers & Hooks.

Testing

Because @openweather/maps-core has no DOM dependency, createCoreMapController runs unmodified under plain Node (no jsdom) — this is how the SDK's own core package tests run, and it's a convenient way to unit-test business logic (layer switching, timeline alignment, entitlement handling) without spinning up a real map at all.