Map
Map injection boundaries for the consumer-owned MapLibre map.
Responsibilities
Waymark no longer creates or owns a map. The consumer constructs the MapLibre Map — container, style, basemaps, camera and attribution — and injects it into createInstance({ map, document? }).
Waymark's map-facing responsibilities are:
- validate the injected map against the required method contract
- bind instance events to
map.getContainer() - mount the
data.layers[]GeoJSON overlay onto the injected map - keep Waymark-owned sources and sublayers mounted across consumer
style.loadcycles - resolve pointer hits over Waymark-owned layers into
waymark:feature.*interaction events (popups and cursor styling stay consumer-owned) - remove Waymark-owned sources/layers and detach Waymark map listeners on
destroy()
Explicitly not Waymark's responsibility:
- map or container creation
- bundling or serving MapLibre GL JS and its worker — the consumer installs MapLibre as a peer dependency and bundles both themselves
- providing MapLibre CSS — the consumer imports
maplibre-gl/dist/maplibre-gl.css - basemap configuration and raster/vector switching
- camera capture or sync (no
state.map.*output) - map style and attribution
- forwarded
waymark:map.*events
Input and output boundaries
- Input map: consumer-owned MapLibre
Map, duck-typed againstgetContainer,on,off,addSource,addLayer,getStyle,fitBounds. Invalid input throws aTypeErrornaming the missing methods. - Input document:
{ config, state, data }only. There is noconfig.maporstate.mapslice; unknown config keys are dropped during normalisation. - Output document:
toJSON()returns{ config, state, data }. No camera or basemap slices are serialised. - Output overlay metadata: GeoJSON source/sublayer IDs are runtime metadata only and are not included in
toJSON().
One runtime exists per map: the registry is a WeakMap keyed by the injected map. A second createInstance(...) call with the same map throws until the existing instance is destroyed.
Runtime behaviour
Waymark validates the injected map in
src/entry.js, normalises the document, then wires the runtime insrc/runtime/createInstanceCore.js.If the injected map is already loaded (
map.loaded()), initial layers mount immediately (synchronously in the common path). If not, Waymark waits for the map'sloadevent and mounts then.Waymark subscribes to
style.load; after a consumer style swap it resets its mounted marker, clears feature-interaction layer tracking and hover state, and remounts all Waymark-owned sources and sublayers.GeoJSON layers are inserted below the first
symbollayer already present in the map style; when the style has no symbol layer they are appended.Instance events are dispatched on
map.getContainer(). Lifecycle, data-layer and state events are documented indocs/1.api.md.Camera and basemaps are the consumer's. Waymark does not observe map camera events, manage styles, or emit basemap/camera events.
instance.data.addLayer(..., { fitBounds })andinstance.data.fitBounds(...)callmap.fitBounds()on the injected map. Seedocs/5.data.mdfor option semantics.destroy()removes Waymark-owned layers (reverse render-plan order) and sources, detaches Waymark'sload/style.loadlisteners and the feature interactionclick/mousemove/mouseouthandlers, and deletes its registry entry. It never callsmap.remove()and never touches the container.GeoJSON source/sublayer IDs are instance-scoped to avoid collisions:
source:
waymark-{id}-geojson-source-{index}sublayer:
waymark-{id}-geojson-layer-{index}-{family}typed sublayer:
waymark-{id}-geojson-layer-{index}-{family}-type-{typeKey}symbol sublayer:
waymark-{id}-geojson-layer-{index}-symbol-type-{typeKey}hit-circle:
waymark-{id}-geojson-layer-{index}-{family}-hiticon-type hit-circle:
waymark-{id}-geojson-layer-{index}-circle-hit-{typeKey}
For public injection validation, config defaults and event payload contracts, treat docs/1.api.md as the source of truth.
Internal files
src/entry.js(factory entry, map duck-type validation)src/runtime/createInstanceCore.js(runtime wiring, public API, destroy flow)src/runtime/runtimeRegistry.js(WeakMapmap → core registry)src/runtime/createInstanceEvents.js(container event bus; no map-event forwarding)src/runtime/state/createInstanceState.js(debug/type-visibility runtime state)src/geojson/createGeoJSONModule.js(overlay mount, style remount, owned-layer cleanup)src/geojson/createFeatureInteractionModule.js(feature click/hover/leave resolution and emission)src/config/resolveConfig.js(runtime config resolution)
src/map/** has been removed entirely — no map creation, container creation, style/basemap ownership, or camera sync remains in the library.