Use the map without React
MountayaMap is the map itself. The React elements are drawn on it. This is the same object reached directly, not a reduced version of it. Mountaya publishes no custom elements, so on Vue, Svelte, Angular or no framework at all, this is the supported path.
Construct a map
Give it a container and a client, and it fetches every specification it draws through that client. container takes an element or its id, and whenReady() resolves once the style has loaded.
The naming is a rule: set replaces one value, add appends, and no resource offers both. Packages and credentials are on Install the SDK.
Each method places what it adds at the right height in the layer order. An overlay keeps its slot beneath the itinerary without your naming a beforeId.
Draw a specification you already hold
setItinerary(id) fetches. An application reading through its own cache already holds the specification. setSpecification draws it under a name of your choosing, with no second request.
Mounting the same name again replaces what it held. The intent is remembered rather than only the layers, so a base-map switch replays it. Outside its zoom window a source draws nothing, with no error and no empty tile. Reach for easeIntoZoomRange when a reader switched something on.
Add your own layers at a Mountaya rank
map.raw.addLayer also works, and appends above everything. Come through the façade for the shared registry. Anchoring reads the ranks already placed, so a private registry orders wrongly against this one. That renders as an itinerary drawn under its own overlay, a wrong-looking map rather than an error. The same caveat covers map.raw itself: anything placed through it sits outside the registry and outside the style-swap replay.
Your source is yours, so the layer is not replayed across a style swap. Re-add it once the swap resolves.
Swap the base style without losing what you drew
setTerrain covers the catalog. setStyle covers your own cartography, a third-party base map, or a catalog style you amend as it arrives.
transformStyle runs after the style is fetched and before it is committed. That is the only moment a source can join the style document itself. Injecting a DEM for 3D relief is that case. Prefer this to map.raw.setStyle, which destroys every source and layer with nothing raised.
Listen for map events
The events are click, contextmenu, featureclick, featurehover, move, moveend, styleload, accessrequired and error. featureclick fires only for Mountaya's own features, so a click on empty basemap does not reach it. featurehover reports the itinerary's features under the pointer, routed lines and waypoints, at most once per animation frame, and an empty list off them. on returns its own unsubscribe, so a framework's unmount hook calls what its mount hook returned.
accessrequired and error carry what no call of yours could reject. accessrequired is a 401, a 402 or a 403 on one of the map's own requests, with the address refused: a tile, a sprite, a glyph, a style, or the layers manifest. error is every other failure. Attach both as soon as the map is built. The manifest is read before the style loads, and an event with no listener is not kept.
A custom tile transform is the transformRequest option of new MountayaMap({ … }). The maplibre option takes MapLibre's own options, less container, style and transformRequest. The map applies them before its own, so they add to them and replace none.
Authenticate a map you constructed yourself
The Tile API declares its credentials as headers, so transformRequest is the only place to attach one. A map without it answers 401.
transformRequest runs for every request the map makes, so the credential goes only to Mountaya origins. Name others with origins, and pass shareToken for a share-link visitor. There is no field for a secret key, which mints session tokens server-side and can never reach a map.
Read geometry without a renderer
@mountaya/elements/geo publishes the geographic core on its own: GeoJSON flattening, bounds, corridor distance, and the camera and zoom arithmetic. Its module graph pulls in no renderer.
An itinerary's geometry comes in more than one shape. A waypoint is a bare Point. A linestring segment is a bare LineString, or a GeometryCollection of that line and the vertices drawn when resampling added positions and the vertices drawn number fewer than the line's sample budget (one position per 50 m of its distance, plus two, between 400 and 4,000); a dense recorded track is a bare LineString even when resampling filled a gap in it. A directions segment is a GeometryCollection of the routed LineString and the vias it was routed through. Flatten before reading geometry.type, which differs from one segment to the next. A BoundingBox computed here passes straight into map.fitBounds(…).
@mountaya/elements/profile derives the elevation series and the per-segment rows, covered on Draw an elevation profile. @mountaya/elements/data reads one itinerary's geometry, characteristics and waypoints in a single round trip.
Convert units
@mountaya/elements/units holds every unit conversion the SDK makes: lengths, speeds, durations, temperatures, slopes, proportions and amounts of data. Each function takes a value and two unit names. None of them formats, and none pulls in a renderer.
Amounts of data come in two families. kilobyte and megabyte are decimal, 1,000 and 1,000,000 bytes, as every bit rate means them. kibibyte and mebibyte are binary, 1,024 bytes and 1,024 kibibytes, which is how the API states a body ceiling: an upload of at most 25 MiB. Read as megabytes, that ceiling comes out 1,214,400 bytes short.
The decimal names are the identifiers Intl.NumberFormat takes as a unit, so a size converted into one formats under that name. The binary pair are IEC names that list does not carry, so format a size in one as a plain number.
Turn search results into rows
A search answers with six shapes and a reader wants one list. @mountaya/elements/search is that mapping, and it is lighter than the package root: nothing here renders or imports maplibre-gl.
Each builder answers a SearchRow or null. A place whose centroid did not survive narrowing is dropped rather than rendered as a dead row. splitByRanges slices the original string, so "MONT blanc" searched for "mont" still draws "MONT".
SearchSnapshot holds the search at a moment, per section, so a points-of-interest outage does not blank the itineraries beside it. Branch on roundsSettled rather than on emptiness, because a viewport search that finds nothing broadens and asks again.