Skip to content
Documentation menu
docs / maps-reference · raw .md

@mapmap/maps reference

Generated from the published @mapmap/maps 0.25.1 type declarations by website/scripts/sdk-reference.mjs. Do not edit by hand: change the JSDoc in the package, or the examples in website/content/sdk-reference/maps.examples.md, and regenerate.

Every public export of the web maps SDK, from the main entry point and each subpath (/live, /models, /tiles, /avatars, /road-signs, /direction-icons, /asset-markers). For the task-by-task guide, read Web maps in SDKs & installation, Maps, tiles & Studio and Live layers.

bash
npm install @mapmap/maps@0.25.1 maplibre-gl

Other SDK references: @mapmap/points, @mapmap/core, @mapmap/tile, @mapmap/react-native, @mapmap/voice, MapMapKit, ai.mapmap:core.

663 exports across 8 entry points: 32 classes, 240 functions, 173 interfaces, 84 types, 134 constants.

How to read this page

Each entry gives the declaration as published, the JSDoc description, and a table of parameters or properties with their types. The Default column quotes the default the source states (an @default tag or a "Default ..." sentence in the JSDoc). "required" means the property must be given; "not stated" means the source gives no default, so none is claimed here. Classes, factories and the main entry functions each carry a minimal example; examples marked from the source are the package's own @example.

Setup used by the examples

The examples below share one map, made once in src/map.ts, as a reader's own project would. Replace snk_… with your key.

ts
// src/map.ts
import "maplibre-gl/dist/maplibre-gl.css";
import { createMap } from "@mapmap/maps";

export const map = createMap({ container: "map", apiKey: "snk_…", center: [-0.1276, 51.5072], zoom: 12 });

Contents

@mapmap/maps

ts
import { /* … */ } from "@mapmap/maps";

Classes (@mapmap/maps)

AdrCheck, CameraAlertChip, ColourThemeLayer, CreditControl, DataLayer, FlowRouteEffectLayer, Geocoder, GuidanceBanner, InteractionRegistry, IsochroneError, IsochroneLayer, LogoControl, MapMapMap, MarkersLayer, NavigationCamera, PlacesLayer, PositionPuck, ProgramCache, RouteLayer, SearchBox, ThemeScheduler, TransitStopsLayer, TransitVehiclesLayer, VoiceGuidance

AdrCheck

Class

ts
class AdrCheck { … }

Calls POST /adr/check and returns the parsed compliance decision.

Constructor and methods

  • constructor(options: AdrCheckOptions)
  • check(request: AdrCheckRequest): Promise<AdrCheckResult>

Example

ts
import { AdrCheck } from "@mapmap/maps";

const adr = new AdrCheck({ baseUrl: "https://api.mapmap.ai", apiKey: "snk_…" });
const result = await adr.check({ hazmat: true, tunnelCode: "D/E", tunnelCategory: "C" });
console.log(result.status, result.reason);

CameraAlertChip

Class

ts
class CameraAlertChip { … }

A minimal DOM safety-alert chip: kind icon, kind label and (when known) the limit and distance, in a calm or escalated state.

Style with the mapmap-alert-chip class, or pass a Studio design (extra.nav alerts block, e.g. map.navDesign?.alerts) to match a Studio theme. Framework-free and DOM-only, exactly like GuidanceBanner; head units should read alertChipContent instead.

The chip NEVER overlaps the speed or the limit: its position comes from a constrained slot enum, and aboveSpeed reserves its own clearance.

PropertyTypeDefaultDescription
readonly elementHTMLElementThe chip root element; attach it wherever your UI needs it.
readonly isEscalatedbooleanWhether the chip is currently in its escalated state.

Constructor and methods

  • constructor(container?: HTMLElement, design?: NavAlertsDesign)
  • update(alert: CameraAlert | null, state?: { speeding?: boolean; }): void: Renders an alert (or hides the chip with null). state.speeding drives the escalated state; the chip itself shows regardless, because the visual alert is unconditional. A kind whose design turns alertWhileDriving off hides the chip: the customer chose not to surface that kind while driving.

Example

ts
import { CameraAlertChip } from "@mapmap/maps";

const chip = new CameraAlertChip(document.getElementById("alerts") ?? undefined);
chip.update({ kind: "speed", limitKph: 50, distanceM: 300 }, { speeding: false });
// Hide it again:
chip.update(null);

ColourThemeLayer

Class

ts
class ColourThemeLayer implements CustomLayerInterface { … }

A post-process custom layer that grades the composed frame through a LUT.

Implements CustomLayerInterface.

PropertyTypeDefaultDescription
readonly idstring
readonly type"custom"
readonly renderingMode"2d"

Constructor and methods

  • constructor(options: ColourThemeLayerOptions)
  • setLut(lut: LutBytes, strength?: number): void: Swap the LUT (and optionally the strength); the next frame uses it.
  • setStrength(strength: number): void: Set the blend with the ungraded frame, 0..1.
  • onAdd(map: Map, gl: WebGL2RenderingContext): void
  • onRemove(_map: Map, gl: WebGL2RenderingContext): void
  • render(glArg: CustomLayerGl, _args: unknown): void

Example

ts
import { map } from "./map.ts";
import { ColourThemeLayer, IDENTITY_LUT } from "@mapmap/maps";

// A LUT that leaves colours unchanged; build your own with buildLut or lutFromPngData.
const grade = new ColourThemeLayer({ lut: IDENTITY_LUT, strength: 0.8 });
map.map.addLayer(grade);
grade.setStrength(0.5);

CreditControl

Class

ts
class CreditControl<T extends CreditInnerControl = CreditInnerControl> { … }

A MapLibre IControl that renders MapLibre's attribution as the v2 map credit. attribution is the wrapped control, unchanged.

PropertyTypeDefaultDescription
readonly attributionTThe wrapped MapLibre attribution control.
readonly themeMapBrandThemeThe variant on show.

Constructor and methods

  • constructor(attribution: T, options?: CreditOptions)
  • getDefaultPosition(): ChromeCorner
  • onAdd(map: unknown): HTMLElement
  • onRemove(map?: unknown): void
  • setTheme(theme: MapBrandTheme): void: Switch between the Day and Night credit (same size and shape; the colour pair follows the ground).

Example

ts
import * as maplibregl from "maplibre-gl";
import { CreditControl } from "@mapmap/maps";

// For a plain maplibregl.Map: createMap already adds the credit for you.
const map = new maplibregl.Map({ container: "map", style: "https://example.com/style.json", attributionControl: false });
const credit = new CreditControl(new maplibregl.AttributionControl({ compact: false }), { theme: "day" });
map.addControl(credit);
credit.setTheme("night");

DataLayer

Class

ts
class DataLayer { … }

A GeoJSON or PMTiles data layer on a MapMap map. See the module docs.

PropertyTypeDefaultDescription
readonly ids{ source: string; layers: string[]; }The source id and every layer id this DataLayer draws, bottom first.

Constructor and methods

  • constructor(map: MapMapMap, opts: DataLayerOptions)
  • setData(data: GeoJSON.FeatureCollection | string): void: Replace the data (inline or a GeoJSON URL). Clears hover and selection.
  • updateData(diff: GeoJSONSourceDiff): void: Apply a MapLibre GeoJSON diff (add, remove, update by id) without re-sending the whole dataset. Needs inline data with a unique id on every feature (or promoteId); the change survives a theme swap.
  • setFilter(filter: FilterSpecification | null): void: Filter every layer of this DataLayer (null clears). Survives a theme swap.
  • selected(): GeoJSON.Feature[]: The selected features.
  • select(ids: (string | number)[]): void: Select features by id (feature id, or the promoteId value).
  • clearSelection(): void: Clear the selection.
  • on(event: DataLayerEventType, handler: (e: DataLayerEvent) => void): () => void: Listen for click, hover or select. Returns an unsubscribe function.
  • remove(): void: Remove the source, its layers, the popup and every listener.

Example

ts
import { map } from "./map.ts";
import { DataLayer } from "@mapmap/maps";

const sites = new DataLayer(map, {
  data: "https://example.com/sites.geojson",
  mode: "point",
  style: { categories: { property: "status", values: { open: "#1a7f37", closed: "#cf222e" } } },
});
const off = sites.on("click", (e) => console.log(e.feature?.properties));
// Later:
off();
sites.remove();

FlowRouteEffectLayer

Class

ts
class FlowRouteEffectLayer implements CustomLayerInterface { … }

A MapLibre custom layer (CustomLayerInterface) drawing the flowing route ribbon. Construct via createRouteEffect (the registry) or use MapMapMap.setRouteEffect("flow"), which manages the lifecycle.

Implements CustomLayerInterface.

PropertyTypeDefaultDescription
readonly idstring
readonly type"custom"
readonly renderingMode"2d"

Constructor and methods

  • constructor(geometry: RouteGeometry, options?: RouteFlowOptions)
  • setGeometry(geometry: RouteGeometry): void: Swap the ribbon onto a new route line (e.g. after a reroute).
  • onAdd(map: Map, gl: WebGL2RenderingContext): void
  • onRemove(_map: Map, gl: WebGL2RenderingContext): void
  • render(gl: CustomLayerGl, args: unknown): void

Example

ts
import { map } from "./map.ts";
import { FlowRouteEffectLayer } from "@mapmap/maps";

const flow = new FlowRouteEffectLayer(
  { type: "LineString", coordinates: [[-0.1276, 51.5072], [-0.0877, 51.5055]] },
  { width: 8 },
);
map.map.addLayer(flow);
// After a reroute:
flow.setGeometry({ type: "LineString", coordinates: [[-0.1276, 51.5072], [-0.1, 51.52]] });

Geocoder

Class

ts
class Geocoder { … }

Calls the gateway's geocoding endpoints and returns parsed hits.

Constructor and methods

  • constructor(options: GeocoderOptions)
  • geocode(query: string, options?: GeocodeOptions): Promise<GeocodeHit[]>: Forward geocode: free-text query → hits, best first.
  • reverse(point: LngLatLike, options?: ReverseGeocodeOptions): Promise<GeocodeHit[]>: Reverse geocode: point → nearest hits, nearest first.

Example

ts
import { map } from "./map.ts";
import { Geocoder } from "@mapmap/maps";

// A MapMapMap satisfies GeocoderOptions, so the map's gateway and key are reused.
const geocoder = new Geocoder(map);
const [best] = await geocoder.geocode("Temple Meads, Bristol");
if (best) map.map.flyTo({ center: best.lngLat, zoom: 15 });
const here = await geocoder.reverse([-2.5813, 51.4491]);
console.log(here[0]?.name, here[0]?.distanceM);

GuidanceBanner

Class

ts
class GuidanceBanner { … }

A minimal DOM banner: primary text with a maneuver icon from the platform direction set (the same direction-icons glyphs the MapMap apps use, ferry, roundabouts, forks, ramps and all), plus an optional lane row. Style with the mapmap-banner / mapmap-banner-lanes / mapmap-banner-icon classes, pass a Studio design (extra.nav banner block, e.g. map.navDesign?.banner) to match a Studio theme, or read StepGuidance yourself for fully custom UI. The icon is drawn in the banner's text colour; its secondary shapes (class="mm2": the rest of a roundabout ring, other lanes) are that same colour at 35% opacity, never a fixed grey. Retune the opacity with .mapmap-banner-icon .mm2 { fill-opacity: …; stroke-opacity: … }.

Roundabouts draw for the side traffic drives on: clockwise for left-hand traffic (roundabout_lht_*), anticlockwise for right-hand traffic. The side comes from the route, never a default; when it is unknown the banner draws the plain turn glyph for the exit direction.

PropertyTypeDefaultDescription
readonly elementHTMLElementThe banner root element; attach it wherever your UI needs it.

Constructor and methods

  • constructor(container?: HTMLElement, design?: NavBannerDesign)
  • update(banner: BannerInstruction | null, step?: Pick<StepGuidance, "mode" | "drivingSide" | "bannerIcon">): void: Renders a banner instruction (or hides the element with null). step is icon context: pass the StepGuidance entry the banner came from. Its bannerIcon is the glyph for the manoeuvre the banner describes (the next step's, with that step's own driving side and, at a roundabout, the paired through-angle exit), and a ferry-mode step draws the ferry glyph. Without bannerIcon (a hand-built { mode, drivingSide }), the glyph comes from the banner's own type and modifier with that drivingSide; with no side a roundabout draws the plain turn glyph for its direction.

Example

ts
import { GuidanceBanner } from "@mapmap/maps";

const banner = new GuidanceBanner(document.getElementById("banner") ?? undefined);
banner.update({
  distanceAlongGeometry: 120,
  primary: { text: "Baldwin Street", type: "turn", modifier: "left" },
});

InteractionRegistry

Class

ts
class InteractionRegistry { … }

The per-map interaction registry behind MapMapMap.addInteraction. Exported for apps that drive a plain maplibregl.Map.

Constructor and methods

  • constructor(map: Map)
  • add(id: string, interaction: Interaction): void: Add (or replace) the interaction id.
  • remove(id: string): void: Remove the interaction id. Unknown ids are ignored.
  • ids(): string[]: The registered interaction ids, in the order they were added.
  • setFeatureState(target: InteractionTarget & { id: string | number; }, state: Record<string, unknown>): void: Set feature state on every source layer behind target: a featureset sets it once per distinct source and source layer (building and building-3d share one), so a paint expression reading ["feature-state", ...] on any of those layers sees it.
  • destroy(): void: Detach every listener and forget every interaction.

Example

ts
import * as maplibregl from "maplibre-gl";
import { InteractionRegistry } from "@mapmap/maps";

// For a plain maplibregl.Map; a MapMapMap has the same thing as map.addInteraction.
const map = new maplibregl.Map({ container: "map", style: "https://example.com/style.json" });
const interactions = new InteractionRegistry(map);
interactions.add("poi-click", {
  type: "click",
  target: { featuresetId: "poi" },
  handler: (e) => {
    console.log(e.feature?.properties);
    return true; // handled: stop here
  },
});

IsochroneError

Class

ts
class IsochroneError extends Error { … }

A failed showReachability: the HTTP status and the gateway's RFC 9457 problem fields. The message keeps the long-standing form isochrone request failed: HTTP <status> (<title> - <detail>).

Extends Error.

PropertyTypeDefaultDescription
readonly statusnumberHTTP status of the gateway's answer.
readonly problemTypestring | undefinedThe problem's type URN, e.g. NO_ROADS_NEAR_ORIGIN.
readonly titlestring | undefined
readonly detailstring | undefined
readonly noRoadsNearOriginbooleanTrue when the origin has no road within 5 km (open sea, desert): move it onto land near a road and ask again.

Constructor and methods

  • constructor(status: number, problem: Record<string, unknown> | undefined)

Example

ts
import { map } from "./map.ts";
import { IsochroneError, IsochroneLayer } from "@mapmap/maps";

const reach = new IsochroneLayer(map);
try {
  await reach.showReachability({ origin: [-30, 45], minutes: [15] });
} catch (err) {
  if (err instanceof IsochroneError && err.noRoadsNearOrigin) {
    console.log("Move the origin onto land near a road", err.status);
  } else {
    throw err;
  }
}

IsochroneLayer

Class

ts
class IsochroneLayer { … }

Renders reachability rings from the gateway's POST /isochrone.

PropertyTypeDefaultDescription
readonly currentIsochroneFeatureCollection | undefinedThe most recently drawn rings, if any.

Constructor and methods

  • constructor(map: MapMapMap | Map, options?: IsochroneLayerOptions)
  • showReachability(options: ShowReachabilityOptions): Promise<IsochroneFeatureCollection>: Fetch and render reachability rings. Returns the GeoJSON FeatureCollection the gateway produced (each feature carries a contour property in minutes), for callers who also want the raw shapes. Replaces any rings already shown by this layer.
  • clear(): void: Remove the rings' layers and source from the map.
  • destroy(): void: Remove the rings and detach the layer's style.load listener and any pending wait for the style.

Example

ts
import { map } from "./map.ts";
import { IsochroneLayer } from "@mapmap/maps";

const reach = new IsochroneLayer(map);
const rings = await reach.showReachability({ origin: [-0.1276, 51.5072], mode: "driving", minutes: [10, 20, 30] });
console.log(rings.features.length);

LogoControl

Class

ts
class LogoControl { … }

A MapLibre IControl rendering the MapMap mark. Typed structurally (onAdd/onRemove) so it needs no maplibre-gl import and works with any instance the host app bundles.

PropertyTypeDefaultDescription
readonly themeMapBrandThemeThe variant on show.

Constructor and methods

  • constructor(options?: LogoOptions)
  • getDefaultPosition(): LogoPosition
  • onAdd(): HTMLElement
  • onRemove(): void
  • setTheme(theme: MapBrandTheme): void: Switch between the Day and Night mark.

Example

ts
import * as maplibregl from "maplibre-gl";
import { LogoControl } from "@mapmap/maps";

// createMap adds the mark itself; this is for a plain maplibregl.Map.
const map = new maplibregl.Map({ container: "map", style: "https://example.com/style.json" });
const logo = new LogoControl({ position: "bottom-left", theme: "day" });
map.addControl(logo);

MapMapMap

Class

ts
class MapMapMap { … }

The MapMap map: a branded, tiles-and-routing-ready MapLibre map.

PropertyTypeDefaultDescription
readonly mapMapThe underlying MapLibre map. Use it for any native MapLibre call.
readonly apiKeystring | undefinedGateway API key, if provided.
readonly baseUrlstringGateway base URL (no trailing slash).
readonly navDesignNavDesign | undefinedThe Studio navigation design (extra.nav) parsed from the theme passed as style, when it carried one. RouteLayer, PositionPuck and GuidanceBanner pick this up as their default look; undefined means the theme had no nav block (or style was not a theme document).
readonly poiDesignPoiDesign | undefinedThe Studio POI category design (extra.poi) parsed from the theme passed as style, when it carried one. Apply its label-text part with applyPoiDesign(map.map, map.poiDesign); undefined means the theme had no poi block (or style was not a theme document).
readonly groundThemeMapBrandThemeday or night: the variant of the map credit and the MapMap mark on show, read off the ground of the style actually drawn. Also set as data-mapmap-ground on the map container, so page CSS can follow it.

Constructor and methods

  • constructor(options: MapMapOptions)

  • setTerrain(terrain: boolean | TerrainOptions): void: Turn terrain on or off after construction. false removes the DEM sources and any hillshade layer this SDK added.

  • setRouteEffect(effect: RouteEffectName | null, options?: SetRouteEffectOptions): void

    Set (or clear) the visual effect on the active route line - the effects-engine entry point (see effects.ts). The first effect is "flow": an animated energy ribbon flowing along the route, drawn in a MapLibre custom layer with first-party GLSL.

    ts
    const route = await routes.route(from, to);
    map.setRouteEffect("flow");                       // uses the drawn route
    map.setRouteEffect("flow", { color: "#ff7a1f" }); // options
    map.setRouteEffect(null);                          // back to the plain line
    

    Geometry: pass { geometry } explicitly, or omit it and the effect attaches to whatever route a RouteLayer on this map draws (current and future - RouteLayer reports every drawn line via setRouteEffectGeometry).

    Styles whose theme carried an effects block auto-enable their effect from the compiled style's metadata; calling this method (with any value, including null) overrides the style's wish for the lifetime of this map.

    Accessibility/resilience (see effects.ts): honours prefers-reduced-motion (static gradient, no animation) and falls back to the plain route line with a single console warning if WebGL setup fails.

  • setRouteEffectGeometry(geometry: RouteGeometry | null): void: Attach the active route effect to a route line (or detach it with null). RouteLayer calls this on every draw()/clear(), so apps normally never do - pass geometry to setRouteEffect for routes drawn outside a RouteLayer.

  • setBuildings3d(enabled: boolean): void: Toggle 3D building extrusions at runtime, the live equivalent of compiling the style with buildings_3d: true (see Theme): adds or removes the building-3d fill-extrusion layer and hands the flat building footprint layer off at zoom 15. The extrusion takes its colour from the current building fill, so it follows the theme. Idempotent; safe to call before the style has loaded (it applies on load). Requires the MapMap skeleton's building layer, on a custom style without one this throws rather than guessing. Mobile note: leave 3D off in native navigation views for now (maplibre-native#4107, fill-extrusion memory at street zooms).

  • setStyle(style: MapMapTheme | Theme | StyleSpecification | string, options?: Parameters<Map["setStyle"]>[1]): void: Swap the map style: a theme name ("light" / "dark"), a Studio Theme document, a full StyleSpecification or a style URL, the same values the style option takes. Theme names and documents build against the same territory tiles the map was created with. Everything the SDK draws comes back on the new style: routes, places, markers, terrain, route effects, and every persistent source and layer (addPersistentLayer, DataLayer), in order, at its slot. navDesign and poiDesign stay as they were read at construction.

  • slot(slot: Slot): string | undefined

    The beforeId for an insertion slot on the live style, or undefined to append on top. See SLOT_ANCHORS for what each slot means.

    ts
    map.map.addLayer(myLayer, map.slot("bottom"));
    

    A layer added this way is gone after the next setStyle; use addPersistentLayer for one that stays.

  • addPersistentSource(id: string, source: SourceSpecification): void: Add a source that survives setStyle. Calling it again with the same id replaces the registered source: a GeoJSON source swaps its data in place (setData); any other change needs removePersistent first, because MapLibre cannot change a source's type or URL under the layers drawing it.

  • addPersistentLayer(layer: LayerSpecification, opts?: PersistentLayerOptions): void

    Add a layer that survives setStyle, at an insertion slot or below a layer id. Persistent layers are re-added on every style load in the order they were added, each at its slot resolved against the NEW style, so a theme swap keeps them in order and in place.

    ts
    map.addPersistentSource("depots", { type: "geojson", data: depots });
    map.addPersistentLayer(
      { id: "depots", type: "circle", source: "depots", paint: { "circle-radius": 6 } },
      { slot: "middle" },
    );
    map.setStyle("dark"); // the depots stay, above the roads, below the labels
    

    The layer's source must be a persistent source or one every style you switch to carries (territory); a layer whose source is missing after a swap is skipped with one console warning.

  • removePersistent(id: string): void: Remove a persistent source or layer, from the map and the registry. Removing a source also removes every persistent layer drawing it. Unknown ids are ignored.

  • persistentIds(): PersistentIds: The persistent source and layer ids, in the order they were added.

  • addInteraction(id: string, interaction: Interaction): void: Run interaction.handler on clicks or hovers over a layer, a basemap featureset (poi, place-labels, buildings) or the map itself. Shaped like Mapbox GL JS addInteraction; a handler returning true stops the event reaching interactions further down. Adding an id that exists replaces it. Interactions survive setStyle.

  • removeInteraction(id: string): void: Remove the interaction id. Unknown ids are ignored.

  • setFeatureState(target: InteractionTarget & { id: string | number; }, state: Record<string, unknown>): void: Set feature state on a layer's or featureset's features, for paint expressions that read ["feature-state", key]. Basemap features carry stable ids, so this works on poi and place-labels without promoteId. On buildings it is best effort: the tiles merge neighbouring footprints of the same height into one feature, so the state lands on that whole group.

  • whenReady(): Promise<void>: Resolves once the style and first tiles are loaded. Safe to call at any point in the map's life, not just before its first load: map.loaded() goes false again whenever a source is loading (a theme swap, a pan into new tiles) while load only ever fires once, so this waits on idle too rather than hanging.

  • destroy(): void: Remove the map and release its WebGL context. Anything still queued behind a style load is dropped first, so nothing touches the map after this returns.

  • setColorTheme(theme: ColorThemeSpec | null): Promise<void>

    Grade the whole map through a colour theme (a 16x16x16 LUT), the Mapbox setColorTheme equivalent. null removes it.

    ts
    await map.setColorTheme({ data: "https://example.com/night.png" }); // Mapbox-format 256x16 PNG
    await map.setColorTheme({ lut: bytes, strength: 0.6 });             // raw LUT bytes or base64
    map.setColorTheme(null);
    

    The theme is drawn by a custom layer ("mapmap-colour-theme") that the SDK keeps on top: it moves back above anything added later, and comes back after setStyle. Strength 0 removes the layer (no identity pass), while getColorTheme() still reports it. Resolves once the LUT is decoded; rejects with a readable message for a bad image, a LUT that is not 12288 bytes, or a strength outside 0..1. A later call wins over an earlier one still decoding.

    Over a style already graded at compile time (one carrying metadata["mapmap:color-theme"]) it still works, and logs one warning.

  • getColorTheme(): { digest: string; strength: number; } | null: The runtime colour theme in force: its LUT digest (FNV-1a 64, 16 hex characters, the same digest compile-time grading stamps in metadata["mapmap:color-theme"]) and strength, or null with none.

  • addClip(id: string, opts: ClipOptions): void

    Hide the basemap's buildings (or POI labels) inside a polygon, the Mapbox clip layer equivalent. Works on its own, with no model:

    ts
    map.addClip("new-tower", { polygon: site });                       // buildings
    map.addClip("plaza", { polygon: plaza, types: ["buildings", "symbols"] });
    map.removeClip("new-tower");
    

    A feature that touches the polygon is not drawn (the style-spec distance filter, which MapLibre GL JS and Native both evaluate). Clips survive setStyle, apply to building-3d when setBuildings3d(true) adds it later, and two clips on one layer hide features inside either polygon. Calling it again with the same id replaces that clip. The polygon may have at most 500 vertices in total.

  • removeClip(id: string): void: Remove a clip; each layer gets back its own filter (or the other clips').

  • clips(): string[]: The ids of the clips in place, in the order they were added.

Example

ts
import { MapMapMap } from "@mapmap/maps";

// createMap(options) is the usual way in; the constructor takes the same options.
const map = new MapMapMap({ container: "map", apiKey: "snk_…", center: [-1.8904, 52.4862], zoom: 12 });
await map.whenReady();
map.setStyle("dark");
map.setBuildings3d(true);
map.addPersistentSource("depots", {
  type: "geojson",
  data: { type: "FeatureCollection", features: [] },
});
map.addPersistentLayer({ id: "depots", type: "circle", source: "depots" }, { slot: "top" });

MarkersLayer

Class

ts
class MarkersLayer { … }

Draws a theme's custom markers & labels on a MapLibre map.

ts
const markers = await markersFromThemeUrl(themeUrl);
if (markers) new MarkersLayer(map, markers);

Registers every needed marker image (rasterised glyph pins are cached by mm-marker-<icon>-<colour>-<size>; custom images by data-URI hash), builds one GeoJSON feature per marker carrying its image key, label, precomputed icon-size ratio and anchor, and installs the single mm-user-markers source + symbol layer. Survives setStyle like PlacesLayer (re-installed on every style.load).

PropertyTypeDefaultDescription
readonly currentMarkerItem[]The layer's current markers.
readonly idsMarkersLayerIdsThe MapLibre source/layer ids - public API for escape-hatch styling. Both are the contract id mm-user-markers.

Constructor and methods

  • constructor(map: MapMapMap | Map, markers?: MarkersBlock, options?: MarkersLayerOptions)
  • setMarkers(markers: MarkersBlock | undefined): void: Replace the layer's markers with a parsed block (undefined or an empty block clears the map of markers but keeps the layer alive). Custom images load asynchronously: their markers render as default pins until the image arrives, then swap in place; a failed or oversized image keeps the pin fallback.
  • clear(): void: Remove the markers' layer, source and registered images from the map. Images are removed by the keys this layer REGISTERED, not by whatever items happens to hold now, deriving them from the items meant setMarkers(undefined) followed by clear()/destroy() removed nothing at all.
  • destroy(): void: Remove the markers and detach the style.load listener and any pending wait for the style. Call when disposing of the layer (the map is left untouched). Any image load still in flight resolves into a no-op.

Example

ts
import { map } from "./map.ts";
import { MarkersLayer, parseMarkers } from "@mapmap/maps";

const block = parseMarkers({
  version: 1,
  items: [{ id: "hq", lng: -0.1276, lat: 51.5072, icon: "star", colour: "#0b5fff", size: "m", label: "HQ" }],
});
const markers = new MarkersLayer(map, block);
// Later:
markers.destroy();

Class

ts
class NavigationCamera { … }

A follow-mode chase camera for MapMap maps.

PropertyTypeDefaultDescription
readonly modeNavigationCameraModeThe camera's current behaviour: "follow", "overview" or "free".

Constructor and methods

  • static isSupported(map: MapMapMap | Map): boolean: false when the map runs the globe (or vertical-perspective) projection, whose camera geometry breaks the low-anchor offset maths and top-down overview framing. Switch to mercator for navigation.
  • constructor(map: MapMapMap | Map, options?: NavigationCameraOptions)
  • attachPuck(puck: CoDrivenPuck): void: Co-drive a PositionPuck: every follow call also setLocations the puck, so camera and puck never diverge.
  • follow(fix: CameraFix, courseDeg?: number): void: Glide the camera to a fix, course-up when courseDeg is given (bearing is left unchanged when it is undefined). Each call eases with linear timing over easeMs capped by the observed fix interval, and interrupts the previous ease (no queue buildup). The fix and an attached puck are always updated, but the camera only moves in "follow" mode - "free" and "overview" record the fix for resume.
  • overview(routeGeometry?: RouteGeometry): void: Fit the route top-down (pitch 0, north-up). Pass the route geometry on the first call; later calls reuse the last geometry given. A no-op when no geometry has ever been provided.
  • resume(): void: Return to follow mode, gliding back to the last fix (with its last known course) when one has been recorded.
  • destroy(): void: Remove the map listeners and cancel any pending auto-recentre.

Example

ts
import { map } from "./map.ts";
import { NavigationCamera, PositionPuck } from "@mapmap/maps";

if (NavigationCamera.isSupported(map)) {
  const camera = new NavigationCamera(map, { pitch: 55, zoom: 17 });
  camera.attachPuck(new PositionPuck(map));
  navigator.geolocation.watchPosition((p) => {
    camera.follow({ lat: p.coords.latitude, lon: p.coords.longitude }, p.coords.heading ?? undefined);
  });
}

PlacesLayer

Class

ts
class PlacesLayer { … }

Draws customer places on a MapLibre map, with clustering and popups.

PropertyTypeDefaultDescription
readonly currentPlace[]The layer's current places (normalised to Place[]).
readonly idsPlacesLayerIds"mapmap-places"The generated MapLibre source/layer ids - public API for escape-hatch styling (map.setPaintProperty, queryRenderedFeatures, …) beyond the layer's options. Stable for the layer's lifetime, derived from the id option (default "mapmap-places"). The cluster ids are only installed on the map with cluster: true (the default), and points is a circle layer by default or a symbol layer once a custom icon has loaded.

Constructor and methods

  • constructor(map: MapMapMap | Map, options?: PlacesLayerOptions)
  • setPlaces(places: PlacesInput): void: Replace the layer's places - a Place[] or a GeoJSON FeatureCollection of Points. Never silently drops an update: once the source exists the data is applied immediately, even while isStyleLoaded() is transiently false mid-render (search-as-you-type just works). Before the source exists it is installed as soon as the style is parsed, even while tiles are still loading; calls made before that are stashed - the latest one wins - and installed the moment the style is ready, with no later setPlaces or style swap needed. With fitBounds: true the first non-empty set also fits the map view.
  • select(id: string, options?: PlacesSelectOptions): Place | undefined: Programmatically select a place by id - list-to-map sync for a store finder's results list. Opens the layer's configured popup at the place (popup: false to skip, no-op without a popup option) and eases the camera to it (flyTo: false to skip; zoom to also zoom). Returns the selected place, or undefined for an unknown id (in which case nothing happens). Does NOT invoke onPlaceClick - a programmatic selection is not a user click.
  • deselect(): void: Close the popup opened by select or a place click, if any.
  • nearest(origin: { lat: number; lon: number; }, n?: number): PlaceWithDistance[]: The nearest n places (default 1) to origin by straight-line (haversine) distance, each with distanceM attached. Pure and instant - no network. For road-network answers use nearestByDriveTime.
  • nearestByDriveTime(origin: { lat: number; lon: number; }, options?: NearestByDriveTimeOptions): Promise<PlaceWithDriveTime[]>: The nearest n places (default 1) to origin by drive time, via the gateway's POST /matrix (one source, all places as targets). Resolves to places sorted by durationS ascending, with the driven distanceM attached; unreachable places (null duration) are dropped. Needs the gateway baseUrl/apiKey - picked up from a MapMapMap automatically, or pass them as layer options. Answers always describe the places that were asked about: the list is snapshotted at call time, so a setPlaces landing mid-flight (a search-as-you-type filter, say) cannot mis-pair the matrix rows with a different set of places.
  • clear(): void: Remove the places' layers, source, image and popup from the map.
  • destroy(): void: Remove the places and detach every listener (style.load, clicks, hovers, and a pending wait for the style). Call when disposing of the layer (the map is left untouched).

Example

ts
import { map } from "./map.ts";
import { PlacesLayer } from "@mapmap/maps";

const stores = new PlacesLayer(map, {
  places: [
    { id: "a", name: "Old Market", lat: 51.4556, lon: -2.5795 },
    { id: "b", name: "Clifton", lat: 51.4648, lon: -2.6203 },
  ],
  cluster: true,
  onPlaceClick: (place) => console.log(place.name),
});
const nearest = stores.nearest({ lat: 51.4545, lon: -2.5879 }, 1);
console.log(nearest[0]?.distanceM);

PositionPuck

Class

ts
class PositionPuck { … }

A current-position puck marker for MapMap maps.

PropertyTypeDefaultDescription
readonly elementHTMLElementThe puck's root DOM element (the Marker element).

Constructor and methods

  • constructor(map: MapMapMap | Map, design?: NavPuckDesign, options?: PositionPuckOptions): Creates the puck (not yet on the map - it appears on the first setLocation). The design defaults to the map's navDesign.puck when given a MapMapMap whose theme carried an extra.nav block, then to the built-in blue puck.
  • setLocation(location: { lat: number; lon: number; }, headingDeg?: number): void: Moves the puck (adding it to the map on the first call). headingDeg rotates the whole element - arrow or custom image - clockwise from north; omit it to keep the previous heading. With interpolation on (the default) every call after the first glides from the currently rendered position - a fix arriving mid-tween retargets smoothly rather than jumping.
  • remove(): void: Removes the puck from the map (cancelling any tween). setLocation re-adds it.

Example

ts
import { map } from "./map.ts";
import { PositionPuck } from "@mapmap/maps";

const puck = new PositionPuck(map);
puck.setLocation({ lat: 51.5072, lon: -0.1276 }, 90);

ProgramCache

Class

ts
class ProgramCache<T> { … }

One compiled program (or any per-variant object) per shaderData.variantName. The prelude differs by variant, so a program built for one projection must never draw another.

Constructor and methods

  • get(variant: string, build: () => T): T
  • delete(gl: WebGL2RenderingContext, dispose: (t: T) => void): void: Dispose of every entry and empty the cache (call from onRemove).

Example

ts
import { ProgramCache } from "@mapmap/maps";

// One compiled program per projection variant, inside your own custom layer.
const programs = new ProgramCache<WebGLProgram>();
export function programFor(gl: WebGL2RenderingContext, variant: string): WebGLProgram {
  return programs.get(variant, () => {
    const program = gl.createProgram();
    // ...compile and link the shaders for this variant...
    return program;
  });
}
export function release(gl: WebGL2RenderingContext): void {
  programs.delete(gl, (p) => gl.deleteProgram(p)); // from onRemove
}

RouteLayer

Class

ts
class RouteLayer { … }

Draws MapMap routes on a MapLibre map.

PropertyTypeDefaultDescription
readonly idsRouteLayerIdsmapmap-routeThe MapLibre source and layer ids this layer owns - public API for escape-hatch styling and layer ordering (map.moveLayer). All are derived from the id option (default mapmap-route).
readonly currentParsedRoute | undefinedThe most recently drawn route, if any.
readonly currentWaypoints[number, number][]The intermediate stops currently drawn, [lng, lat] each.
readonly alternativeRoutesreadonly ParsedRoute[]Which alternatives are currently drawn, in the order given.

Constructor and methods

  • constructor(map: MapMapMap | Map, options?: RouteLayerOptions)
  • route(from: LngLatLike, to: LngLatLike, options?: RouteOptions): Promise<ParsedRoute>: Route from from to to (with optional intermediate via points passed through options is not supported here - pass a coordinate list to routePath for that), draw the line, and return the parsed route.
  • routePath(points: LngLatLike[], options?: RouteOptions): Promise<ParsedRoute>: Route through an ordered list of coordinates and draw the result. Concurrent calls are ordered by ISSUE, not by arrival: only the newest request draws. A destination retyped while the first request is still in flight used to leave the map showing whichever response happened to land last, so a driver could be looking at the line to the address they had already replaced. Each caller still receives its own parsed route, so a caller that wants the data of a superseded request keeps getting it - only the drawing is suppressed. RouteLayer.clear likewise supersedes anything in flight.
  • draw(route: ParsedRoute): void: Draw (or update) a parsed route's line on the map. Safe to call before the style has loaded: the route is drawn as soon as the style is parsed, even while tiles are still loading, and before that it is stored (the latest call wins) and installed the moment the style is ready, instead of throwing MapLibre's "Style is not done loading".
  • setWaypoints(waypoints: readonly LngLatLike[]): void: Set the intermediate stops drawn by the endpoint markers, in order. routePath fills these in from its own via points, so this is only needed when drawing a route parsed elsewhere (e.g. a route fetched by the app and handed to draw). An empty array clears them.
  • drawGeometry(coordinates: [number, number][]): void: Draw a bare line from coordinates, without a parsed OSRM route. RouteLayer.draw expects a ParsedRoute because it is normally fed by RouteLayer.route. Callers that already have geometry and nothing else, an agent tool result, a stored polyline, a hand-built preview, had to invent a ParsedRoute with zeroed distance and duration that draw never reads. This is that path, named honestly.
  • drawAlternatives(routes: ParsedRoute[], selectedIndex?: number): void: Draw a set of routes: one selected, the rest as dimmer alternatives beneath it. Offering alternatives is table stakes for a navigation UI, and the selected route keeps every feature of RouteLayer.draw (progress, manoeuvre arrow, corridors, route effects). Pass the index of the route to select; out-of-range values clamp to the first route. Calling with a single route is equivalent to draw, and calling with an empty array clears everything.
  • onSelectAlternative(handler: ((index: number) => void) | undefined): void: Register a click handler for the alternative lines. The index is the position within the array last passed to RouteLayer.drawAlternatives, so a caller can re-issue that call with the new selection. Passing undefined removes the handler.
  • setFerrySegments(segments: [number, number][][]): void: Draw ferry legs of the selected route as dashes over its line, so water crossings do not read as driving. Supplied as explicit geometries rather than derived from the route, because line-dasharray cannot be data-driven: a ferry leg needs its own layer, and only the caller knows which parts of their route are ferries.
  • clearFerrySegments(): void: Remove the ferry dashes.
  • setLineStyle(style: RouteLineStyle): void: Override the drawn line's paint at runtime, over whatever the design or the built-in look set. Route styling is not always static: a route can be provisional, or a straight-line approximation that must not be mistaken for a surveyed one. That is a paint change on a route already drawn, so it belongs here rather than in the constructor's design. Overrides survive style reloads. Pass {} to clear them.
  • setProgress(fraction: number): void: Sets how much of the route has been travelled, as a fraction in [0, 1] of the line's length. The travelled part dims to progressColor (the "vanishing route line"); 0 restores the untinted line. The value is remembered across draw calls and style swaps. Pair with the guidance module's distance-remaining to derive the fraction.
  • setManeuver(lngLat: [number, number], bearingDeg: number): void: Shows (or moves) the upcoming-manoeuvre arrow: a small map-aligned arrow at lngLat rotated to bearingDeg (clockwise from north). Survives style swaps until clearManeuver.
  • clearManeuver(): void: Hides the manoeuvre arrow.
  • setAlertCorridors(corridors: readonly (readonly [number, number])[][], design?: NavAlertsDesign): void: Highlights average-speed enforcement corridors on the route line. A corridor is a stretch of the route between an entry and an exit camera, so it is a property of the LINE, not a point alert: drawing it as a tinted overlay above the route is what makes "you are inside a section check right now" readable at a glance, and it is the only part of the alert design that persists rather than firing once. Pass the corridor geometries (arrays of [lng, lat] along the route) and, optionally, a Studio alerts design for the colour and opacity; without one the layer uses the design carried by the owning map, then a built-in tint. An empty array clears the highlight. Survives style swaps like the route itself.
  • clearAlertCorridors(): void: Removes the corridor highlight (the route line itself is untouched).
  • clear(): void: Remove the route's layers and source from the map. Any route request still in flight is superseded, so a late response cannot redraw a route the caller has already cleared.
  • destroy(): void: Remove the route and detach the layer's style.load listener and any pending wait for the style. Call when disposing of the layer (the map itself is left untouched).

Example

ts
import { map } from "./map.ts";
import { RouteLayer } from "@mapmap/maps";

const routes = new RouteLayer(map);
const route = await routes.route([-0.1276, 51.5072], [-1.2577, 51.752], {
  profile: "truck",
  truck: { heightM: 4.2, weightT: 26 },
});
console.log(`${(route.distanceM / 1000).toFixed(1)} km, ${Math.round(route.durationS / 60)} min`);

Class

ts
class SearchBox { … }

A MapLibre IControl search bar: debounced suggestions, keyboard navigation, and a typed "select" event carrying the picked feature.

ts
const box = new SearchBox({ apiKey: "snk_…" });
box.on("select", ({ suggestion, hit }) => {
  console.log(suggestion.name, hit?.postcode);
});
map.map.addControl(box, "top-left");

Constructor and methods

  • constructor(options?: SearchBoxOptions)
  • on(event: "select", listener: SearchBoxSelectListener): () => void: Subscribe to the "select" event. Returns an unsubscribe function.
  • off(event: "select", listener: SearchBoxSelectListener): void: Unsubscribe a "select" listener.
  • onAdd(map?: SearchBoxMap): HTMLElement: The IControl hook: build the DOM and take the map handle.
  • onRemove(): void: The IControl hook: tear everything down.

Example

ts
import type { IControl } from "maplibre-gl";
import { map } from "./map.ts";
import { SearchBox } from "@mapmap/maps";

const search = new SearchBox({ apiKey: "snk_…", placeholder: "Search places" });
// Up to 0.25.1, SearchBox's type does not match maplibre-gl 6's IControl
// (isStyleLoaded may return void there), so strict TypeScript needs this cast.
// Fixed at source for the next release, after which addControl(search) compiles as is.
map.map.addControl(search as unknown as IControl, "top-left");
search.on("select", (e) => console.log(e.suggestion.name, e.hit?.postcode));

ThemeScheduler

Class

ts
class ThemeScheduler { … }

Applies the sun-appropriate theme now and at every subsequent sunrise/sunset until dispose. Pair with the OS dark-mode signal in the app if the user's system preference should win instead.

PropertyTypeDefaultDescription
readonly current"light" | "dark" | undefinedThe theme most recently applied, if any.

Constructor and methods

  • constructor(options: ThemeSchedulerOptions)
  • setPosition(lat: number, lng: number): void: Moves the observer (e.g. a new GPS fix region) and re-evaluates.
  • dispose(): void: Stops all future flips.

Example

ts
import { map } from "./map.ts";
import { ThemeScheduler } from "@mapmap/maps";

// Light map by day, dark after sunset, at the map's location.
const scheduler = new ThemeScheduler({
  lat: 51.5072,
  lng: -0.1276,
  onLight: () => map.setStyle("light"),
  onDark: () => map.setStyle("dark"),
});
// Later:
scheduler.dispose();

TransitStopsLayer

Class

ts
class TransitStopsLayer { … }

Bus stops and bus lines from the MapMap tiles host (see module docs).

PropertyTypeDefaultDescription
readonly ids{ sources: string[]; layers: string[]; }The source and layer ids this layer adds.
readonly readyPromise<boolean>Resolves true once the layers are added, false when the tiles index announces neither archive (the feature is not published there).

Constructor and methods

  • constructor(map: MapMapMap, options?: TransitStopsLayerOptions)
  • remove(): void: Remove the sources, layers and handlers.

Example

ts
import { map } from "./map.ts";
import { TransitStopsLayer } from "@mapmap/maps";

const stops = new TransitStopsLayer(map, {
  onStopClick: (stop) => console.log(stop.id, stop.name, stop.lines),
});
// Later:
stops.remove();

TransitVehiclesLayer

Class

ts
class TransitVehiclesLayer { … }

Live bus positions from GET /v1/transit/vehicles, drawn smoothly.

PropertyTypeDefaultDescription
readonly ids{ source: string; layers: string[]; }The source and layer ids this layer owns.
readonly ownerMapMapMapThe map this layer draws on (for companion layers such as the 3D buses).
readonly defaultVehicleTypeBusVehicleTypeWhat a bus whose feed names no body type is drawn as (defaultVehicleType, default "generic").

Constructor and methods

  • constructor(map: MapMapMap, options?: TransitVehiclesLayerOptions)
  • start(): void: Start polling and drawing. Safe to call before the style has loaded: the layer installs as soon as the style is parsed, even while tiles are still loading, and before that waits once for it (StyleWait).
  • stop(): void: Stop polling and drawing. The vehicles last drawn stay on the map.
  • remove(): void: Stop, and remove the layer's layers, source, image and popup.
  • vehicles(): TransitVehicle[]: The vehicles as last drawn (interpolated positions).
  • feedStatus(): TransitFeedReport: The feed's freshness after the latest poll (the last TransitFeedReport).
  • lastAnswer(): TransitFeedAnswer | null: The last successful answer's counts, or null before the first answer.
  • setFollowed(id: string | null): void: Follow one vehicle by id, or null to stop. Its feature carries followed: true; with marker: "bus" it wears a ring (2 px white, 2 px ink) and the others draw at 55 %. The camera is yours to move.
  • followed(): string | null: The id passed to setFollowed, or null.
  • onDraw(listener: (vehicles: readonly TransitDrawnVehicle[]) => void): () => void: Call listener with the vehicles as drawn after every draw (at most 10 a second while vehicles move) and when the followed vehicle changes. Returns the unsubscribe function. The 3D buses (TransitVehicles3dLayer, @mapmap/maps/models) are fed this way.
  • setSpriteOpacity(factor: number): void: Fade the top-down sprite and its followed ring (marker: "bus"), or the heading arrow (the default), by factor (0 to 1, on top of every other dim), so a companion layer can crossfade with it. Labels, pucks and dots are untouched. Default 1.

Example

ts
import { map } from "./map.ts";
import { TransitVehiclesLayer } from "@mapmap/maps";

const buses = new TransitVehiclesLayer(map, {
  bbox: "viewport",
  onFeedStatus: (report) => console.log(report.status),
});
buses.start();

VoiceGuidance

Class

ts
class VoiceGuidance { … }

Speaks core guidance updates through the browser's SpeechSynthesis, with severity-aware prosody, optional earcons, and mute/volume controls. Feed every update from the wasm GuidanceSession to VoiceGuidance.update.

PropertyTypeDefaultDescription
readonly availablebooleanWhether this environment can speak at all.
readonly mutedbooleanWhether announcements are currently muted.

Constructor and methods

  • constructor(options?: VoiceGuidanceOptions)
  • mute(): void: Mute announcements (also cancels anything mid-utterance).
  • unmute(): void: Unmute announcements. Prompts seen while muted are not replayed.
  • setVolume(volume: number): void: Set the volume for speech and earcons (clamped to 0–1).
  • update(update: VoiceGuidanceUpdate): void: Consume one guidance update. Speaks the update's prompt the first time its utteranceId appears; plays the warning earcon once per off-route episode. Safe to call in any environment.
  • dispose(): void: Cancel any speech in progress and forget the de-duplication state.

Example

ts
import { VoiceGuidance } from "@mapmap/maps";

const voice = new VoiceGuidance({ lang: "en-GB", volume: 0.9 });
voice.update({
  state: "navigating",
  spoken: { text: "In 300 metres, turn left", triggerDistanceM: 300, utteranceId: "step-4" },
});
voice.mute();

Functions (@mapmap/maps)

addBusMarkerImages, alertChipContent, alertContrastIssues, alertIconSvg, alertIconUrl, alertPresentation, alertSoundUrl, alertSpeedReadoutColor, applyColourTheme, applyGeoJSONDiff, applyPoiDesign, applyTerrain, bannerLanes, baseTheme, bearingBetween, bindFlythroughToScroll, buildAdrCheckBody, buildGeocodeUrl, buildLut, buildProbeUrl, buildRetrieveUrl, buildReverseGeocodeUrl, buildRouteQuery, buildRouteUrl, buildStyle, buildSuggestUrl, buildVertexSource, builtInPoiColor, busMarkerLayers, busPuckImage, busPuckImageOptions, busSilhouetteSdf, busSpriteBody, busTickImage, busVehicleType, cameraKindLabel, cameraKindsShownOnMap, cameraShownOnMap, cameraSpriteName, cameraSymbolLayer, capTransitBbox, checkSourceUrl, clipFilter, colourThemeMetadata, contrastRatio, createMap, createRouteEffect, creditTier, dataLayerColor, defaultNavAlertsDesign, defaultNavDesign, defaultPoiDesign, directionArrow, directionIconSvg, effectsFromStyleMetadata, extractGuidance, featuresetLayerIds, fixSetFromCollection, flythrough, flythroughPose, formatCoord, formatCoords, globeModelMatrix, gradeColourString, gradeStyleColours, hasBakedMarkers, haversineDistanceM, holdLayersOnTop, iconNameForManeuver, iconNameForStep, iconNamesForSteps, interpolateFixes, isMarkerGlyphId, isNameTextField, isSlot, keyedStyleUrl, keyedTilesUrl, laneArrowDirection, languageTextField, layersOnTopMoves, liveTargetLayerIds, lngLatToMercator, locateProjectionUniforms, lutApply, lutDigest, lutFromBase64, lutFromImageData, lutFromPngData, lutToBase64, lutToImageData, mapBrandSvg, mapGroundTheme, markerImage, markerImageDataKey, markerImageKey, markersFromTheme, markersFromThemeUrl, markerText, markerTextImageKey, mercatorModelMatrix, modelClipMatrices, multiplyMat4, namedBase, navAlertLeadDistanceM, navAlertSoundUrl, navCameraKind, navDesignFromTheme, navDesignFromThemeUrl, osmAndMoreCredit, parseCssColour, parseGeocodeResponse, parseHexColor, parseMarkers, parseNavAlertsDesign, parseNavDesign, parseOsrmRoute, parsePoiDesign, parseSuggestResponse, placesFromGeoJSON, poiDesignFromTheme, poiDesignFromThemeUrl, poiDesignIsDefault, poiTextColorExpression, prefersReducedMotion, projectionVariant, readProjection, registerPmtilesProtocol, relativeLuminance, removeTerrain, renderClockMs, renderMarkerImage, resetDiagnostics, resolveBaseId, resolveSlot, resolveTerrain, resolveTheme, runMapDiagnostics, setMapLanguage, setProjectionUniforms, severityProsody, shortCredit, shortestArcDeg, shortestArcDelta, speak, sphereFrame, sphereSurface, ssmlToText, styleFromBase, styleGroundTheme, subdivideMercator, sunTimes, supportsTerrainDraping, territoryTilesSourceUrl, tessellateRouteRibbon, tidyPlaceName, toLngLat, toPmtilesUrl, transitArchiveUrl, transitFreshnessLabel, transitStopFromProperties, transitTileJsonUrl, transitUrlsFromIndex, truncateChars, uploadProbeBatch, validateColourTheme, validateUseTheme

addBusMarkerImages

Function

ts
function addBusMarkerImages(map: Pick<Map, "hasImage" | "addImage">): void;

Add the bus marker's images to the style, skipping any already there.

ParameterTypeDefaultDescription
mapPick<Map, "hasImage" | "addImage">required

alertChipContent

Function

ts
function alertChipContent(design: NavAlertsDesign, alert: CameraAlert): AlertChipContent;

The text/icon content of an alert chip, free of any styling tokens.

ParameterTypeDefaultDescription
designNavAlertsDesignrequired
alertCameraAlertrequired

Options and types: NavAlertsDesign, CameraAlert.

alertContrastIssues

Function

ts
function alertContrastIssues(design: NavAlertsDesign): AlertContrastIssue[];

Every chip colour pair in design that fails the contrast floor, in state order. An empty array means both states are legible (or, for colours this module cannot parse, not judgeable - those are skipped rather than reported as failures).

Advisory by design: the parser stays lenient and never rejects a theme on contrast. Studio surfaces these as warnings next to the pickers so a designer sees the problem while choosing, which is the only moment the warning can actually change the outcome.

ParameterTypeDefaultDescription
designNavAlertsDesignrequired

Options and types: NavAlertsDesign.

alertIconSvg

Function

ts
function alertIconSvg(design: NavAlertsDesign, kind: NavCameraKind | string): string;

The icon for a kind under a design, as a complete inline SVG string.

iconSet chooses the frame (a European circular plate, a US rounded plate, or no frame); the glyph inside always encodes the KIND, because that is the channel kind is allowed to travel on. "brand" draws the unframed glyph as its fallback - it expects an iconUrlOverrides entry, and alertIconUrl is what actually resolves one.

ParameterTypeDefaultDescription
designNavAlertsDesignrequired
kindNavCameraKind | stringrequired

Options and types: NavAlertsDesign, NavCameraKind.

alertIconUrl

Function

ts
function alertIconUrl(design: NavAlertsDesign, kind: NavCameraKind | string): string | undefined;

The override URL for a kind, if the design sets one. Overrides win over iconSet for that kind only; every other kind keeps the curated icon.

ParameterTypeDefaultDescription
designNavAlertsDesignrequired
kindNavCameraKind | stringrequired

Options and types: NavAlertsDesign, NavCameraKind.

alertPresentation

Function

ts
function alertPresentation(design: NavAlertsDesign, alert: CameraAlert, state?: {
    speeding?: boolean;
}): AlertPresentation;

Resolves a design plus live state into what to present.

Escalation is by INTENSITY, not identity: escalated restyles the same chip and re-uses the same earcon motif more insistently. It never swaps in a different icon or a different sound - kind is carried by the icon and by speech, urgency by timbre, and mixing the two channels is how drivers end up unable to tell "a camera" from "you are speeding".

ParameterTypeDefaultDescription
designNavAlertsDesignrequired
alertCameraAlertrequired
state?{ speeding?: boolean; }not stated

Options and types: NavAlertsDesign, CameraAlert.

alertSoundUrl

Function

ts
function alertSoundUrl(design: NavAlertsDesign, escalated: boolean): string;

The earcon URL for a design in the calm or escalated state.

A design-level alertSoundUrl / escalatedSoundUrl override wins; otherwise the chosen built-in resolves against the hosted earcon library. There is deliberately no per-kind sound: kind travels in the icon and in speech, urgency travels in timbre.

ParameterTypeDefaultDescription
designNavAlertsDesignrequired
escalatedbooleanrequired

Options and types: NavAlertsDesign.

alertSpeedReadoutColor

Function

ts
function alertSpeedReadoutColor(design: NavAlertsDesign, escalated: boolean): string | undefined;

The colour a host should paint the SPEED readout, given a design and whether the driver is speeding.

Deliberate division of labour: the escalation the driver reads is the speed number turning the escalated colour, while the alert chip stays legible in its own escalated tokens. Colouring the card and leaving the speed untouched puts the urgency on the wrong element - the driver has to act on the speed, so the speed is what changes. Returns undefined when calm, meaning "leave the readout in its normal colour".

ParameterTypeDefaultDescription
designNavAlertsDesignrequired
escalatedbooleanrequired

Options and types: NavAlertsDesign.

applyColourTheme

Function

ts
function applyColourTheme(style: StyleSpecification, theme: {
    color_theme?: ColourTheme;
    layers?: Record<string, {
        use_theme?: unknown;
    }>;
}): StyleSpecification;

The compilers' last step: grade style through theme.color_theme, skipping the layers whose override says use_theme: "none", and stamp metadata["mapmap:color-theme"] as the third metadata key (after effects and territories). A theme without color_theme returns style untouched, so its bytes do not move. LOCKSTEP with the end of sn_style::compile.

ParameterTypeDefaultDescription
styleStyleSpecificationrequired
theme{ color_theme?: ColourTheme; layers?: Record<string, { use_theme?: unknown; }>; }required

Options and types: ColourTheme.

applyGeoJSONDiff

Function

ts
function applyGeoJSONDiff(data: GeoJSON.FeatureCollection, diff: GeoJSONSourceDiff, promoteId?: string): GeoJSON.FeatureCollection;

Apply a MapLibre GeoJSON diff to a local FeatureCollection.

ParameterTypeDefaultDescription
dataGeoJSON.FeatureCollectionrequired
diffGeoJSONSourceDiffrequired
promoteId?stringnot stated

applyPoiDesign

Function

ts
function applyPoiDesign(map: PoiPaintMap, design: PoiDesign, fallbackTextColor?: string): void;

Applies a design's per-category label text colours to every poi-labels layer on a live map (including per-territory clones named poi-labels@<territory>). fallbackTextColor is the colour non-overridden categories keep - pass the style's poi-labels text colour (the theme's textSecondary slot; defaults to the light-base value). A default design restores the plain fallback, so this is safe to call on every design change.

NOTE: runtime paint changes do not survive a later setStyle; re-apply after style swaps (the MapMap website bakes the expression into the style object instead for exactly this reason).

ParameterTypeDefaultDescription
mapPoiPaintMaprequired
designPoiDesignrequired
fallbackTextColor?stringnot stated

Options and types: PoiDesign.

applyTerrain

Function

ts
function applyTerrain(map: Map, cfg: ResolvedTerrain): void;

Add the sources/layers and switch terrain on. Safe to call repeatedly.

ParameterTypeDefaultDescription
mapMaprequired
cfgResolvedTerrainrequired

bannerLanes

Function

ts
function bannerLanes(banner: BannerInstruction): LaneIndication[];

Lane entries of a banner's sub line, if it carries a lane diagram.

Banner lane components only carry active (the recommended lane), the gateway drops the per-lane valid flag from banners, keeping it in the raw route's intersections[].lanes. An active lane is by definition usable, so valid is true for active lanes and unknown (undefined, never false) for the rest: a non-recommended lane may still be legal. Read route.raw legs[].steps[].intersections[].lanes for the full valid set.

ParameterTypeDefaultDescription
bannerBannerInstructionrequired

Options and types: BannerInstruction.

baseTheme

Function

ts
function baseTheme(id: string): Theme | undefined;

A fresh theme document for a named base, or undefined for an id the catalogue never had. Every call returns its own object, so editing one is safe.

ParameterTypeDefaultDescription
idstringrequired

bearingBetween

Function

ts
function bearingBetween(a: [number, number], b: [number, number]): number;

Initial great-circle bearing from a to b, degrees clockwise from north, normalised to [0, 360).

ParameterTypeDefaultDescription
a[number, number]required
b[number, number]required

bindFlythroughToScroll

Function

ts
function bindFlythroughToScroll(controller: FlythroughController, target?: HTMLElement | Window): () => void;

Scrollytelling: bind a flythrough to a scroll position, so scrolling a story column scrubs the camera along the route. The binder pauses the controller (scroll owns the timeline) and seeks it to the scrolled fraction - immediately on bind, then on every scroll. Returns the unbind function.

ts
const replay = flythrough(map, route);
const unbind = bindFlythroughToScroll(replay, document.querySelector("#story")!);
ParameterTypeDefaultDescription
controllerFlythroughControllerrequired
target?HTMLElement | Windownot stated

Options and types: FlythroughController.

buildAdrCheckBody

Function

ts
function buildAdrCheckBody(request: AdrCheckRequest): Record<string, unknown>;

Builds the exact wire body the gateway deserialises (sn-gateway routes/adr.rs → sn_adr::AdrVehicleProfile): {"adr": {"dimensions": {…}, "tunnel_code"?, "hazmat"}, "tunnel_category"}. Unset dimensions default to the EU 96/53/EC artic maximums, mirroring TruckDimensions::default(). Exported for contract tests.

ParameterTypeDefaultDescription
requestAdrCheckRequestrequired

Options and types: AdrCheckRequest.

buildGeocodeUrl

Function

ts
function buildGeocodeUrl(baseUrl: string, query: string, options?: GeocodeOptions): string;

Build the full forward-geocode URL. baseUrl is the gateway origin (trailing slashes are trimmed). Note the API key is NOT embedded - fetches of this URL need the Authorization: Bearer snk_… header, exactly like buildRouteUrl.

ParameterTypeDefaultDescription
baseUrlstringrequired
querystringrequired
options?GeocodeOptionsnot stated

Options and types: GeocodeOptions.

buildLut

Function

ts
function buildLut(fn: (r: number, g: number, b: number) => [number, number, number]): LutBytes;

Build a LUT by evaluating fn at every lattice point. fn gets the lattice indices (0..15) and returns 0..255 channel values, which are rounded and clamped.

ParameterTypeDefaultDescription
fn(r: number, g: number, b: number) => [number, number, number]required

buildProbeUrl

Function

ts
function buildProbeUrl(baseUrl: string): string;

The /v1/probe endpoint for a gateway origin (trailing slashes trimmed).

ParameterTypeDefaultDescription
baseUrlstringrequired

buildRetrieveUrl

Function

ts
function buildRetrieveUrl(gatewayUrl: string, id: string): string;

Build the GET /geocode/retrieve URL for one document id.

ParameterTypeDefaultDescription
gatewayUrlstringrequired
idstringrequired

buildReverseGeocodeUrl

Function

ts
function buildReverseGeocodeUrl(baseUrl: string, point: LngLatLike, options?: ReverseGeocodeOptions): string;

Build the full reverse-geocode URL. Same auth caveat as forward.

ParameterTypeDefaultDescription
baseUrlstringrequired
pointLngLatLikerequired
options?ReverseGeocodeOptionsnot stated

Options and types: LngLatLike, ReverseGeocodeOptions.

buildRouteQuery

Function

ts
function buildRouteQuery(truck?: TruckParams, guidance?: GuidanceQuery): string;

Build the OSRM query string (without the leading ?) for a request.

ParameterTypeDefaultDescription
truck?TruckParamsnot stated
guidance?GuidanceQuerynot stated

Options and types: TruckParams.

buildRouteUrl

Function

ts
function buildRouteUrl(baseUrl: string, profile: RouteProfile, points: LngLatLike[], truck?: TruckParams, guidance?: GuidanceQuery): string;

Build the full OSRM route URL. baseUrl is the gateway origin (trailing slashes are trimmed); points is the ordered coordinate path.

ParameterTypeDefaultDescription
baseUrlstringrequired
profileRouteProfilerequired
pointsLngLatLike[]required
truck?TruckParamsnot stated
guidance?GuidanceQuerynot stated

Options and types: RouteProfile, LngLatLike, TruckParams.

buildStyle

Function

ts
function buildStyle(options?: BuildStyleOptions): StyleSpecification;
ParameterTypeDefaultDescription
options?BuildStyleOptionsnot stated

Options and types: BuildStyleOptions.

buildSuggestUrl

Function

ts
function buildSuggestUrl(gatewayUrl: string, query: string, options?: SuggestUrlOptions): string;

Build the GET /geocode/suggest URL. The API key is NOT embedded, fetches need the Authorization: Bearer snk_… header, exactly like buildGeocodeUrl.

ParameterTypeDefaultDescription
gatewayUrlstringrequired
querystringrequired
options?SuggestUrlOptionsnot stated

Options and types: SuggestUrlOptions.

buildVertexSource

Function

ts
function buildVertexSource(args: ProjectionArgs, body: string): string;

A GLSL ES 3.00 vertex shader around MapLibre's projection prelude. body uses in/out and calls projectTile(vec2) (mercator 0..1, ground) or projectTileFor3D(vec2, float elevationMetres).

ParameterTypeDefaultDescription
argsProjectionArgsrequired
bodystringrequired

Options and types: ProjectionArgs.

builtInPoiColor

Function

ts
function builtInPoiColor(categoryId: string): string | undefined;

The built-in dot colour for a category id.

ParameterTypeDefaultDescription
categoryIdstringrequired

busMarkerLayers

Function

ts
function busMarkerLayers(prefix: string, source: string, opacity: {
    feed: number;
    othersDimmed: boolean;
}): LayerSpecification[];

The bus marker's layer specs, bottom to top: the dot (z8 to 12), the heading tick and the line-number puck (z12 to 15.5), the followed ring, the sprite and its label (z15.5 and in). feed is the feed-level opacity, othersDimmed whether a vehicle is followed.

ParameterTypeDefaultDescription
prefixstringrequired
sourcestringrequired
opacity{ feed: number; othersDimmed: boolean; }required

busPuckImage

Function

ts
function busPuckImage(size?: number, options?: {
    followed?: boolean;
}): Rgba8;

The line-number puck as raw RGBA: an ink (#0f1115) disc of radius 9 with a 1.5 px white halo, centred on a 24 px square drawn at size pixels (default 48, pixel ratio 2). With followed, the ring the followed vehicle wears instead: 2 px white then 2 px ink, on a 28 px square (default 56). The layer stretches its middle column to fit the line number (busPuckImageOptions).

ParameterTypeDefaultDescription
size?numbernot stated
options?{ followed?: boolean; }not stated

busPuckImageOptions

Function

ts
function busPuckImageOptions(size?: number, options?: {
    followed?: boolean;
}): Partial<StyleImageMetadata>;

addImage options for a busPuckImage: its pixel ratio, a one-px stretchable middle column, and the content box icon-text-fit fits the line number into (for the followed puck, inset by the extra 2 px of ring so both pills are the same width around the same text).

ParameterTypeDefaultDescription
size?numbernot stated
options?{ followed?: boolean; }not stated

busSilhouetteSdf

Function

ts
function busSilhouetteSdf(heightPx?: number, radius?: number, type?: BusVehicleType): Sdf;

A top-down bus of body type, nose north, as a MapLibre SDF image (addImage(id, img, { sdf: true })): white, with the signed distance to the outline in alpha by the TinySDF convention (edge at alpha 191.25, so 192 rounds inside; radius px of distance per 255 * 1 alpha; MapLibre reads halo widths in true pixels when radius is 8). Drawn from the modelled bus's top view: the body outline, with the windscreen (a block behind the nose, the heading cue), the roof hatches and (single-decker) the roof pod's front edge cut out, so the halo colour shows through them as roof detail. At the default size the canvas is 48 px wide and the double-decker's 96 px tall (body 72 x 22 px); heightPx scales the double-decker's height and every other type by the same factor.

ParameterTypeDefaultDescription
heightPx?numbernot stated
radius?numbernot stated
type?BusVehicleTypenot stated

Options and types: BusVehicleType.

busSpriteBody

Function

ts
function busSpriteBody(type?: BusVehicleType): {
    length: number;
    width: number;
};

A body type's outline length and width on the reference canvas, px.

ParameterTypeDefaultDescription
type?BusVehicleTypenot stated

Options and types: BusVehicleType.

busTickImage

Function

ts
function busTickImage(pixelRatio?: number): Rgba8;

The heading tick as raw RGBA: an ink triangle 8 px wide and 6 px tall, pointing north, with a 1 px white edge, centred on a 12 x 10 px canvas drawn at pixelRatio (default 2). The layer orbits it round the puck with icon-offset, which MapLibre turns with icon-rotate, so one image serves every bearing.

ParameterTypeDefaultDescription
pixelRatio?numbernot stated

busVehicleType

Function

ts
function busVehicleType(properties: Record<string, unknown> | null | undefined): BusVehicleType | null;

The body type a feed feature's properties name, or null when they name none: vehicle_type ("double", "single", "mini" or "generic") first, then deck ("double" or "single"). Anything else is unknown.

ParameterTypeDefaultDescription
propertiesRecord<string, unknown> | null | undefinedrequired

cameraKindLabel

Function

ts
function cameraKindLabel(kind: NavCameraKind | string): string;

Human-readable name for a camera kind, used in the chip's text and in the spoken announcement. Kind lives here and in the icon, never in the earcon.

ParameterTypeDefaultDescription
kindNavCameraKind | stringrequired

Options and types: NavCameraKind.

cameraKindsShownOnMap

Function

ts
function cameraKindsShownOnMap(design: NavAlertsDesign, mode?: MapDisplayMode): NavCameraKind[];

The camera kinds a style should draw in the given mode, in the canonical kind order. Feed it straight into a MapLibre filter (see cameraSymbolLayer); an empty array means "draw nothing", which a caller must honour by removing or hiding the layer.

ParameterTypeDefaultDescription
designNavAlertsDesignrequired
mode?MapDisplayModenot stated

Options and types: NavAlertsDesign, MapDisplayMode.

cameraShownOnMap

Function

ts
function cameraShownOnMap(design: NavAlertsDesign, kind: NavCameraKind | string, mode?: MapDisplayMode): boolean;

Whether a kind's pin should be drawn on the map in the given mode.

Browsing and navigating are separate switches because they are separate decisions - the market warns with or without a planned route, so a design that shows a camera on the planning map is not thereby committed to a cluttered driving map, nor the reverse.

ParameterTypeDefaultDescription
designNavAlertsDesignrequired
kindNavCameraKind | stringrequired
mode?MapDisplayModenot stated

Options and types: NavAlertsDesign, NavCameraKind, MapDisplayMode.

cameraSpriteName

Function

ts
function cameraSpriteName(kind: NavCameraKind | string, variant?: "light" | "dark"): string;

Sprite image id for a camera kind, as built into the published sprite sheet by map-assets/icons/cameras/generate.mjs.

LOCKSTEP: the file names in map-assets/sprites/svg/camera-*.svg are exactly these ids, spreet names each image after its file.

ParameterTypeDefaultDescription
kindNavCameraKind | stringrequired
variant?"light" | "dark"not stated

Options and types: NavCameraKind.

cameraSymbolLayer

Function

ts
function cameraSymbolLayer(design: NavAlertsDesign, source: string, mode?: MapDisplayMode, variant?: "light" | "dark", id?: string): Record<string, unknown>;

A MapLibre symbol layer that draws camera POIs from the sprite sheet.

Additive by design: the style compiler is untouched and ships no camera layer of its own, because cameras arrive as host data (the gateway's POST /v1/cameras/along, projected into a GeoJSON source) rather than in the vector tiles. Point this at that source and the sprite icons built from map-assets/icons/cameras render at the design's size, zoom floor and per-mode visibility.

The features must carry a kind property holding one of NAV_CAMERA_KINDS or any wire spelling navCameraKind accepts (the gateway's redlight, OSM's traffic_signals, …); an unrecognised or absent value falls back to the unknown icon, never to a guess at a specific camera type.

ParameterTypeDefaultDescription
designNavAlertsDesignrequired
sourcestringrequiredGeoJSON source id holding the camera features.
mode?MapDisplayModenot stated
variant?"light" | "dark"not statedSprite variant to draw: "light" icons read on a dark basemap, "dark" icons on a light one.
id?stringnot stated

Options and types: NavAlertsDesign, MapDisplayMode.

capTransitBbox

Function

ts
function capTransitBbox(bbox: [number, number, number, number], maxSqDeg?: number): [number, number, number, number];

A [west, south, east, north] box shrunk around its centre to at most maxSqDeg square degrees (the gateway refuses larger ones).

ParameterTypeDefaultDescription
bbox[number, number, number, number]required
maxSqDeg?numbernot stated

checkSourceUrl

Function

ts
function checkSourceUrl(url: string, allowPmtiles: boolean): string | undefined;

The URL rules for a customer source: https:// (or, with allowPmtiles, pmtiles://https://), no user name or password, no literal IP address, no localhost, no spaces, at most MAX_SOURCE_URL_CHARS. Returns the reason, or undefined when the URL passes. Mirrors sn_style::check_source_url.

ParameterTypeDefaultDescription
urlstringrequired
allowPmtilesbooleanrequired

clipFilter

Function

ts
function clipFilter(polygon: Polygon | MultiPolygon, original: FilterSpecification | null | undefined, minzoom?: number): FilterSpecification;

A layer filter that keeps original and hides every feature touching polygon: ["all", original, [">", ["distance", polygon], 0]] (just the distance test when there is no original filter). With minzoom, the distance test only applies from that zoom up.

ParameterTypeDefaultDescription
polygonPolygon | MultiPolygonrequired
originalFilterSpecification | null | undefinedrequired
minzoom?numbernot stated

colourThemeMetadata

Function

ts
function colourThemeMetadata(theme: ColourTheme, lut: LutBytes): Record<string, unknown>;

metadata["mapmap:color-theme"]: name, size, strength and the LUT digest.

ParameterTypeDefaultDescription
themeColourThemerequired
lutLutBytesrequired

Options and types: ColourTheme, LutBytes.

contrastRatio

Function

ts
function contrastRatio(a: unknown, b: unknown): number | undefined;

WCAG 2.x contrast ratio between two hex colours, from 1 (identical) to 21 (black on white). Order-independent. Returns undefined when either colour cannot be parsed, so callers can distinguish "not judgeable" from "fails".

ParameterTypeDefaultDescription
aunknownrequired
bunknownrequired

createMap

Function

ts
function createMap(options: MapMapOptions): MapMapMap;

Functional alias for MapMapMap, mirroring the Mapbox new Map feel.

ParameterTypeDefaultDescription
optionsMapMapOptionsrequired

Options and types: MapMapOptions.

Example

ts
import "maplibre-gl/dist/maplibre-gl.css";
import { createMap } from "@mapmap/maps";

const map = createMap({
  container: "map",       // an element id or the element itself
  apiKey: "snk_…",
  style: "light",         // or "dark", a Studio theme, a StyleSpecification or a style URL
  center: [-2.5879, 51.4545],
  zoom: 13,
});
await map.whenReady();
map.map.setPitch(45);     // map.map is the underlying MapLibre map

createRouteEffect

Function

ts
function createRouteEffect(name: RouteEffectName, geometry: RouteGeometry, options?: RouteFlowOptions): RouteEffectLayer;

Create a named route effect layer. Throws an agent-readable error for unknown names (the accepted list included).

ParameterTypeDefaultDescription
nameRouteEffectNamerequired
geometryRouteGeometryrequired
options?RouteFlowOptionsnot stated

Options and types: RouteEffectName, RouteGeometry, RouteFlowOptions.

Example

ts
import { map } from "./map.ts";
import { createRouteEffect } from "@mapmap/maps";

const effect = createRouteEffect("flow", {
  type: "LineString",
  coordinates: [[-0.1276, 51.5072], [-0.0877, 51.5055]],
});
map.map.addLayer(effect);

creditTier

Function

ts
function creditTier(room: number, fullWidth: number, shortWidth: number): CreditTier;

The CreditTier for a credit with room px for its text, whose full line is fullWidth px and short line (with the (i) and its gap) shortWidth px wide at the 6px standard.

ParameterTypeDefaultDescription
roomnumberrequired
fullWidthnumberrequired
shortWidthnumberrequired

dataLayerColor

Function

ts
function dataLayerColor(style?: DataLayerStyle): string | ExpressionSpecification;

The colour expression for style.

ParameterTypeDefaultDescription
style?DataLayerStylenot stated

Options and types: DataLayerStyle.

defaultNavAlertsDesign

Function

ts
function defaultNavAlertsDesign(): NavAlertsDesign;

Defaults for the optional alerts block. LOCKSTEP: mirrors defaultNavAlertsDesign in website/lib/studio-nav.ts.

Calm chip = the banner's dark pill, so an unstyled alert already matches the rest of the guidance surface. Escalated = a red that clears 4.5:1 against white text.

Per-kind defaults follow the "visual always, audio conditional" rule: the three confidently classified kinds alert unconditionally, a mobile site (a location where enforcement sometimes happens, not a device) warns only if speeding, and an unclassified camera stays on the map but does not interrupt a drive.

defaultNavDesign

Function

ts
function defaultNavDesign(): NavDesign;

Defaults mirror what the SDK draws today with no design: RouteLayer's signal-blue line over a dark casing, and GuidanceBanner's dark pill.

defaultPoiDesign

Function

ts
function defaultPoiDesign(): PoiDesign;

No overrides: every category keeps its built-in dot and label colours.

directionArrow

Function

ts
function directionArrow(direction: string): string;

Unicode arrow for a lane/maneuver direction (OSRM indication strings). A text-only fallback; sprite-based lane icons ship with the map assets.

ParameterTypeDefaultDescription
directionstringrequired

directionIconSvg

Function · also exported from @mapmap/maps/direction-icons

ts
function directionIconSvg(type?: string, modifier?: string, drivingSide?: string): string;

Inline SVG markup for an OSRM-shaped maneuver (see iconNameForManeuver).

ParameterTypeDefaultDescription
type?stringnot stated
modifier?stringnot stated
drivingSide?stringnot stated

effectsFromStyleMetadata

Function

ts
function effectsFromStyleMetadata(metadata: unknown): {
    route: "flow";
    params?: Record<string, unknown>;
} | undefined;

The effects block from a compiled style's metadata, if the style carries a valid one ({ route: "flow", params? }). Lenient by design, it reads FOREIGN styles (hosted URLs, baked packages), so anything malformed returns undefined rather than throwing.

ParameterTypeDefaultDescription
metadataunknownrequired

extractGuidance

Function

ts
function extractGuidance(route: ParsedRoute): StepGuidance[];

Extracts per-step guidance from a parsed route (requires the route to have been requested with steps: true and voice/banner enabled). Steps without instructions yield empty arrays, never holes.

ParameterTypeDefaultDescription
routeParsedRouterequired

Options and types: ParsedRoute.

featuresetLayerIds

Function

ts
function featuresetLayerIds(id: FeaturesetId): readonly string[];

The layer ids a featureset covers (all of them, present or not).

ParameterTypeDefaultDescription
idFeaturesetIdrequired

Options and types: FeaturesetId.

fixSetFromCollection

Function

ts
function fixSetFromCollection(collection: unknown): FixSet;

The fixes in one gateway answer, keyed by vehicle id. Features without a usable point or time are skipped.

ParameterTypeDefaultDescription
collectionunknownrequired

flythrough

Function

ts
function flythrough(map: MapMapMap | Map, route: RouteGeometry | ParsedRoute, options?: FlythroughOptions): FlythroughController;

Cinematic route replay: fly the camera along a route line with a chase-cam bearing (eased along the shortest arc, so junctions glide instead of spinning), at a configurable pitch/zoom/speed. Returns a transport-style controller; nothing moves until play() or seek().

ts
const route = await routes.route(from, to);
const replay = flythrough(map, route, { pitch: 60, durationMs: 15000 });
replay.onProgress((t) => scrubber.value = String(t));
replay.play();

Drives the camera with jumpTo once per animation frame (the standard MapLibre scrub pattern). Runs under any projection; on globe the ride is unanchored but valid. Accepts a ParsedRoute (from RouteLayer) or a bare GeoJSON LineString geometry.

ParameterTypeDefaultDescription
mapMapMapMap | Maprequired
routeRouteGeometry | ParsedRouterequired
options?FlythroughOptionsnot stated

Options and types: MapMapMap, RouteGeometry, ParsedRoute, FlythroughOptions.

Example

ts
import { map } from "./map.ts";
import { RouteLayer, flythrough } from "@mapmap/maps";

const route = await new RouteLayer(map).route([-0.1276, 51.5072], [-0.0877, 51.5055]);
const replay = flythrough(map, route, { pitch: 60, durationMs: 15000 });
replay.play();

flythroughPose

Function

ts
function flythroughPose(coordinates: [number, number][], t: number, lookAheadM?: number): FlythroughPose;

The camera pose at progress t (0-1) along a route: the interpolated point that fraction of the total distance along the line, with a chase-cam bearing towards the point lookAheadM further on. Pure - exported for tests and for apps that drive the camera themselves.

ParameterTypeDefaultDescription
coordinates[number, number][]required
tnumberrequired
lookAheadM?numbernot stated

formatCoord

Function

ts
function formatCoord(point: LngLatLike): string;

Format one point as an OSRM lon,lat coordinate.

ParameterTypeDefaultDescription
pointLngLatLikerequired

Options and types: LngLatLike.

formatCoords

Function

ts
function formatCoords(points: LngLatLike[]): string;

Format an ordered list of points as an OSRM coordinate path (lon,lat;lon,lat;…). At least two points are required, matching the gateway, which rejects single-coordinate requests.

ParameterTypeDefaultDescription
pointsLngLatLike[]required

Options and types: LngLatLike.

globeModelMatrix

Function

ts
function globeModelMatrix(lngLat: [number, number], altitudeM: number): Float64Array;

Local metres in the three.js frame (X east, Y up, Z south) to unit-sphere space, column-major. A tangent plane at the anchor: the sphere curves away from it by about 2 m at 5 km, which is sub-pixel at every zoom where a 5 km scene fills the screen.

ParameterTypeDefaultDescription
lngLat[number, number]required
altitudeMnumberrequired

gradeColourString

Function

ts
function gradeColourString(lut: LutBytes, value: string, strength?: number): string;

Grade one colour string, or return it unchanged when it is not one of the forms the compilers grade.

Graded: #rgb, #rgba, #rrggbb, #rrggbbaa (any case) and rgb(r,g,b) / rgba(r,g,b,a) with integer channels 0..255 (plain spaces allowed around each value). Output: hex in gives lowercase hex out, #rrggbb for the 3 and 6 digit forms and #rrggbbaa for the 4 and 8 digit forms (alpha kept); rgb()/rgba() in gives the same function out with no spaces, rgba keeping its original alpha token verbatim. Anything else (hsl(), named colours, percentages, #12), and everything at strength 0, is returned as is.

ParameterTypeDefaultDescription
lutLutBytesrequired
valuestringrequired
strength?numbernot stated

Options and types: LutBytes.

gradeStyleColours

Function

ts
function gradeStyleColours(style: StyleSpecification, lut: LutBytes, opts?: GradeStyleOptions): StyleSpecification;

Grade every colour in a compiled style through lut: each string under layers[*].paint and layers[*].layout and under every entry of metadata["mapmap:territories"] (the per-territory paint diffs), recursing through expressions, so interpolate, step, match and case stops are graded too. Strings follow gradeColourString's rule.

Left untouched: layers in skipLayerIds, layers whose metadata["mapmap:use-theme"] is "none" (and those layers' entries in the territory diffs), and the root light, sky and sprite. That is the one difference from Mapbox's full-frame LUT, which the runtime ColourThemeLayer matches instead.

Returns a new style; the input is not modified.

ParameterTypeDefaultDescription
styleStyleSpecificationrequired
lutLutBytesrequired
opts?GradeStyleOptionsnot stated

Options and types: LutBytes, GradeStyleOptions.

hasBakedMarkers

Function

ts
function hasBakedMarkers(map: MapMapMap | Map): boolean;

Whether the map's current style carries compiler-baked marker layers, i.e. its markers already render in any MapLibre client, with no SDK code.

Useful for deciding whether to construct a MarkersLayer at all: you only need one to CHANGE the markers at runtime, or to render the custom data: image markers a static sprite cannot carry.

ParameterTypeDefaultDescription
mapMapMapMap | Maprequired

Options and types: MapMapMap.

haversineDistanceM

Function

ts
function haversineDistanceM(a: {
    lat: number;
    lon: number;
}, b: {
    lat: number;
    lon: number;
}): number;

Straight-line (haversine) distance between two points, metres.

ParameterTypeDefaultDescription
a{ lat: number; lon: number; }required
b{ lat: number; lon: number; }required

holdLayersOnTop

Function

ts
function holdLayersOnTop(map: Pick<Map, "getLayersOrder" | "getLayer" | "moveLayer" | "on" | "off">, ids: readonly string[] | (() => readonly string[])): () => void;

Keeps ids at the top of map's drawing order, bottom to top in the order given, from now on: once at the call and again on every styledata. Pass a function to have the ids read afresh on every raise. Ids not on the map are skipped, so the hold can start before its layers are added. Returns the release, which removes the listener (calling it again does nothing).

ParameterTypeDefaultDescription
mapPick<Map, "getLayersOrder" | "getLayer" | "moveLayer" | "on" | "off">required
idsreadonly string[] | (() => readonly string[])required

Example

ts
import { map } from "./map.ts";
import { holdLayersOnTop } from "@mapmap/maps";

// Keep your own layers above the basemap through style swaps and later additions.
const release = holdLayersOnTop(map.map, ["depots-circles", "depots-labels"]);
// Later, to stop holding them:
release();

iconNameForManeuver

Function · also exported from @mapmap/maps/direction-icons

ts
function iconNameForManeuver(type?: string, modifier?: string, drivingSide?: string): DirectionIconName;

Pick the icon for an OSRM-shaped maneuver (maneuver.type + maneuver.modifier, as returned by the MapMap gateway's OSRM endpoint and by Mapbox-style banner instructions).

Unknown or partial input degrades gracefully: unknown types fall back to the plain turn family and ultimately turn_straight, so the result is always a renderable icon.

ParameterTypeDefaultDescription
type?stringnot stated
modifier?stringnot stated
drivingSide?stringThere is deliberately no default: when the side is unknown a roundabout draws the plain turn glyph for its direction, and a u-turn the plain continue_uturn, rather than a glyph that may circulate the wrong wayThe side traffic drives on at this manoeuvre (OSRM step.driving_side). It selects the roundabout drawing ("left" = clockwise roundabout_lht_*, "right" = anticlockwise roundabout_*) and the u-turn arm. There is deliberately no default: when the side is unknown a roundabout draws the plain turn glyph for its direction, and a u-turn the plain continue_uturn, rather than a glyph that may circulate the wrong way.

iconNameForStep

Function · also exported from @mapmap/maps/direction-icons

ts
function iconNameForStep(step: DirectionIconStep): DirectionIconName;

Pick the icon straight from an OSRM route step, the preferred entry point for a single step. Reads maneuver.type/maneuver.modifier, takes the driving side from the step's own driving_side (so a UK roundabout draws clockwise and a UK u-turn uturn_right with no caller configuration), and returns the ferry icon for ferry-mode legs.

Rendering a whole turn list? Use iconNamesForSteps instead, a roundabout's icon cannot be resolved from one step alone.

ParameterTypeDefaultDescription
stepDirectionIconSteprequired

Options and types: DirectionIconStep.

iconNamesForSteps

Function · also exported from @mapmap/maps/direction-icons

ts
function iconNamesForSteps(steps: readonly DirectionIconStep[]): DirectionIconName[];

Icons for a whole turn list, the entry point for anything rendering consecutive steps, because roundabouts can only be resolved in context.

A roundabout's icon should show the manoeuvre's THROUGH angle: the turn between the road you arrive on and the road you leave on. No single step carries that. The enter step knows the approach (bearing_before) and the matching exit step knows the road taken (bearing_after), so this pass pairs them and gives both the same modifier. The pair shares one driving side too: the enter step's, or the exit step's when only it has one.

Without it, every roundabout on a route draws the same generic ring: the MapMap gateway sends roundabout steps with no modifier at all, and stock OSRM sends the ENTRY tangent instead, which is "left" for every roundabout in a left-hand-traffic country. Either way the icon stops telling one exit from another, which is exactly what it is there for.

A supplied roundabout modifier is deliberately overridden: it describes a different angle from the one being drawn. Everything else is left to iconNameForStep untouched.

ParameterTypeDefaultDescription
stepsreadonly DirectionIconStep[]required

Options and types: DirectionIconStep.

interpolateFixes

Function

ts
function interpolateFixes(prev: FixSet, next: FixSet, atMs: number): Rendered[];

Where every vehicle was at atMs (epoch milliseconds), between two consecutive polls. Pure: same inputs, same answer.

ParameterTypeDefaultDescription
prevFixSetrequired
nextFixSetrequired
atMsnumberrequired

Options and types: FixSet.

isMarkerGlyphId

Function

ts
function isMarkerGlyphId(value: unknown): value is MarkerGlyphId;

Whether value is one of the 21 marker glyph ids.

ParameterTypeDefaultDescription
valueunknownrequired

isNameTextField

Function

ts
function isNameTextField(textField: unknown): boolean;

True when a layer's text-field reads name/name:* properties, i.e. it is a place/POI/road-name label whose language can switch. Fields reading other properties (ref shields, house numbers) are not.

ParameterTypeDefaultDescription
textFieldunknownrequired

isSlot

Function

ts
function isSlot(value: unknown): value is Slot;

True when value is one of the three slot names.

ParameterTypeDefaultDescription
valueunknownrequired

keyedStyleUrl

Function

ts
function keyedStyleUrl(url: string, apiKey: string | undefined, baseUrl?: string): string;

A style URL with the key added, when it names a document on the key's own gateway that carries the key through to its tiles: a hosted style (/styles/{id}.json) or a territory style (/tiles/{territory}/style.json). The gateway stamps a ?api_key= it was sent onto the tiles the document points at, so the basemap works from any website. Any other URL, a URL that already has an api_key, or no key: returned unchanged.

ParameterTypeDefaultDescription
urlstringrequired
apiKeystring | undefinedrequired
baseUrl?stringnot stated

keyedTilesUrl

Function

ts
function keyedTilesUrl(apiKey: string, baseUrl?: string): string;

The keyed basemap source URL: the gateway's TileJSON for KEYED_TILES_TERRITORY, carrying the key as ?api_key=.

A TileJSON URL rather than a bare {z}/{x}/{y} template on purpose: the gateway fills in the zoom range and bounds from the archive header, adds an archive-version cache buster to the tile template, and stamps the same api_key on it, so MapLibre stays authenticated down to every tile. The query form (not a header) is what lets a plain style URL carry the key, and it is accepted for browser keys restricted by allowed_origins.

baseUrl is the gateway that issued the key; a self-hosted gateway without a planet archive should pass territoryTilesUrl instead.

ParameterTypeDefaultDescription
apiKeystringrequired
baseUrl?stringnot stated

laneArrowDirection

Function

ts
function laneArrowDirection(lane: LaneIndication): string;

The single direction a lane's arrow should show.

A lane that permits several movements ("straight or right") carries them all in directions, in the gateway's bitmask order, which is NOT the order the route cares about. Drawing directions[0] therefore shows a straight-ahead arrow on the lane the driver is being told to turn right from. activeDirection is the one the route actually takes, so it wins; the first permitted direction is only the fallback for lanes where the server could not resolve one.

ParameterTypeDefaultDescription
laneLaneIndicationrequired

Options and types: LaneIndication.

languageTextField

Function

ts
function languageTextField(language: string | null): DataDrivenPropertyValueSpecification<string>;

The text-field expression for labels in language, the requested language first, the Latin transliteration second, the local name last. null yields the compiled default (name:en, then name).

Typed as the widest value text-field accepts on both majors, because MapLibre 6 types setLayoutProperty's value parameter where 5.x took any, and a coalesce of gets is one such value. The expressions themselves are unchanged, so every caller keeps its current labels.

ParameterTypeDefaultDescription
languagestring | nullrequired

layersOnTopMoves

Function

ts
function layersOnTopMoves(order: readonly string[], ids: readonly string[]): string[];

The ids to move to the top of order, in the order to move them (each one moved to the very top, so the last moved draws over the rest). Empty when the ids present already close order in their own order, or when none of them is present. Ids not in order are skipped and a repeated id counts once. Pure.

ParameterTypeDefaultDescription
orderreadonly string[]required
idsreadonly string[]required

liveTargetLayerIds

Function

ts
function liveTargetLayerIds(map: Map, target: InteractionTarget): string[];

The target's layer ids that exist in the live style, in style order.

ParameterTypeDefaultDescription
mapMaprequired
targetInteractionTargetrequired

Options and types: InteractionTarget.

lngLatToMercator

Function

ts
function lngLatToMercator(lngLat: [number, number]): [number, number];

Project a [lng, lat] to web-mercator world coordinates in [0, 1] (MapLibre's MercatorCoordinate convention: x east, y south).

ParameterTypeDefaultDescription
lngLat[number, number]required

locateProjectionUniforms

Function

ts
function locateProjectionUniforms(gl: WebGL2RenderingContext, program: WebGLProgram): Record<ProjectionUniform, WebGLUniformLocation | null>;

Uniform locations for PROJECTION_UNIFORMS. A name the variant's prelude does not declare (the mercator prelude has no fallback matrix) is null, which WebGL treats as a no-op when set.

ParameterTypeDefaultDescription
glWebGL2RenderingContextrequired
programWebGLProgramrequired

lutApply

Function

ts
function lutApply(lut: LutBytes, rgb: readonly [number, number, number], strength?: number): [number, number, number];

Grade one RGB colour (channels 0..255) through lut, blended with the original by strength (0 = untouched, 1 = fully graded, default 1).

The algorithm, in this exact order (LOCKSTEP with the Rust and Studio ports): per channel s = v / 255 * 15, i0 = floor(s), i1 = min(i0 + 1, 15), f = s - i0; trilinear interpolation of the eight lattice corners along red, then green, then blue, each step a + (b - a) * f; then round(in + (lut - in) * strength) per channel, clamped to 0..255. Rounding is half up; every value is non-negative, so Rust's f64::round gives the same integer.

ParameterTypeDefaultDescription
lutLutBytesrequired
rgbreadonly [number, number, number]required
strength?numbernot stated

Options and types: LutBytes.

lutDigest

Function

ts
function lutDigest(lut: LutBytes): string;

FNV-1a 64-bit of the LUT bytes, as 16 lowercase hex characters.

ParameterTypeDefaultDescription
lutLutBytesrequired

Options and types: LutBytes.

lutFromBase64

Function

ts
function lutFromBase64(s: string): LutBytes;

Decode a base64 LUT (standard alphabet, padded, no whitespace: the form the Rust validator accepts). Throws LUT_SIZE_MESSAGE for anything that is not valid base64 of exactly 12288 bytes.

ParameterTypeDefaultDescription
sstringrequired

lutFromImageData

Function

ts
function lutFromImageData(image: LutImageData): LutBytes;

Read a Mapbox-format colour-theme image: 256 pixels wide, 16 high; blue picks the 16-pixel block (x = b * 16 + r), green is the row (y = g, top row 0). Alpha is ignored. Any other size throws, naming 256x16.

ParameterTypeDefaultDescription
imageLutImageDatarequired

Options and types: LutImageData.

lutFromPngData

Function

ts
function lutFromPngData(data: string): Promise<LutBytes>;

Decode a Mapbox-format colour-theme PNG (256x16) into LUT bytes, in the browser. data is what Mapbox's color-theme.data takes, plus a URL: a data: URI, an http(s):// URL (served with CORS), or the raw base64 of a PNG. The pixels are read with colour-space conversion off, so a PNG carrying a colour profile still gives its stored values. Rejects with a message naming the accepted forms or the 256x16 size.

ParameterTypeDefaultDescription
datastringrequired

lutToBase64

Function

ts
function lutToBase64(lut: LutBytes): string;

Encode a LUT as standard padded base64.

ParameterTypeDefaultDescription
lutLutBytesrequired

Options and types: LutBytes.

lutToImageData

Function

ts
function lutToImageData(lut: LutBytes): {
    width: number;
    height: number;
    data: Uint8ClampedArray;
};

The inverse of lutFromImageData: the LUT as 256x16 RGBA pixels (alpha 255), Mapbox's layout. The runtime layer uploads exactly this as its LUT texture, and it is what a PNG export writes.

ParameterTypeDefaultDescription
lutLutBytesrequired

Options and types: LutBytes.

mapBrandSvg

Function

ts
function mapBrandSvg(theme: MapBrandTheme): string;

The composed v2/MapBrand SVG for one theme.

ParameterTypeDefaultDescription
themeMapBrandThemerequired

Options and types: MapBrandTheme.

mapGroundTheme

Function

ts
function mapGroundTheme(map: GroundReadableMap, whenUnreadable: MapBrandTheme): MapBrandTheme;

Day or Night for the style a live map is drawing right now. Cheap enough to run on every styledata: it walks layer ids only until the first background layer (normally the first) and reads one paint value, rather than serialising the whole style.

ParameterTypeDefaultDescription
mapGroundReadableMaprequired
whenUnreadableMapBrandThemerequired

Options and types: GroundReadableMap, MapBrandTheme.

markerImage

Function

ts
function markerImage(v: unknown): string | undefined;

A usable custom marker image, or undefined: a data: URI of an accepted image type (png/jpeg/webp/svg+xml) whose decoded payload is at most 64 KB. Oversized or foreign URIs are rejected - the marker falls back to its glyph pin (the puck.ts cap precedent).

ParameterTypeDefaultDescription
vunknownrequired

markerImageDataKey

Function

ts
function markerImageDataKey(dataUri: string): string;

map.addImage cache key for a custom-image marker: the data URI is hashed (FNV-1a), so identical images share one registered copy no matter how many markers use them.

ParameterTypeDefaultDescription
dataUristringrequired

markerImageKey

Function

ts
function markerImageKey(icon: MarkerGlyphId, colour: string, size: MarkerSize): string;

map.addImage cache key for a rasterised glyph marker: mm-marker-<icon>-<colour>-<size> (contract format; the colour is the normalised lowercase #rrggbb). Identical markers share one image.

ParameterTypeDefaultDescription
iconMarkerGlyphIdrequired
colourstringrequired
sizeMarkerSizerequired

Options and types: MarkerGlyphId, MarkerSize.

markersFromTheme

Function

ts
function markersFromTheme(theme: Theme | undefined | null): MarkersBlock | undefined;

Reads and parses the extra.markers block from a Studio theme document. Returns undefined when the theme carries no markers block at all (so callers can tell "no markers" apart from "an empty designed set"); a present but malformed block parses leniently via parseMarkers.

ParameterTypeDefaultDescription
themeTheme | undefined | nullrequired

Options and types: Theme.

markersFromThemeUrl

Function

ts
function markersFromThemeUrl(url: string, fetchImpl?: typeof fetch): Promise<MarkersBlock | undefined>;

Fetches a hosted theme document and reads its extra.markers block - the same endpoint contract as navDesignFromThemeUrl:

ts
const markers = await markersFromThemeUrl(
  "https://api.mapmap.ai/styles/midnight-fleet-a1b2c3/theme",
);
if (markers) new MarkersLayer(map, markers);

Returns undefined when the theme carries no markers block; throws on network failure, a non-2xx response or a non-JSON body. Bad DATA never throws - invalid items are skipped by the lenient parser.

ParameterTypeDefaultDescription
urlstringrequired
fetchImpl?typeof fetchnot statedOptional fetch replacement (tests, Node polyfills).

markerText

Function

ts
function markerText(value: unknown): string | undefined;

Normalise a short pin text: trimmed and cut to MAX_MARKER_TEXT_LENGTH characters, or undefined when nothing printable remains. Callers use undefined to mean "draw the glyph".

ParameterTypeDefaultDescription
valueunknownrequired

markerTextImageKey

Function

ts
function markerTextImageKey(text: string, colour: string, size: MarkerSize): string;

map.addImage cache key for a rasterised SHORT-TEXT marker: mm-marker-text-<text>-<colour>-<size>. Deliberately distinct from markerImageKey so glyph pins keep their existing keys unchanged.

ParameterTypeDefaultDescription
textstringrequired
colourstringrequired
sizeMarkerSizerequired

Options and types: MarkerSize.

mercatorModelMatrix

Function

ts
function mercatorModelMatrix(lngLat: [number, number], altitudeM: number): Float64Array;

Local metres in the three.js frame (X east, Y up, Z south) to mercator 0..1 with a conformal z, column-major: the bridge every MapMap 3D layer has used on mercator, translate(MercatorCoordinate.fromLngLat(lngLat, altitudeM)) * scale(s, -s, s) * rotX(pi/2), s = meterInMercatorCoordinateUnits() at the anchor, built with the same operations three.js's makeTranslation().scale().multiply() performs.

ParameterTypeDefaultDescription
lngLat[number, number]required
altitudeMnumberrequired

modelClipMatrices

Function

ts
function modelClipMatrices(args: ProjectionArgs, lngLat: [number, number], altitudeM: number): ClipMatrices;

The clip matrices for a scene anchored at lngLat. On a mercator frame this is exactly mainMatrix * mercatorModelMatrix(...), the matrix the layers used before the globe existed. On a globe frame the mercator matrix is built from MapLibre's mercator fallback, so the blend through the globe-to-mercator zoom band never squashes elevated geometry (the prelude's own fallback is fed metres where it expects mercator units).

ParameterTypeDefaultDescription
argsProjectionArgsrequired
lngLat[number, number]required
altitudeMnumberrequired

Options and types: ProjectionArgs.

multiplyMat4

Function

ts
function multiplyMat4(a: ArrayLike<number>, b: ArrayLike<number>): Float64Array;

a * b for column-major 4x4s, summed in exactly the order three.js's Matrix4.multiplyMatrices sums (a11*b11 + a12*b21 + a13*b31 + a14*b41), so a product computed here equals the one three.js computed bit for bit.

ParameterTypeDefaultDescription
aArrayLike<number>required
bArrayLike<number>required

namedBase

Function

ts
function namedBase(id: string): MapMapBase | undefined;

The catalogue entry for an id, following BASE_ID_ALIASES.

ParameterTypeDefaultDescription
idstringrequired

Function

ts
function navAlertLeadDistanceM(preset: unknown): number;

Metres of lead for a preset (garbage falls back to standard).

ParameterTypeDefaultDescription
presetunknownrequired

Function

ts
function navAlertSoundUrl(sound: unknown, baseUrl?: string): string;

Absolute URL for a built-in earcon. An unrecognised value falls back to cameraCalm rather than returning nothing: a missing alert sound is a silent failure a driver cannot see.

ParameterTypeDefaultDescription
soundunknownrequired
baseUrl?stringnot stated

Function

ts
function navCameraKind(value: unknown): NavCameraKind;

Normalises a camera kind from the wire (or any host classifier) onto a NavCameraKind. Unrecognised values become "unknown", never a guess: a mislabelled camera would alert a driver about the wrong thing.

ParameterTypeDefaultDescription
valueunknownrequired

Function

ts
function navDesignFromTheme(theme: Theme | undefined | null): NavDesign | undefined;

Reads and parses the extra.nav block from a Studio theme document. Returns undefined when the theme carries no nav block at all (so callers can tell "no design" apart from "default design"); a present but malformed block parses leniently to the defaults.

ParameterTypeDefaultDescription
themeTheme | undefined | nullrequired

Options and types: Theme.

Function

ts
function navDesignFromThemeUrl(url: string, fetchImpl?: typeof fetch): Promise<NavDesign | undefined>;

Fetches a hosted theme document and reads its extra.nav block.

Point it at the gateway's theme endpoint - the design a Studio publish stores alongside the compiled style:

ts
const design = await navDesignFromThemeUrl(
  "https://api.mapmap.ai/styles/midnight-fleet-a1b2c3/theme",
);

The endpoint is public (no API key) and never cached, so this always reflects the latest published version. Returns undefined when the theme carries no nav block (same contract as navDesignFromTheme); throws on network failure, a non-2xx response or a non-JSON body.

ParameterTypeDefaultDescription
urlstringrequired
fetchImpl?typeof fetchthe global fetchOptional fetch replacement (tests, Node polyfills). Defaults to the global fetch.

osmAndMoreCredit

Function

ts
function osmAndMoreCredit(line: string): {
    lead: string;
    more: number;
    text: string;
};

The third credit line (0.22.1), for when even the short line would need less than 6px: the OpenStreetMap credit verbatim (the ODbL condition) followed by " and <n> more", where n counts the line's other entries (creditEntries, one per source). A line without an OpenStreetMap credit leads with its first entry's short form instead. Every source's whole wording stays in the (i) panel.

ParameterTypeDefaultDescription
linestringrequired

parseCssColour

Function

ts
function parseCssColour(colour: string): [number, number, number, number] | undefined;

Parse a CSS colour to premultiplication-ready [r, g, b, a] (0-1 channels). Supports the hex forms and rgb()/rgba(); anything else (named colours, hsl()) returns undefined and the caller falls back to the default - this runs where no canvas is guaranteed, so no browser colour parser is available.

ParameterTypeDefaultDescription
colourstringrequired

parseGeocodeResponse

Function

ts
function parseGeocodeResponse(body: unknown): GeocodeHit[];

Parse a geocode response body (either endpoint) into GeocodeHits. Throws when the body is not a FeatureCollection. Features without a Point geometry are skipped: the gateway only emits Points, so anything else is not a hit this parser can represent.

ParameterTypeDefaultDescription
bodyunknownrequired

parseHexColor

Function

ts
function parseHexColor(value: unknown): [number, number, number] | undefined;

Parses a CSS hex colour (#rgb, #rrggbb, #rgba, #rrggbbaa) into 0-255 sRGB channels. Alpha is accepted and ignored - the chip composites over an opaque background, so its alpha does not describe what the driver sees. Returns undefined for any other notation (named colours, rgb(), gradients): unparseable means "cannot judge", never "fails".

ParameterTypeDefaultDescription
valueunknownrequired

parseMarkers

Function

ts
function parseMarkers(value: unknown): MarkersBlock;

Lenient parse of an extra.markers value into a v1 block. A block whose version is not 1 (including a missing one) parses to NOTHING: the Rust validator requires exactly 1, so a version-less block that rendered here could never be published, and a future v2 block must not be silently drawn as v1 by an already-deployed SDK.

Within a v1 block, invalid ITEMS are skipped (bad/missing id, duplicate id, out-of-range coordinates); invalid FIELDS on a valid item fall back to their defaults (unknown glyph -> pin, bad colour -> the default blue, bad size -> m, over-long labels truncated, unusable images dropped). Never throws on bad data - a hand-edited theme cannot break the map. At most 200 items survive.

ParameterTypeDefaultDescription
valueunknownrequired

parseNavAlertsDesign

Function

ts
function parseNavAlertsDesign(value: unknown): NavAlertsDesign;

Lenient parse of an extra.nav.alerts value. Every numeric is clamped, every enum validated, and garbage falls back per field to the defaults - so a hand-edited or older theme can never produce an alert that is unreadable, positioned over the speed readout, or missing its escalated state. The escalated tokens in particular always come back set, even when the input omits or nulls them: a driver-facing escalation is not a removable feature.

ParameterTypeDefaultDescription
valueunknownrequired

parseNavDesign

Function

ts
function parseNavDesign(value: unknown): NavDesign;

Lenient parse of an extra.nav value: unknown or malformed fields fall back to the defaults, so an imported theme never fails on its nav block. LOCKSTEP: identical semantics to parseNavDesign in website/lib/studio-nav.ts (same clamps, same fallbacks).

ParameterTypeDefaultDescription
valueunknownrequired

parseOsrmRoute

Function

ts
function parseOsrmRoute(body: unknown): ParsedRoute;

Parse an OSRM route response into a ParsedRoute. Throws with the OSRM code/message when the response is not Ok or carries no route.

ParameterTypeDefaultDescription
bodyunknownrequired

parsePoiDesign

Function

ts
function parsePoiDesign(value: unknown): PoiDesign;

Lenient parse of an extra.poi value: unknown category ids and invalid colours are dropped rather than failing, so an imported theme never breaks on its POI block. LOCKSTEP: identical semantics to parsePoiDesign in website/lib/studio-poi.ts.

ParameterTypeDefaultDescription
valueunknownrequired

parseSuggestResponse

Function

ts
function parseSuggestResponse(body: unknown): SearchSuggestion[];

Parse a GET /geocode/suggest body into rows, dropping anything that is not a complete suggestion.

Deliberately forgiving about the envelope and strict about each row: a dropdown that renders a row with no id offers the user something the retrieve endpoint cannot resolve.

ParameterTypeDefaultDescription
bodyunknownrequired

placesFromGeoJSON

Function

ts
function placesFromGeoJSON(collection: PlacesFeatureCollection): Place[];

Normalise a GeoJSON FeatureCollection of Points to Place[]. The id comes from feature.id, then properties.id, then the feature index; the name from properties.name (else ""). Non-Point features are skipped.

ParameterTypeDefaultDescription
collectionPlacesFeatureCollectionrequired

Options and types: PlacesFeatureCollection.

poiDesignFromTheme

Function

ts
function poiDesignFromTheme(theme: Theme | undefined | null): PoiDesign | undefined;

Reads and parses the extra.poi block from a Studio theme document. Returns undefined when the theme carries no poi block at all (so callers can tell "no design" apart from "default design"); a present but malformed block parses leniently to the defaults. Same contract as navDesignFromTheme.

ParameterTypeDefaultDescription
themeTheme | undefined | nullrequired

Options and types: Theme.

poiDesignFromThemeUrl

Function

ts
function poiDesignFromThemeUrl(url: string, fetchImpl?: typeof fetch): Promise<PoiDesign | undefined>;

Fetches a hosted theme document and reads its extra.poi block - point it at the gateway's public, never-cached theme endpoint, e.g. https://api.mapmap.ai/styles/midnight-fleet-a1b2c3/theme. Returns undefined when the theme carries no poi block; throws on network failure, a non-2xx response or a non-JSON body. Same contract as navDesignFromThemeUrl.

ParameterTypeDefaultDescription
urlstringrequired
fetchImpl?typeof fetchnot statedOptional fetch replacement (tests, Node polyfills).

poiDesignIsDefault

Function

ts
function poiDesignIsDefault(design: PoiDesign): boolean;

True when the design changes nothing.

ParameterTypeDefaultDescription
designPoiDesignrequired

Options and types: PoiDesign.

poiTextColorExpression

Function

ts
function poiTextColorExpression(design: PoiDesign, fallback: string): unknown;

The poi-labels text-color value for a design: the plain fallback colour when no category overrides label text, otherwise a match expression keyed on the tile's class property. Every non-services category always gets an arm (override or fallback) so unmatched classes

  • the services fallback arm - never inherit another category's colour. LOCKSTEP: mirrors poiTextColorExpression in website/lib/studio-poi.ts.
ParameterTypeDefaultDescription
designPoiDesignrequired
fallbackstringrequired

Options and types: PoiDesign.

prefersReducedMotion

Function

ts
function prefersReducedMotion(): boolean;

Whether the user has asked for reduced motion. Safe without a DOM.

projectionVariant

Function

ts
function projectionVariant(args: ProjectionArgs): ProjectionVariant;

Which projection the frame is drawn with; unknown names read as mercator.

ParameterTypeDefaultDescription
argsProjectionArgsrequired

Options and types: ProjectionArgs.

readProjection

Function

ts
function readProjection(args: unknown): ProjectionArgs | undefined;

The projection-aware render arguments, or undefined when MapLibre did not supply them: a bare matrix (MapLibre 4), or an object without shaderData (early 5.x). Callers keep their legacy mercator path for the undefined case.

ParameterTypeDefaultDescription
argsunknownrequired

registerPmtilesProtocol

Function

ts
function registerPmtilesProtocol(gl?: ProtocolHost): void;

Register the pmtiles:// protocol on a MapLibre instance. Idempotent per maplibre-gl instance, and safe to call before constructing any map. Exposed for apps that build their own maplibregl.Map (possibly from their own bundled maplibre-gl copy) but still want to read MapMap PMTiles.

ParameterTypeDefaultDescription
gl?ProtocolHostnot stated

Options and types: ProtocolHost.

Example

ts
import * as maplibregl from "maplibre-gl";
import { registerPmtilesProtocol } from "@mapmap/maps";

// Before the first map that reads pmtiles:// sources.
registerPmtilesProtocol(maplibregl);
const map = new maplibregl.Map({
  container: "map",
  style: {
    version: 8,
    sources: { parcels: { type: "vector", url: "pmtiles://https://example.com/parcels.pmtiles" } },
    layers: [{ id: "parcels", type: "line", source: "parcels", "source-layer": "parcels" }],
  },
});
map.on("load", () => console.log("loaded"));

relativeLuminance

Function

ts
function relativeLuminance(rgb: readonly [number, number, number]): number;

WCAG 2.x relative luminance of an sRGB triple (channels 0-255).

ParameterTypeDefaultDescription
rgbreadonly [number, number, number]required

removeTerrain

Function

ts
function removeTerrain(map: Map): void;

Turn terrain off and remove what applyTerrain added.

ParameterTypeDefaultDescription
mapMaprequired

renderClockMs

Function

ts
function renderClockMs(recordedAtMaxMs: number, receivedAtMs: number, nowMs: number, renderBehindMs: number): number;

The moment to draw: one poll behind the data clock. The data clock is the newest fix the latest answer held (recordedAtMaxMs), run forward by the time since that answer arrived. Never later than the newest fix, so a feed that stops leaves vehicles parked where they last reported.

ParameterTypeDefaultDescription
recordedAtMaxMsnumberrequired
receivedAtMsnumberrequired
nowMsnumberrequired
renderBehindMsnumberrequired

renderMarkerImage

Function

ts
function renderMarkerImage(options?: RenderMarkerImageOptions): RenderedMarkerImage | null;

Rasterise one marker to ImageData for map.addImage, per the rendering contract: every glyph except dot is the coloured pin-body teardrop with the glyph drawn in white centred on the head (anchor the symbol bottom - the tip sits exactly on the canvas's bottom edge); dot is a coloured circle with a white outline (anchor center). The canvas is a square of twice the preset's CSS pixel size, returned with pixelRatio: 2.

Passing text switches on the short-text mode: the same coloured pin body, with 1-3 white bold characters centred in the head (auto-shrunk to fit) in place of the glyph. That is what numbered waypoints and lettered stops are drawn with.

Returns null where canvas 2D or Path2D is unavailable (never expected in a browser; keeps non-DOM environments safe, the poi-icons.ts pattern).

ParameterTypeDefaultDescription
options?RenderMarkerImageOptionsnot stated

Options and types: RenderMarkerImageOptions.

resetDiagnostics

Function

ts
function resetDiagnostics(): void;

Reset the once-per-page dedup - for tests (and hot-reload tooling).

resolveBaseId

Function

ts
function resolveBaseId(id: string): MapMapBaseId | undefined;

Resolve an id to its canonical form, following BASE_ID_ALIASES.

ParameterTypeDefaultDescription
idstringrequired

resolveSlot

Function

ts
function resolveSlot(style: Pick<StyleSpecification, "layers"> | {
    layers?: readonly LayerLike[];
}, slot: Slot): string | undefined;

The beforeId for slot in style, or undefined to append on top.

ts
map.map.addLayer(myLayer, resolveSlot(map.map.getStyle(), "bottom"));

MapMapMap.slot(slot) does the same against the live map, and addPersistentLayer(layer, { slot }) re-resolves on every style load.

ParameterTypeDefaultDescription
stylePick<StyleSpecification, "layers"> | { layers?: readonly LayerLike[]; }required
slotSlotrequired

Options and types: Slot.

resolveTerrain

Function

ts
function resolveTerrain(input: boolean | TerrainOptions | undefined): Required<Omit<TerrainOptions, "hillshade">> & {
    hillshade: boolean;
} | null;

Normalise true | TerrainOptions into a full, clamped config.

ParameterTypeDefaultDescription
inputboolean | TerrainOptions | undefinedrequired

Options and types: TerrainOptions.

resolveTheme

Function

ts
function resolveTheme(date: Date, lat: number, lng: number): "light" | "dark";

The theme the sun dictates at date for lat/lng.

ParameterTypeDefaultDescription
dateDaterequired
latnumberrequired
lngnumberrequired

runMapDiagnostics

Function

ts
function runMapDiagnostics(input: MapDiagnosticsInput): void;

Run the construction-time checks and attach the 401 watcher. Called by MapMapMap automatically; exported for apps wrapping a raw maplibregl.Map that still want the self-diagnosis.

ParameterTypeDefaultDescription
inputMapDiagnosticsInputrequired

Options and types: MapDiagnosticsInput.

setMapLanguage

Function

ts
function setMapLanguage(map: MapMapMap | Map, language: string | null): string[];

Switches every name-label layer of the map's current style to language (null restores the style's default). Returns the ids of the layers it rewrote. Throws on a malformed language tag. Reapply after setStyle, a style swap resets label languages.

ParameterTypeDefaultDescription
mapMapMapMap | Maprequired
languagestring | nullrequired

Options and types: MapMapMap.

setProjectionUniforms

Function

ts
function setProjectionUniforms(gl: WebGL2RenderingContext, locations: Record<ProjectionUniform, WebGLUniformLocation | null>, args: ProjectionArgs): void;

Set the five prelude uniforms for this frame (the program must be in use).

ParameterTypeDefaultDescription
glWebGL2RenderingContextrequired
locationsRecord<ProjectionUniform, WebGLUniformLocation | null>required
argsProjectionArgsrequired

Options and types: ProjectionUniform, ProjectionArgs.

severityProsody

Function

ts
function severityProsody(severity: GuidanceSeverity, baseRate?: number): SeverityProsody;

Prosody for a severity level at a base rate. Pure, exported for tests and for custom voice layers that want the same house style.

ParameterTypeDefaultDescription
severityGuidanceSeverityrequired
baseRate?numbernot stated

Options and types: GuidanceSeverity.

shortCredit

Function

ts
function shortCredit(line: string): string;

The short form of a credit line: each source's own short credit (CREDIT_SHORT_FORMS), everything else verbatim. A line with no known long notice comes back with only the OpenStreetMap credit shortened; it still gets the (i) and its full wording when it would need less than 6px.

ParameterTypeDefaultDescription
linestringrequired

shortestArcDeg

Function

ts
function shortestArcDeg(fromDeg: number, toDeg: number): number;

The signed shortest-arc rotation from fromDeg to toDeg, in degrees. Always in (-180, 180], so a heading tween never spins the long way round the compass (350° -> 10° is +20°, not -340°).

ParameterTypeDefaultDescription
fromDegnumberrequired
toDegnumberrequired

shortestArcDelta

Function

ts
function shortestArcDelta(from: number, to: number): number;

The signed shortest-arc rotation from bearing from to bearing to, in (-180, 180] degrees - the slerp-style delta the flythrough eases along so the chase cam never spins the long way round.

ParameterTypeDefaultDescription
fromnumberrequired
tonumberrequired

speak

Function

ts
function speak(instruction: VoiceInstruction, options?: SpeakOptions): boolean;

Speaks a voice instruction through the browser's SpeechSynthesis. Prefers the SSML body's text (browsers do not accept raw SSML). Returns false when speech synthesis is unavailable (e.g. non-browser contexts). De-duplication is the caller's responsibility: speak each instruction once as its trigger distance is crossed.

ParameterTypeDefaultDescription
instructionVoiceInstructionrequired
options?SpeakOptionsnot stated

Options and types: VoiceInstruction, SpeakOptions.

sphereFrame

Function

ts
function sphereFrame(lngLat: [number, number]): {
    position: Vec3;
    east: Vec3;
    south: Vec3;
    up: Vec3;
};

The tangent frame at a [lng, lat]: the prelude's globeGetRotationMatrix columns (east, then south, then up), written in closed form so it stays defined at the poles, where the prelude's normalize(p.z, 0, -p.x) divides by zero. Orthonormal.

ParameterTypeDefaultDescription
lngLat[number, number]required

sphereSurface

Function

ts
function sphereSurface(lngLat: [number, number]): Vec3;

A [lng, lat] on MapLibre's unit globe: x = sin(lng) cos(lat), y = sin(lat), z = cos(lng) cos(lat) (the prelude's projectToSphere).

ParameterTypeDefaultDescription
lngLat[number, number]required

ssmlToText

Function

ts
function ssmlToText(ssml: string): string;

Strips SSML tags down to speakable plain text. Entities are decoded in a single pass (never re-scanning already-decoded output), so text whose literal content looks like an entity, e.g. &amp;lt;, the gateway's escape of a literal &lt;, round-trips correctly. Decodes the five named XML entities plus decimal numeric references (&#39;).

ParameterTypeDefaultDescription
ssmlstringrequired

styleFromBase

Function

ts
function styleFromBase(id: string, options?: Omit<BuildStyleOptions, "theme">): StyleSpecification;

Build a MapLibre style from a base name.

Throws on an unknown id, naming every accepted one: a silent fallback to the default slate would show a map that is simply not the one asked for.

ParameterTypeDefaultDescription
idstringrequired
options?Omit<BuildStyleOptions, "theme">not stated

Options and types: BuildStyleOptions.

Example

ts
import * as maplibregl from "maplibre-gl";
import { MAPMAP_BASES, registerPmtilesProtocol, styleFromBase } from "@mapmap/maps";

console.log(MAPMAP_BASES.map((b) => b.id)); // the accepted ids
registerPmtilesProtocol(maplibregl);
const map = new maplibregl.Map({ container: "map", style: styleFromBase(MAPMAP_BASES[0].id, { apiKey: "snk_…" }) });
map.on("load", () => console.log("loaded"));

styleGroundTheme

Function

ts
function styleGroundTheme(style: unknown, whenUnreadable: MapBrandTheme): MapBrandTheme;

Day or Night for a style document (a MapLibre StyleSpecification), or whenUnreadable when it carries no readable ground.

ParameterTypeDefaultDescription
styleunknownrequired
whenUnreadableMapBrandThemerequired

Options and types: MapBrandTheme.

subdivideMercator

Function

ts
function subdivideMercator(coords: readonly [number, number][], maxSegment?: number): [number, number][];

Insert points so no segment exceeds maxSegment mercator units.

On the globe a straight mercator chord is not a straight line on screen: the prelude projects each vertex onto the sphere and the GPU joins them with straight lines, so a long segment cuts through the planet and vanishes. Subdividing makes the geometry follow the same mercator path a MapLibre line layer draws. A no-op (same points, same order) for input already finer than the limit, and idempotent.

ParameterTypeDefaultDescription
coordsreadonly [number, number][]required
maxSegment?numbernot stated

sunTimes

Function

ts
function sunTimes(date: Date, lat: number, lng: number): SunTimes;

Sunrise and sunset (standard -0.833° horizon: refraction + solar disc) for the civil day containing date (UTC) at lat/lng, or a polar marker when the sun never crosses the horizon that day.

ParameterTypeDefaultDescription
dateDaterequired
latnumberrequired
lngnumberrequired

supportsTerrainDraping

Function

ts
function supportsTerrainDraping(args: unknown): false;

HOOK(maplibre-6.13-terrain): MapLibre 6.13 adds renderToTerrainTile, renderTerrainHeightMap and terrainTileRevision, which let a custom layer drape onto 3D terrain. The SDKs' dev pin reached 6.14.0 on 27 October 2026, but their peer ranges still admit 5.x and 6.9 to 6.12, which lack them, and draping is not built yet, so this still answers false. Implement draping here and nowhere else, gated on the installed version.

ParameterTypeDefaultDescription
argsunknownrequired

territoryTilesSourceUrl

Function

ts
function territoryTilesSourceUrl(options?: Pick<BuildStyleOptions, "territoryTilesUrl" | "apiKey" | "baseUrl">): string;

The URL a compiled style's territory source points at.

  1. An explicit territoryTilesUrl always wins (pmtiles:// added when missing), keyed or not.
  2. Otherwise, with an apiKey, the keyed gateway TileJSON (keyedTilesUrl), which works from any website.
  3. Otherwise the keyless DEFAULT_TERRITORY_TILES_URL, which works on mapmap.ai and on a local development server.
ParameterTypeDefaultDescription
options?Pick<BuildStyleOptions, "territoryTilesUrl" | "apiKey" | "baseUrl">not stated

Options and types: BuildStyleOptions.

tessellateRouteRibbon

Function

ts
function tessellateRouteRibbon(coordinates: [number, number][]): RibbonMesh;

Tessellate a route line into a centreline triangle strip: two vertices per point, each carrying the point's mercator position, a unit extrusion normal (averaged between adjacent segments at joins - a bevel-free miter that slightly thins very sharp corners, which is invisible on a soft glow ribbon), and normalised progress along the line.

Pure: no WebGL, no map. Consecutive duplicate points are dropped; fewer than two distinct points yield an empty mesh. Long segments are split by subdivideMercator (no piece longer than 1/512 mercator units, about 78 km at the equator), so on the globe the ribbon follows the same path a MapLibre line layer draws instead of cutting through the planet; a street-scale route gains no points.

ParameterTypeDefaultDescription
coordinates[number, number][]required

tidyPlaceName

Function

ts
function tidyPlaceName(name: string): string;

A place name as riders read it: the feed's underscores become spaces ("Brighton_Marina" reads "Brighton Marina"), runs of spaces collapse, and the ends are trimmed. origin and destination pass through this, so labels, popups and TransitVehiclesLayer.vehicles agree.

ParameterTypeDefaultDescription
namestringrequired

toLngLat

Function

ts
function toLngLat(point: LngLatLike): [number, number];

Normalise any accepted shape to a [lng, lat] tuple.

ParameterTypeDefaultDescription
pointLngLatLikerequired

Options and types: LngLatLike.

toPmtilesUrl

Function

ts
function toPmtilesUrl(url: string): string;

Ensure a tiles URL carries the pmtiles:// protocol prefix.

ParameterTypeDefaultDescription
urlstringrequired

transitArchiveUrl

Function

ts
function transitArchiveUrl(url: string, indexUrl: string): string;

pmtiles:// URL for an archive, resolving a path against the index.

ParameterTypeDefaultDescription
urlstringrequired
indexUrlstringrequired

transitFreshnessLabel

Function

ts
function transitFreshnessLabel(status: TransitFeedStatus, ageS: number | null): string;

The standard freshness label for a live-vehicle feed: "Live, <n> s ago" while ok, "Paused: last data <m> min ago" once stale, "Feed status unknown" when nothing vouches for the feed.

ParameterTypeDefaultDescription
statusTransitFeedStatusrequired
ageSnumber | nullrequired

Options and types: TransitFeedStatus.

transitStopFromProperties

Function

ts
function transitStopFromProperties(props: Record<string, unknown>): TransitStopFeature;

The clicked feature's properties as a TransitStopFeature.

ParameterTypeDefaultDescription
propsRecord<string, unknown>required

transitTileJsonUrl

Function

ts
function transitTileJsonUrl(baseUrl: string, id: string, apiKey?: string): string;

The keyed TileJSON URL for a transit archive on the gateway. The key rides as api_key so the gateway stamps it onto the tile URLs it returns (MapLibre sends no Authorization header for tiles).

ParameterTypeDefaultDescription
baseUrlstringrequired
idstringrequired
apiKey?stringnot stated

transitUrlsFromIndex

Function

ts
function transitUrlsFromIndex(index: unknown, indexUrl: string): {
    stops: string | null;
    lines: string | null;
};

The archive URLs from a tiles index document, or null for an archive the index does not announce.

ParameterTypeDefaultDescription
indexunknownrequired
indexUrlstringrequired

truncateChars

Function

ts
function truncateChars(text: string, max: number): string;

Cut a string to max UNICODE SCALARS (not UTF-16 code units). The Rust validator counts chars(), so a plain slice both rejected valid emoji strings and could cut a surrogate pair in half, and a lone surrogate fails serde_json with a JSON parse error instead of the friendly marker message. LOCKSTEP: the same helper exists in Studio's mirror.

ParameterTypeDefaultDescription
textstringrequired
maxnumberrequired

uploadProbeBatch

Function

ts
function uploadProbeBatch(baseUrl: string, apiKey: string, body: string, options?: UploadProbeOptions): Promise<ProbeUploadOutcome>;

POST one probe body to {baseUrl}/v1/probe with a bearer key. Transient failures (network or 5xx) are retried with bounded backoff; permanent ones (400/403/501) are not, and neither is an aborted signal. Resolves with the terminal outcome and never rejects, so a fire-and-forget void uploadProbeBatch(...) is safe.

ParameterTypeDefaultDescription
baseUrlstringrequired
apiKeystringrequired
bodystringrequiredthe string returned by GuidanceSession.finishProbeJson().
options?UploadProbeOptionsnot stated

Options and types: UploadProbeOptions.

validateColourTheme

Function

ts
function validateColourTheme(theme: unknown): LutBytes;

Validate a color_theme block and decode its LUT. Throws the messages sn_style::validate_colour_theme returns, word for word (and the same as website/lib/colour-theme.ts).

ParameterTypeDefaultDescription
themeunknownrequired

validateUseTheme

Function

ts
function validateUseTheme(value: unknown): asserts value is UseTheme | undefined;

Throw unless value is a valid use_theme (the Rust serde message).

ParameterTypeDefaultDescription
valueunknownrequired

Interfaces (@mapmap/maps)

AdrCheckOptions, AdrCheckRequest, AdrCheckResult, AdrDimensions, AlertChipContent, AlertContrastIssue, AlertPresentation, BannerComponent, BannerContent, BannerInstruction, BuildStyleOptions, CameraAlert, CameraFix, ClipMatrices, ClipOptions, ColorThemeSpec, ColourTheme, ColourThemeLayerOptions, CreditInnerControl, CreditOptions, DataLayerCategories, DataLayerClusterOptions, DataLayerEvent, DataLayerExtrusionOptions, DataLayerGraduated, DataLayerOptions, DataLayerSimpleStyle, DataLayerStyle, DirectionIconStep, EndpointMarker, EndpointsDesign, FlythroughController, FlythroughOptions, FlythroughPose, GeocodeHit, GeocodeOptions, GeocoderOptions, GradeStyleOptions, GroundReadableMap, GuidanceSpokenPrompt, Interaction, InteractionEvent, InteractionTarget, IsochroneFeatureCollection, IsochroneLayerOptions, LaneIndication, LayerOverride, LogoOptions, LutImageData, MapDiagnosticsInput, MapMapBase, MapMapOptions, MarkerItem, MarkersBlock, MarkersLayerIds, MarkersLayerOptions, NavAlertKindDesign, NavAlertsDesign, NavBannerDesign, NavCameraDesign, NavDesign, NavigationCameraOptions, NavPuckDesign, NavRouteDesign, NearestByDriveTimeOptions, ParsedRoute, PersistentIds, PersistentLayerOptions, Place, PlacePointFeature, PlacesFeatureCollection, PlacesIcon, PlacesLabelOptions, PlacesLayerIds, PlacesLayerOptions, PlacesSelectOptions, PoiCategoryDesign, PoiDesign, PositionPuckOptions, ProjectionArgs, Rendered, RenderedMarkerImage, RenderMarkerImageOptions, ReverseGeocodeOptions, RibbonMesh, RouteEffectLayer, RouteFlowOptions, RouteGeometry, RouteLayerIds, RouteLayerOptions, RouteLineStyle, RouteOptions, SearchBoxMap, SearchBoxOptions, SearchBoxSelectEvent, SearchSuggestion, SetRouteEffectOptions, SeverityProsody, ShowReachabilityOptions, SnappedOrigin, SpeakOptions, StepGuidance, SuggestUrlOptions, TerrainOptions, Theme, ThemeEffects, ThemeSchedulerOptions, TransitFeedAnswer, TransitFeedReport, TransitFix, TransitStopFeature, TransitStopsLayerOptions, TransitVehicle, TransitVehiclesLayerOptions, TruckParams, UploadProbeOptions, VoiceGuidanceOptions, VoiceGuidanceUpdate, VoiceInstruction

AdrCheckOptions

Interface

ts
interface AdrCheckOptions
PropertyTypeDefaultDescription
baseUrlstringrequiredGateway base URL, e.g. https://api.mapmap.ai.
apiKey?stringnot statedGateway API key (snk_…).

AdrCheckRequest

Interface

ts
interface AdrCheckRequest

Input for the gateway's POST /adr/check compliance endpoint: the vehicle's ADR profile plus the category of the tunnel to check. Serialised on the wire as {"adr": <AdrVehicleProfile>, "tunnel_category": "A".."E"} (see sn-gateway routes/adr.rs).

PropertyTypeDefaultDescription
hazmatbooleanrequiredCarrying dangerous goods.
tunnelCode?stringnot statedThe vehicle load's ADR 8.6.4 tunnel restriction code, e.g. "C" or "C/E". Omit when carrying dangerous goods of unknown code (the gateway then conservatively treats the load as code B). This is not the tunnel's category, that goes in tunnelCategory.
dimensions?AdrDimensionsthe EU standard artic maximumsVehicle dimensions. Defaults to the EU standard artic maximums.
tunnelCategoryAdrTunnelCategoryrequiredThe ADR category of the tunnel to check, "A" … "E".

AdrCheckResult

Interface

ts
interface AdrCheckResult

Parsed response from POST /adr/check.

PropertyTypeDefaultDescription
statusstringrequired"allowed" or "blocked".
reason?stringnot statedHuman-readable justification citing ADR 8.6.4 where blocked.
rawRecord<string, unknown>requiredThe raw response body.

AdrDimensions

Interface

ts
interface AdrDimensions

Physical truck dimensions for the ADR vehicle profile (mirrors sn_adr::TruckDimensions). All optional; unset fields default to the EU 96/53/EC maximum-authorised articulated vehicle (4.0 m high, 2.55 m wide, 16.5 m long, 40 t gross), matching the Rust Default.

PropertyTypeDefaultDescription
heightM?number4.0Vehicle height, metres. Defaults to 4.0.
widthM?number2.55Vehicle width, metres. Defaults to 2.55.
lengthM?number16.5Vehicle length, metres. Defaults to 16.5.
grossWeightT?number40Gross combination weight, tonnes. Defaults to 40.
axleLoadT?numbernot statedHeaviest single-axle load, tonnes, if known.
axleCount?numbernot statedNumber of axles, if known.

AlertChipContent

Interface

ts
interface AlertChipContent

Template-shaped content for an alert: the fields a head unit can actually render.

CarPlay's CPNavigationAlert and Android Auto's Alert inside a NavigationTemplate take a title, a subtitle and an image - the system draws them, and none of the chip's colour, radius or position tokens survive the trip. Hosts targeting a head unit should read this instead of the DOM chip, so styling degrades gracefully rather than being assumed to render.

PropertyTypeDefaultDescription
kindNavCameraKindrequired
titlestringrequiredPrimary line, e.g. "Average speed check".
subtitlestringrequiredSecondary line: limit and distance when known, else empty.
iconUrl?stringnot statedOverride icon URL when the design sets one for this kind.

AlertContrastIssue

Interface

ts
interface AlertContrastIssue

A chip colour pair that falls below ALERT_CONTRAST_MIN.

PropertyTypeDefaultDescription
state"calm" | "escalated"requiredWhich chip state the pair belongs to.
textColorstringrequiredThe text colour of the failing pair.
backgroundstringrequiredThe background colour of the failing pair.
rationumberrequiredThe measured ratio, rounded to 2 dp.
minimumnumberrequiredThe floor it failed to clear.

AlertPresentation

Interface

ts
interface AlertPresentation

What a host should actually do with an alert, given the design and whether the driver is currently over the limit.

The rule this encodes, and the reason it is a pure function rather than scattered branches in a renderer: the VISUAL alert is unconditional and calm, and AUDIO is the escalation channel. A driver within the limit still sees the chip; only the sound waits for speeding.

PropertyTypeDefaultDescription
visiblebooleanrequiredWhether to show the chip at all.
escalatedbooleanrequiredWhether the chip should render in its escalated state.
audiblebooleanrequiredWhether audio should fire now.
audioModeNavAlertAudioModerequiredWhich audio channel to use when audible.
soundUrlstringrequiredThe earcon to play for THIS state: the design's calm sound, or its escalated variant when escalated. Always set (even when audible is false) so a host can pre-load it; play it only when audible.
leadDistanceMnumberrequiredMetres of lead this design guarantees before the camera.

BannerComponent

Interface

ts
interface BannerComponent

A typed fragment of banner content.

Field names are the wire names, because these objects come straight off route.raw without a mapping pass (see extractGuidance).

PropertyTypeDefaultDescription
typestringrequired
textstringrequired
directions?string[]not stated
active?booleannot stated
active_direction?stringnot statedWhich of directions guidance recommends (gateway active_direction).

BannerContent

Interface

ts
interface BannerContent

One banner line.

PropertyTypeDefaultDescription
textstringrequired
type?stringnot stated
modifier?stringnot stated
components?BannerComponent[]not stated

BannerInstruction

Interface

ts
interface BannerInstruction

The visual banner shown while travelling a step.

PropertyTypeDefaultDescription
distanceAlongGeometrynumberrequired
primaryBannerContentrequired
secondary?BannerContentnot stated
sub?BannerContentnot stated

BuildStyleOptions

Interface

ts
interface BuildStyleOptions
PropertyTypeDefaultDescription
labelLanguage?stringLabel language: an ISO 639 code selects name:<code> with a local-name fallback; the literal "local" selects the local name outright; omitted keeps the default (English-first)Label language: an ISO 639 code selects name:<code> with a local-name fallback; the literal "local" selects the local name outright; omitted keeps the default (English-first). The tiles carry the OSM name:* set, so switching involves no tile rebuild.
theme?MapMapTheme | Theme"light"Theme to build: a built-in name ("light" / "dark") or a full Theme document. Defaults to "light".
territoryTilesUrl?stringnot statedPMTiles URL for the territory tiles. Accepts either a pmtiles://… URL or a plain https://… URL (the pmtiles:// prefix is added for you). Always wins over the keyed default that apiKey selects.
apiKey?stringnot statedGateway API key (snk_…). With no territoryTilesUrl, the basemap reads the keyed gateway tiles (keyedTilesUrl) instead of the keyless CDN, which refuses browser pages outside mapmap.ai and localhost. The key is written into the source URL as ?api_key=.
baseUrl?stringDEFAULT_GATEWAY_URLGateway for the keyed tiles. Defaults to DEFAULT_GATEWAY_URL. Only read when apiKey is set and territoryTilesUrl is not.
roadShields?booleantrueRoad-number shields (road-shields, one layer keyed by each road's own country: M25, A 7, I-280...). Defaults to true; false leaves the layer out. Mirrors the per-territory road_shields block of sn_style, which the SDK theme does not carry.

CameraAlert

Interface

ts
interface CameraAlert

One camera alert to present. kind is normalised through navCameraKind, so a raw gateway value ("redlight") is accepted.

JURISDICTION: whether a camera reaches you at all is decided server-side before the response leaves the gateway. Nothing in this module can widen that; it styles what the policy already permitted.

PropertyTypeDefaultDescription
kindNavCameraKind | stringrequiredCamera regime; wire values are normalised.
limitKph?numbernot statedEnforced limit in km/h, when known.
distanceM?numbernot statedMetres to the camera, when known.

CameraFix

Interface

ts
interface CameraFix

A GPS fix to follow.

PropertyTypeDefaultDescription
latnumberrequired
lonnumberrequired

ClipMatrices

Interface

ts
interface ClipMatrices

The matrices a tier-2 layer draws with this frame.

PropertyTypeDefaultDescription
mercatorFloat64ArrayrequiredLocal metres to clip space through the mercator path (today's matrix on a mercator map).
globeFloat64Array | nullrequiredLocal metres to clip space on the globe; null on a mercator frame.
transitionnumberrequiredThe globe weight, MapLibre's projectionTransition: 0 mercator, 1 globe.

ClipOptions

Interface

ts
interface ClipOptions

Options for MapMapMap.addClip.

PropertyTypeDefaultDescription
polygonPolygon | MultiPolygonrequiredThe area to clear, in lng/lat. At most CLIP_MAX_VERTICES vertices in total.
types?ClipType[]["buildings"]Which skeleton layers to clip. Default ["buildings"]. Ignored when layers is given.
layers?string[]not statedExplicit layer ids to clip instead of types.
minzoom?numberCLIP_DEFAULT_MINZOOMBelow this zoom the clip is not evaluated (the features draw as normal), which keeps the per-feature distance test off low-zoom tiles that hold thousands of buildings. Default CLIP_DEFAULT_MINZOOM.

ColorThemeSpec

Interface

ts
interface ColorThemeSpec

A runtime colour theme for MapMapMap.setColorTheme: a 16x16x16 LUT given one of two ways, plus a strength. Mapbox-compatible: data takes what Mapbox's color-theme.data takes.

PropertyTypeDefaultDescription
data?stringnot statedA Mapbox-format colour-theme PNG (256x16): a data: URI, an http(s):// URL served with CORS, or the raw base64 of the PNG.
lut?LutBytes | stringnot statedThe LUT itself: 12288 bytes (see colour-theme.ts) or their base64.
strength?number1Blend with the ungraded map, 0..1. Default 1.

ColourTheme

Interface

ts
interface ColourTheme

The theme document's color_theme block. Mirrors sn_style::ColourTheme.

PropertyTypeDefaultDescription
lutstringrequiredBase64 of exactly 12288 bytes.
size?numbernot statedFixed at 16.
strength?numbernot stated0..1, default 1.
name?stringnot statedDisplay name, [a-z0-9-]{1,40}.

ColourThemeLayerOptions

Interface

ts
interface ColourThemeLayerOptions

Options for ColourThemeLayer.

PropertyTypeDefaultDescription
id?string"mapmap-colour-theme"Layer id. Default "mapmap-colour-theme".
lutLutBytesrequiredThe LUT, LUT_BYTES bytes (see colour-theme.ts).
strength?numbernot stated0..1, default 1.

CreditInnerControl

Interface

ts
interface CreditInnerControl

The MapLibre control being dressed (typed structurally, so it needs no maplibre-gl import and works with any instance the host app bundles).

Methods

  • onAdd(map: unknown): HTMLElement
  • onRemove(map?: unknown): void
  • getDefaultPosition?(): unknown

CreditOptions

Interface

ts
interface CreditOptions

Options for CreditControl.

PropertyTypeDefaultDescription
position?ChromeCornerbottom-leftThe corner it is mounted in; sets which edges the insets apply to. Default bottom-left.
theme?MapBrandThemenot statedInitial variant. MapMapMap keeps it in step with the drawn style; default day.

DataLayerCategories

Interface

ts
interface DataLayerCategories

A colour per value of one property.

PropertyTypeDefaultDescription
propertystringrequired
valuesRecord<string, string>requiredProperty value (compared as a string) to colour.
fallback?stringsimple.color, then Signal blueColour for any other value. Default simple.color, then Signal blue.

DataLayerClusterOptions

Interface

ts
interface DataLayerClusterOptions
PropertyTypeDefaultDescription
radius?numberMapLibre's default (50) when absentCluster radius in px. MapLibre's default (50) when absent.
maxZoom?numberMapLibre's default (14) when absentHighest zoom that clusters. MapLibre's default (14) when absent.
properties?Record<string, unknown>not statedMapLibre clusterProperties (aggregates per cluster).

DataLayerEvent

Interface

ts
interface DataLayerEvent

What DataLayer.on handlers receive.

PropertyTypeDefaultDescription
type"click" | "hover" | "select"required
featureMapGeoJSONFeature | undefinedrequiredThe feature clicked or hovered; undefined when the pointer left.
lngLatLngLat | undefinedrequired
selectedGeoJSON.Feature[]requiredThe selection after the event.

DataLayerExtrusionOptions

Interface

ts
interface DataLayerExtrusionOptions
PropertyTypeDefaultDescription
heightPropertystringrequiredProperty holding the height in metres.
base?number | string0Base height: metres, or the name of a property holding it. Default 0.
opacity?number0.80 to 1. Default 0.8.

DataLayerGraduated

Interface

ts
interface DataLayerGraduated

A colour ramp over a numeric property.

PropertyTypeDefaultDescription
propertystringrequired
stops[number, string][]required[value, colour] pairs, values strictly ascending.

DataLayerOptions

Interface

ts
interface DataLayerOptions
PropertyTypeDefaultDescription
dataGeoJSON.FeatureCollection | stringrequiredInline GeoJSON, a GeoJSON URL, or pmtiles://https://... for vector tiles.
sourceLayer?stringnot statedThe vector layer to draw; required for a pmtiles:// source.
mode?DataLayerMode"auto": picks by the first feature's geometry when every feature shares itDefault "auto": picks by the first feature's geometry when every feature shares it; a mixed collection, a URL or tiles get fill, line and point layers, each filtered to its geometry.
style?DataLayerStylenot stated
extrusion?DataLayerExtrusionOptionsheight property heightRequired for mode: "extrusion" (default height property height).
cluster?DataLayerClusterOptionsnot stated
promoteId?stringthe feature's own idA property holding a unique, stable feature id. Default: the feature's own id; inline data without ids gets generated ones (hover and selection work, updateData does not).
hover?booleantrueHighlight the feature under the pointer. Default true.
select?"single" | "multi" | false"single"Click to select. Default "single".
popup?(feature: GeoJSON.Feature, lngLat: LngLat) => string | HTMLElementnot statedContent for a popup on click (HTML string or an element).
slot?Slot"middle": above roads, below labelsWhere in the layer stack. Default "middle": above roads, below labels.
attribution?stringnot statedCredit for the data, shown in the map attribution.
fitBounds?booleanfalseFit the map to inline data once it is added. Default false.
id?stringmapmap-data-<n>Id prefix for the source and layers. Default mapmap-data-<n>.

DataLayerSimpleStyle

Interface

ts
interface DataLayerSimpleStyle

One look for every feature.

PropertyTypeDefaultDescription
color?stringSignal blueFill, line or circle colour. Default Signal blue.
opacity?numberfills 0.35, lines 0.9, circles 0.90 to 1. Defaults: fills 0.35, lines 0.9, circles 0.9.
radius?number6Circle radius in px. Default 6.
width?number2Line width in px (and polygon outlines). Default 2.
outlineColor?stringthe fill colour / whitePolygon outline and circle stroke colour. Default the fill colour / white.

DataLayerStyle

Interface

ts
interface DataLayerStyle

Styling: categories wins over graduated, which wins over simple.

PropertyTypeDefaultDescription
simple?DataLayerSimpleStylenot stated
categories?DataLayerCategoriesnot stated
graduated?DataLayerGraduatednot stated

DirectionIconStep

Interface · also exported from @mapmap/maps/direction-icons

ts
interface DirectionIconStep

The slice of an OSRM route step that icon resolution reads.

PropertyTypeDefaultDescription
maneuver?{ type?: string; modifier?: string; bearing_before?: number; bearing_after?: number; }not stated
driving_side?stringnot stated"left" | "right": the side traffic drives on at this step. OSRM and Mapbox routers emit it on every step; the MapMap gateway emits it where the engine establishes it (roundabout and u-turn steps).
mode?stringnot statedOSRM travel mode; "ferry" selects the ferry icon.

EndpointMarker

Interface

ts
interface EndpointMarker

One designed endpoint marker: a coloured pin (or dot) drawn from the shared marker rasteriser, optionally with a text label underneath.

PropertyTypeDefaultDescription
icon?MarkerGlyphIdnot statedGlyph drawn on the pin, or "dot" for a plain circle.
text?stringnot statedShort text (1-3 characters) drawn in the pin head INSTEAD of the glyph - "A", "B", "1". Overrides icon.
colour?stringnot statedMarker colour, any CSS colour the canvas accepts.
size?MarkerSizenot statedSize preset: "s" 24 px, "m" 32 px, "l" 40 px.
label?stringnot statedOptional caption drawn below the marker, with a white halo.

EndpointsDesign

Interface

ts
interface EndpointsDesign

How a route's start, end and intermediate waypoints are drawn. Every field is optional; false switches an endpoint off entirely.

PropertyTypeDefaultDescription
start?EndpointMarker | falsea green dot, size mThe first route coordinate. Default a green dot, size m.
end?EndpointMarker | falsea signal-blue pin, size mThe last route coordinate. Default a signal-blue pin, size m.
waypoint?EndpointMarker | falsea signal-blue pin, size sEvery intermediate stop. Default a signal-blue pin, size s.
numberWaypoints?booleantrueDraw each waypoint's 1-based index in its pin head (1, 2, 3) instead of the glyph. Default true. An explicit waypoint.text wins over the number.

FlythroughController

Interface

ts
interface FlythroughController

The handle a flythrough returns.

PropertyTypeDefaultDescription
speednumberrequiredPlayback-rate multiplier (1 = real duration, 2 = double).
readonly progressnumberrequiredCurrent progress, 0-1.
readonly playingbooleanrequiredWhether the replay is currently advancing.

Methods

  • play(): void: Start (or resume) the replay. Restarts from 0 when it had finished.
  • pause(): void: Freeze the replay where it is.
  • stop(): void: Pause and rewind to the start (the camera jumps to the start pose).
  • seek(t: number): void: Scrub to progress t (0-1, clamped) and apply the pose immediately.
  • onProgress(listener: (t: number) => void): () => void: Subscribe to progress updates; returns the unsubscribe function.
  • destroy(): void: Pause and detach everything. The controller is dead afterwards.

FlythroughOptions

Interface

ts
interface FlythroughOptions
PropertyTypeDefaultDescription
pitch?number60 (the cinematic chase lookCamera tilt in degrees, clamped 0-85. Default 60 (the cinematic chase look; see NavigationCameraOptions.pitch for caveats above 60).
zoom?number16Camera zoom held through the replay. Default 16.
durationMs?number20000Total replay duration in milliseconds. Default 20000. Ignored when speedMps is given.
speedMps?numbernot statedReplay ground speed in metres/second along the route - the duration becomes routeLength / speedMps. Wins over durationMs.
lookAheadM?number200How far up the road the chase cam looks to derive its bearing, metres. Default 200; larger = calmer bearing on wiggly roads.
bearingEase?number3Bearing smoothing rate per second (the fraction of the remaining shortest-arc turn closed each second). Default 3; higher = snappier.

FlythroughPose

Interface

ts
interface FlythroughPose

A camera pose along a flythrough: where to look from, and which way.

PropertyTypeDefaultDescription
center[number, number]requiredCamera target on the route, [lng, lat].
bearingnumberrequiredChase-cam bearing: towards a point lookAheadM up the road.

GeocodeHit

Interface

ts
interface GeocodeHit

One geocode result, flattened from the wire FeatureCollection.

PropertyTypeDefaultDescription
lngLat[number, number]required[lng, lat] - GeoJSON order, ready for a MapLibre camera or marker.
name?stringnot statedDisplay name (properties.name), when the hit carries one.
id?stringnot statedStable id (osm:…), first-party backend only.
kind?stringnot statedDocument kind: poi, address, street, locality, postcode, …
housenumber?stringnot statedAddress parts, present when known.
street?stringnot stated
city?stringnot stated
postcode?stringnot stated
state?stringnot stated
country?stringnot stated
countrycode?stringnot stated
categories?string[]not statedPOI categories, e.g. ["arts_centre"].
distanceM?numbernot statedDistance from the query point in metres - reverse hits only.
details?Record<string, unknown>not statedCurated OSM display attributes on first-party POI hits: opening_hours, phone, website, brand, wheelchair, EV socket:* connectors and friends. Keys absent in OSM are omitted.
rawRecord<string, unknown>requiredThe raw GeoJSON feature, for anything not modelled above.

GeocodeOptions

Interface

ts
interface GeocodeOptions

Options for forward geocoding (GET /geocode).

PropertyTypeDefaultDescription
limit?numbernot statedMaximum results, 1-10.
lang?stringnot statedResult language, e.g. "en", "de", "fr".
bias?LngLatLikenot statedLocation bias: reorders candidates towards this point, never excludes one. The map centre is the natural value for a search box.
zoom?numbernot statedMap zoom (0-20) controlling the bias strength: zoomed in favours nearby results, zoomed out favours prominence. Only meaningful with bias.
bbox?[number, number, number, number]not statedHard bounding-box filter, [minLon, minLat, maxLon, maxLat] (WGS84). Unlike bias this excludes results outside the box outright.

GeocoderOptions

Interface

ts
interface GeocoderOptions

What the Geocoder needs. A MapMapMap satisfies this shape, so new Geocoder(map) reuses the map's gateway origin and key - the same convention as every other SDK class.

PropertyTypeDefaultDescription
baseUrlstringrequiredGateway base URL, e.g. https://api.mapmap.ai.
apiKey?string | undefinednot statedGateway API key (snk_…).

GradeStyleOptions

Interface

ts
interface GradeStyleOptions

Options for gradeStyleColours.

PropertyTypeDefaultDescription
strength?numbernot stated0..1, default 1.
skipLayerIds?ReadonlySet<string>not statedLayer ids to leave untouched (the theme's use_theme: "none" layers).

GroundReadableMap

Interface

ts
interface GroundReadableMap

The slice of a MapLibre map the live read needs (structural, so it works with whichever maplibre-gl copy the host app bundles).

Methods

  • getLayersOrder?(): string[]
  • getStyle?(): unknown
  • getLayer(id: string): { type?: string; } | undefined
  • getPaintProperty(id: string, name: string): unknown
  • getLayoutProperty(id: string, name: string): unknown

GuidanceSpokenPrompt

Interface

ts
interface GuidanceSpokenPrompt

The spoken prompt of a core guidance update.

PropertyTypeDefaultDescription
textstringrequiredPlain text for speech synthesis.
ssml?string | nullnot statedSSML form; browsers reject raw SSML, so it is stripped to text.
triggerDistanceMnumberrequiredMetres before the manoeuvre at which the core released the prompt.
utteranceIdstringrequiredUnique utterance id, the de-duplication key.

Interaction

Interface

ts
interface Interaction

One interaction, as passed to MapMapMap.addInteraction.

PropertyTypeDefaultDescription
typeInteractionTyperequired
target?InteractionTargetnot statedAbsent: the map itself (fires with no feature).
filter?FilterSpecificationnot statedOnly features matching this filter count as hits.
handler(e: InteractionEvent) => boolean | voidrequiredReturn true to stop propagation: interactions on features further down, and map-level interactions, do not get this event. Applies to click and mousemove; mouseenter and mouseleave always fire for every interaction listening.

InteractionEvent

Interface

ts
interface InteractionEvent

What an interaction handler receives.

PropertyTypeDefaultDescription
feature?MapGeoJSONFeaturenot statedThe feature under the pointer, topmost first. undefined for a map-level interaction (no target). For mouseleave it is the feature the pointer just left.
lngLatLngLatrequired
originalEventMouseEventrequired

InteractionTarget

Interface

ts
interface InteractionTarget

What an interaction listens on: one layer, or a featureset.

PropertyTypeDefaultDescription
layerId?stringnot stated
featuresetId?FeaturesetIdnot stated

IsochroneFeatureCollection

Interface

ts
interface IsochroneFeatureCollection

The GeoJSON FeatureCollection the gateway returns, passed through.

PropertyTypeDefaultDescription
type"FeatureCollection"required
snapped_origin?SnappedOriginnot statedWhere the rings start: the origin snapped onto the nearest road. Also on every feature's properties.snapped_origin.
features{ type: "Feature"; geometry: { type: string; coordinates: unknown; }; properties?: Record<string, unknown> | null; }[]required

IsochroneLayerOptions

Interface

ts
interface IsochroneLayerOptions
PropertyTypeDefaultDescription
baseUrl?stringthe map's baseUrl when given a mapGateway base URL. Defaults to the map's baseUrl when given a map.
apiKey?stringthe map's apiKey when given a mapGateway API key. Defaults to the map's apiKey when given a map.
id?string"mapmap-isochrone"Unique id prefix for the source/layers. Defaults to "mapmap-isochrone".

LaneIndication

Interface

ts
interface LaneIndication

One lane entry of a banner lane diagram.

PropertyTypeDefaultDescription
directionsstring[]requiredTurn directions this lane allows (OSRM indication strings).
valid?booleannot statedWhether the lane can be used for the maneuver. undefined means unknown, not unusable, banner components omit the flag for non-recommended lanes (see bannerLanes).
active?booleannot statedWhether guidance recommends this lane.
activeDirection?stringnot statedWhich one of directions guidance actually takes from this lane, when the server resolves it (the gateway's active_direction, set only on active lanes whose mask decodes to a single indication). A lane may permit several movements, "straight or right" is the common one, and only this field says which of them the route uses. Draw the lane arrow from it, falling back to the first permitted direction: see laneArrowDirection.

LayerOverride

Interface

ts
interface LayerOverride

Per-layer override: merged onto the skeleton layer with the same id. Mirrors sn_style::LayerOverride.

PropertyTypeDefaultDescription
visible?booleannot statedHide the layer entirely (layout.visibility = "none").
paint?Record<string, unknown>not statedPaint properties merged over the skeleton's (per-key, override wins).
layout?Record<string, unknown>not statedLayout properties merged over the skeleton's.
filter?unknownnot statedReplace the skeleton's filter (per-attribute styling hook).
minzoom?numbernot stated
maxzoom?numbernot stated
use_theme?UseThemenot statedWhether the theme's Theme.color_theme grades this layer (Mapbox *-use-theme): "none" keeps its colours as written. Mirrors LayerOverride::use_theme.

LogoOptions

Interface

ts
interface LogoOptions

Options for LogoControl.

PropertyTypeDefaultDescription
position?LogoPositionbottom-right, the opposite corner from the credit, which the SDK mounts bottom-left (movable with attributionPosition)Corner to render in. Default bottom-right, the opposite corner from the credit, which the SDK mounts bottom-left (movable with attributionPosition). That is the canonical MapMap layout: credit small bottom-left, mark bottom-right, never both in one corner (stacking the mark on the OSM credit makes a licence-required line unreadable). MapMapMap enforces that: if this corner is the credit's corner, the mark is mounted in the opposite bottom corner instead, with one console.warn for that map. When you add a LogoControl to a map yourself, pass the same corner here as to addControl, so its insets land on the right edges.
href?stringthe MapMap siteLink target when clicked. Default the MapMap site.
theme?MapBrandThemenot statedInitial variant: day (default) for light maps, night for dark. MapMapMap sets and updates this itself from the drawn style.

LutImageData

Interface

ts
interface LutImageData

The shape of ImageData that lutFromImageData reads.

PropertyTypeDefaultDescription
widthnumberrequired
heightnumberrequired
dataUint8ClampedArray | Uint8Arrayrequired

MapDiagnosticsInput

Interface

ts
interface MapDiagnosticsInput

What runMapDiagnostics needs; everything optional and structural.

PropertyTypeDefaultDescription
container?string | HTMLElementnot statedThe container option as given: an element or an element id.
map?unknownnot statedThe constructed map (or any object with a MapLibre-style on). Used to watch for tile-request auth failures.
maplibre?unknownnot statedThe maplibre-gl module the SDK is using (duplicate detection).
apiKey?string | undefinednot statedThe gateway API key, if one was configured.

MapMapBase

Interface

ts
interface MapMapBase

One entry in the catalogue.

PropertyTypeDefaultDescription
idMapMapBaseIdrequiredStable id: what baseTheme takes, and what the static-map API and the MCP create_style tool accept by the same name.
labelstringrequiredShort display label, e.g. "Navigator Night".
descriptionstringrequiredOne line saying what the base is for.
groupMapMapBaseGrouprequired"base" for the two stock slates, "designed" for a drawn style.
restrictionsbooleanrequiredTrue when the base is designed to be seen with MapMap's vehicle-restriction overlay. Only fleet sets it. The SDK cannot draw that overlay. It is a separate vector source the mapmap.ai website installs around the compiled style, because the render tiles carry no restriction attributes and no compiled style can express them. The flag is here so a caller building Fleet through this SDK knows it is getting the palette and nothing else, rather than shipping an industrial-looking map that appears to claim restriction data. Draw restrictions yourself from the routing API's own check_clearance_on_route / check_adr_tunnel, which answer for a real vehicle rather than colouring a basemap.
notCompiledHerereadonly string[]requiredTheme fields the canonical document carries that buildStyle cannot honour, so a caller can see what a browser-side build of this base leaves out rather than guessing. Empty for seven of the ten.
theme() => ThemerequiredA fresh document, safe to edit.

MapMapOptions

Interface

ts
interface MapMapOptions
PropertyTypeDefaultDescription
logo?boolean | LogoOptionsnot statedThe MapMap wordmark on the map (like the Google Maps / Mapbox marks). Always on, at bottom-right (the attribution's opposite corner); pass { position, href } to move or relink it. The mark cannot be taken off. Every displayed MapMap map carries it, which is a condition of the SDK licence, the same model as Mapbox GL JS v2+. false (and true) are still accepted so existing code keeps compiling: passing false is ignored, the mark is added anyway, and the SDK logs one console.warn for that map. false is soft-deprecated: it does nothing and will be dropped from the type in the next major. Use { position } to get the mark out of the way instead.
containerstring | HTMLElementrequiredThe container element or its id.
apiKey?stringnot statedGateway API key (snk_…), used by routing and ADR helpers and by the basemap. With a key and no territoryTilesUrl, the default styles read the keyed gateway tiles ({baseUrl}/tiles/planet/tiles.json?api_key=…), which work on any website; without one they read the keyless CDN, which serves only mapmap.ai and a local development server. A style URL on the gateway (/styles/…, /tiles/…) gets the key added the same way.
baseUrl?stringhttps://api.mapmap.aiGateway base URL for routing, ADR and the keyed basemap. Defaults to https://api.mapmap.ai.
style?MapMapTheme | Theme | StyleSpecification | string"light"Style to load. A theme name ("light" / "dark"), a MapMap Studio Theme document, a full MapLibre StyleSpecification, or a style URL. Defaults to "light".
territoryTilesUrl?stringnot statedOverride the territory PMTiles URL used by the default styles. Always wins over the keyed default that apiKey selects.
center?[number, number]the UKInitial centre as [lng, lat]. Defaults to the UK.
zoom?number5Initial zoom. Defaults to 5.
terrain?boolean | TerrainOptionsnot stated3D terrain from a DEM. true uses sensible defaults; pass TerrainOptions to set exaggeration, point at your own DEM tiles, or add relief shading. The default DEM is the same dataset the gateway reports from POST /elevation, so a map and an elevation query agree.
mapOptions?Partial<Omit<MapOptions, "container" | "style">>not statedExtra MapLibre MapOptions merged last (escape hatch for hash, bearing, maxBounds, etc.). container and style here are ignored. attributionControl is honoured but never allowed to remove or hide the credit: { customAttribution } works as MapLibre documents it, while attributionControl: false and { compact: true } are ignored (the credit stays on and always expanded, with no (i) button, and the SDK logs one console.warn for that map). The OpenStreetMap credit is a condition of the ODbL the map data is served under, for MapMap and for you.
attributionPosition?AttributionPosition"bottom-left", which is the canonical MapMap layout: attribution small bottom-left, MapMap mark bottom-rightCorner for the OpenStreetMap attribution. Default "bottom-left", which is the canonical MapMap layout: attribution small bottom-left, MapMap mark bottom-right. This chooses the credit's corner and nothing else; the credit itself stays on regardless (see mapOptions.attributionControl above), so there is no longer any reason to reach into map._controls to relocate it. The attribution and the mark never share a corner: stacking the mark on the credit makes a line the ODbL requires unreadable. If the corner requested here is the mark's corner (whether the mark's default bottom-right or an explicit logo.position), the mark moves to the opposite bottom corner and the SDK logs one console.warn for that map.

MarkerItem

Interface

ts
interface MarkerItem

One parsed marker of an extra.markers v1 block.

PropertyTypeDefaultDescription
idstringrequiredStable unique id, non-empty, at most 64 characters.
lngnumberrequiredLongitude, degrees, [-180, 180].
latnumberrequiredLatitude, degrees, [-90, 90].
iconMarkerGlyphId"pin"Glyph drawn on the pin (or the standalone dot). Default "pin".
image?stringnot statedOptional custom image (data: URI, png/jpeg/webp/svg+xml, at most 64 KB decoded). Overrides icon; an unusable image falls back to the default pin, never to nothing.
colourstring#1a6bffPin colour, #rrggbb (normalised lowercase). Default #1a6bff.
sizeMarkerSize"m" (32 CSS px)Size preset. Default "m" (32 CSS px).
label?stringnot statedOptional label drawn below the marker, at most 120 characters.

MarkersBlock

Interface

ts
interface MarkersBlock

A parsed extra.markers block.

PropertyTypeDefaultDescription
version1requiredBlock schema version; currently always 1.
itemsMarkerItem[]requiredThe valid markers, in input order, capped at 200.

MarkersLayerIds

Interface

ts
interface MarkersLayerIds

The generated MapLibre ids (see MarkersLayer.ids).

PropertyTypeDefaultDescription
sourcestringrequiredThe GeoJSON source id (mm-user-markers).
layerstringrequiredThe symbol layer id (mm-user-markers).

MarkersLayerOptions

Interface

ts
interface MarkersLayerOptions

Options for MarkersLayer.

PropertyTypeDefaultDescription
onImageError?(image: string, error: unknown) => voidnot statedCalled when a marker's custom image passes the schema (right media type, within the 64 KB cap) but MapLibre cannot rasterise it, most often an SVG with no intrinsic width/height, which <img> renders happily and createImageBitmap rejects. The marker keeps its glyph pin either way; this is the only way to TELL the user that the logo they can see in their editor will not be on the map.

Interface

ts
interface NavAlertKindDesign

Per-kind surfaces and channels. The three booleans are orthogonal: a kind can appear on the map without alerting, alert without appearing on the map, or be listed in the route preview only.

PropertyTypeDefaultDescription
showOnMapbooleanrequiredDraw a pin for this kind while BROWSING the map (no active guidance). Kept as the browse-mode field under its original name so themes saved before the browse/navigate split round-trip unchanged.
showOnMapWhileNavigatingbooleantrue, and absent in an older theme reads as true - the market shows cameras with or without a planned route, so gating map display behind guidance would be more restrictive than every product a driver has usedDraw a pin for this kind on the map DURING active navigation. Separate from showOnMap because the two are genuinely different decisions: a fleet product may want a clean driving map and a fully annotated planning map, or the reverse. Defaults to true, and absent in an older theme reads as true - the market shows cameras with or without a planned route, so gating map display behind guidance would be more restrictive than every product a driver has used.
alertWhileDrivingbooleanrequiredShow the alert chip for this kind while driving.
showInRoutePreviewbooleanrequiredList this kind in the pre-drive route preview.
alertModeNavAlertModerequiredWhen the AUDIBLE alert fires. The chip itself follows alertWhileDriving.
audioModeNavAlertAudioModerequiredWhich audio channel this kind uses.

Interface

ts
interface NavAlertsDesign

Safety-alert tokens (extra.nav.alerts): the camera alert chip, its escalated state, per-kind icons and surfaces, and the average-speed corridor highlight.

The whole block is optional since v1 - themes saved without it load unchanged and hosts keep their built-in look - but a block that IS present is always complete: every field, including both escalated tokens, parses to a value. The escalated state can be restyled, never removed.

Two states only, calm and escalated. There is no amber tier: no shipping navigation product uses a three-colour alert state and drivers have no learned mapping for one.

NOT STYLEABLE HERE: whether cameras may be shown at all. That is a server-side jurisdiction policy applied before any camera leaves the gateway. A design styles what the policy permits and nothing more.

PropertyTypeDefaultDescription
backgroundstringrequiredChip background in the calm (default) state.
textColorstringrequiredChip text and icon colour in the calm state.
outlineColorstringrequiredChip outline colour (both states).
cornerRadiusnumberrequiredChip corner radius in px, 0-24.
outlineWidthnumberrequiredChip outline width in px, 0-4.
escalatedBackgroundstringrequiredChip background when escalated (driver over the limit).
escalatedTextColorstringrequiredChip text and icon colour when escalated.
iconSetNavAlertIconSetrequiredCurated icon set for the chip and map pins.
iconUrlOverrides?Partial<Record<NavCameraKind, string>>not statedPer-kind icon overrides (https: or data: URIs only). Any kind left out keeps iconSet's icon. Absent when no kind is overridden.
alertSoundNavAlertSoundrequiredThe earcon played for a calm alert. One sound for the whole design, never one per kind - see NAV_ALERT_SOUNDS.
alertSoundUrl?stringnot statedOptional replacement for the calm earcon (https: or data: URIs only, same rule as iconUrlOverrides). Absent = the built-in alertSound.
escalatedSoundNavAlertSoundrequiredThe earcon played when the driver is over the limit. The escalated state is not removable - it can be restyled and its sound chosen, but a design cannot silence the escalation itself (set the kind's audioMode to off if you want no audio at all).
escalatedSoundUrl?stringnot statedOptional replacement for the escalated earcon; same URL rule.
mapIconSizenumberrequiredMap pin size as a multiplier of the default ramp, 0.75-1.5.
mapMinZoomnumberrequiredLowest zoom at which map pins are drawn, 9-14.
leadDistanceNavAlertLeadDistancerequiredLead-distance preset; see NAV_ALERT_LEAD_DISTANCE_M.
chipPositionNavAlertChipPositionrequiredWhich constrained slot the chip occupies.
corridorColorstringrequiredColour of the average-speed corridor highlight on the route line.
corridorOpacitynumberrequiredCorridor highlight opacity, 0-1.
kindsRecord<NavCameraKind, NavAlertKindDesign>requiredPer-kind surfaces and channels; always all five kinds.

Interface

ts
interface NavBannerDesign

Banner-instruction tokens (defaults match GuidanceBanner).

PropertyTypeDefaultDescription
backgroundstringrequiredBanner background colour.
textColorstringrequiredBanner text (and arrow) colour.
fontSizenumberrequiredPrimary text size in px.
showLanesbooleanrequiredWhether the lane diagram row is shown when lanes are present.
padding?numbernot statedInner padding in px, 6-24. Optional since v1; default 10.
cornerRadius?numbernot statedCorner radius in px, 0-24. Optional since v1; default 10.
maxWidth?numbernot statedMaximum banner width in px, 200-520. Optional since v1; default 340.
height?numbernot statedBanner height in px, 40-120. Optional since v1; unset means auto - the banner takes its natural content height (old themes keep theirs).

Interface

ts
interface NavCameraDesign

Drive-camera tokens: how the chase cam frames a turn-by-turn drive. The whole block is optional since v1 - themes saved without it load unchanged and the SDK keeps its built-in framing. Every field is itself optional (absent = the documented default). NavigationCamera reads pitch/zoom as its option defaults; speedMps drives Studio's demo drive (and any route simulator) - a camera following real GPS fixes ignores it.

PropertyTypeDefaultDescription
pitch?number60Chase-cam tilt in degrees, 0-85. Default 60.
zoom?number17.5Chase-cam zoom, 14-20. Default 17.5.
speedMps?number12 (~43 km/h)Drive speed in metres per second, 2-40. Default 12 (~43 km/h).

Interface

ts
interface NavDesign

The extra.nav block: navigation design tokens for the SDKs.

PropertyTypeDefaultDescription
version1requiredBlock schema version; currently always 1.
routeNavRouteDesignrequired
puckNavPuckDesignrequired
bannerNavBannerDesignrequired
camera?NavCameraDesignnot statedOptional since v1: drive-camera framing (pitch/zoom) and speed. Absent means "SDK built-ins" - the block stays version: 1 either way.
alerts?NavAlertsDesignnot statedOptional since v1: safety-alert chip, per-kind surfaces and corridor highlight. Absent means "SDK built-ins"; the block stays version: 1.

Interface

ts
interface NavigationCameraOptions
PropertyTypeDefaultDescription
pitch?number60 - MapLibre's non-experimental ceilingCamera tilt in degrees, clamped to 0-85. Default 60 - MapLibre's non-experimental ceiling; values above 60 may show rendering artefacts and flatten DOM-marker pucks. When the requested pitch exceeds the map's maxPitch, the limit is raised to match. Precedence: this option > the Studio design's camera.pitch (when the map is a MapMapMap whose theme carried extra.nav.camera) > the built-in default.
zoom?number17Follow-mode zoom. Default 17. Same precedence as pitch: option > Studio design camera.zoom > built-in default.
anchorY?number0.72 - the puck rides low so the camera looks up the road aheadWhere the fix (and puck) sits vertically on screen, as a fraction of the container height from the top, clamped to 0-1. Default 0.72 - the puck rides low so the camera looks up the road ahead.
easeMs?number900, and always capped by the observed fix interval so a fast fix cadence never queues up lagging animationsEase duration per NavigationCamera.follow call, milliseconds. Default 900, and always capped by the observed fix interval so a fast fix cadence never queues up lagging animations.
autoRecentreMs?number6000Idle time after the last user gesture before the camera recentres itself back to follow mode, milliseconds. Default 6000; 0 disables auto-recentre (the app must call NavigationCamera.resume).

Interface

ts
interface NavPuckDesign

Current-position puck tokens.

PropertyTypeDefaultDescription
colorstringrequiredPuck fill colour.
sizenumberrequiredPuck diameter in px.
headingArrowbooleanrequiredWhether the heading arrow is drawn on the puck.
imageUrl?stringnot statedOptional custom puck image (https: or data: URI, PNG/SVG). When set it replaces the built-in dot + arrow; size still scales it. Optional since v1 - themes saved without it load unchanged.

Interface

ts
interface NavRouteDesign

Route-line tokens (defaults match RouteLayer's built-in look).

PropertyTypeDefaultDescription
colorstringMapMap signal blue (SIGNAL_BLUE)Line colour. Default is MapMap signal blue (SIGNAL_BLUE).
widthnumberrequiredLine width in px at mid zoom.
opacitynumberrequiredLine opacity, 0-1.
casingColorstringrequiredCasing (outline) colour drawn under the line.
casingWidth?numberwidth + 4Casing width in px. Defaults to width + 4. Optional because the casing was previously always width + 4, which cannot express a design whose casing is not exactly four wider than its line (the playground's is 9 over a 4.5 line).
casingOpacity?numberNavRouteDesign.opacityCasing opacity, 0-1. Defaults to NavRouteDesign.opacity. Optional because casing and line previously shared one opacity, which cannot express a translucent casing under a solid line.
dash?number[] | nullnot statedLine dash pattern, in line-widths, as MapLibre's line-dasharray. Omitted or null draws a solid line.

NearestByDriveTimeOptions

Interface

ts
interface NearestByDriveTimeOptions

Options for PlacesLayer.nearestByDriveTime.

PropertyTypeDefaultDescription
n?number1How many places to return. Defaults to 1.
costing?stringnot statedGateway costing model, e.g. "auto" (default) or "truck" (Premium price class - see POST /matrix in the API docs).
costingOptions?Record<string, unknown>not statedValhalla-style costing options forwarded verbatim, e.g. { truck: { height: 4.0 } }.

ParsedRoute

Interface

ts
interface ParsedRoute

A parsed OSRM route, normalised to the fields callers actually use.

PropertyTypeDefaultDescription
distanceMnumberrequiredTotal distance, metres.
durationSnumberrequiredTotal duration, seconds.
geometryRouteGeometryrequiredRoute line as GeoJSON, ready to hand to a MapLibre source.
rawRecord<string, unknown>requiredThe raw OSRM routes[0] object, for callers that need leg/step detail.

PersistentIds

Interface

ts
interface PersistentIds

The ids MapMapMap.persistentIds reports, in registry order.

PropertyTypeDefaultDescription
sourcesstring[]required
layersstring[]required

PersistentLayerOptions

Interface

ts
interface PersistentLayerOptions

Where MapMapMap.addPersistentLayer puts a layer.

PropertyTypeDefaultDescription
slot?Slotnot statedThe insertion slot (bottom, middle, top), re-resolved on every style load. Layers in the same slot keep the order they were added in, the latest on top.
beforeId?stringnot statedInsert below this layer instead. Wins over slot while the layer exists; when it does not (another style, or it was removed), slot applies, and with no slot the layer is appended on top.

Place

Interface

ts
interface Place

One place to show on the map - a store, depot, branch, POI.

PropertyTypeDefaultDescription
idstringrequiredStable unique id, e.g. your store number.
namestringrequiredDisplay name.
latnumberrequiredLatitude, degrees.
lonnumberrequiredLongitude, degrees.
properties?Record<string, unknown>not statedArbitrary extra data (opening hours, phone, …). Every key is copied verbatim onto the top level of the GeoJSON feature's properties, alongside the reserved id, name and __mapmapIndex keys (which win on collision) - so scalar values are directly addressable from a data-driven color expression, e.g. ["get", "category"]. Nested objects and arrays behave differently on each MapLibre major, and the peer range admits both. On MapLibre 5 they are JSON-stringified at render time, so ["get", "details"] and a String(...) in your own code both see JSON text. On MapLibre 6 they are encoded and parsed back, so the same key is a real object or array: a ["get", …] bound to it renders nothing where it used to render the JSON text, a ["match", ["get", …], …] type-errors in the expression evaluator instead of falling through to its default, and String(...) gives "[object Object]". So: keep anything you want to style on, or print, as a top-level string/number/boolean, and if you do read a nested value back off a feature, handle both shapes (typeof v === "string" ? JSON.parse(v) : v). The whole object also comes back on the place handed to onPlaceClick / popup, and that path is the same on both majors: it reads the place you passed in, not round-tripped feature properties.

PlacePointFeature

Interface

ts
interface PlacePointFeature

A GeoJSON Point feature, as accepted in a PlacesFeatureCollection.

PropertyTypeDefaultDescription
type"Feature"required
id?string | numbernot stated
geometry{ type: "Point"; coordinates: number[]; }required
properties?Record<string, unknown> | nullnot stated

PlacesFeatureCollection

Interface

ts
interface PlacesFeatureCollection

A plain GeoJSON FeatureCollection of Points, accepted anywhere a Place[] is (structurally compatible with @types/geojson's FeatureCollection<Point>). See placesFromGeoJSON for how ids and names are derived.

PropertyTypeDefaultDescription
type"FeatureCollection"required
featuresPlacePointFeature[]required

PlacesIcon

Interface

ts
interface PlacesIcon

A custom pin image for unclustered places.

PropertyTypeDefaultDescription
urlstringrequiredImage URL (any format Map#loadImage accepts, e.g. PNG).
size?number1MapLibre icon-size scale factor. Defaults to 1.

PlacesLabelOptions

Interface

ts
interface PlacesLabelOptions

Options for the per-place name labels (see PlacesLayerOptions.label).

The colour keys accept BOTH spellings: colour/haloColour (British, as first shipped) and color/haloColor (matching the sibling color/clusterColor options on PlacesLayerOptions). A dynamically built options object should not lose its labels' colours to a spelling mismatch. British wins if somehow both are given.

PropertyTypeDefaultDescription
property?string"name" - every place carries its name thereFeature property holding the label text (see Place.properties for what is addressable). Defaults to "name" - every place carries its name there.
size?number12Text size in px. Defaults to 12.
colour?stringa dark ink (#333333)Text colour. Defaults to a dark ink (#333333). Alias: color.
color?stringnot statedText colour, American spelling of PlacesLabelOptions.colour.
haloColour?stringwhiteHalo colour behind the text. Defaults to white. Alias: haloColor.
haloColor?stringnot statedHalo colour, American spelling of PlacesLabelOptions.haloColour.

PlacesLayerIds

Interface

ts
interface PlacesLayerIds

The generated MapLibre source/layer ids (see PlacesLayer.ids).

PropertyTypeDefaultDescription
sourcestringrequiredThe GeoJSON source id.
pointsstringrequiredThe unclustered-points layer id (circle, or symbol with icon).
clustersstringrequiredThe cluster circles layer id (only installed with cluster: true).
clusterCountsstringrequiredThe cluster count badge layer id (only installed with cluster: true).
labelsstringrequiredThe labels symbol layer id (only installed with a label option).
pointsFallbackstringrequiredThe circle layer drawn under places without a loaded per-place icon (only installed when icon is a record of images).

PlacesLayerOptions

Interface

ts
interface PlacesLayerOptions
PropertyTypeDefaultDescription
places?PlacesInputnot statedInitial places. Also settable later via PlacesLayer.setPlaces.
cluster?booleantrueCluster nearby places into count badges. Defaults to true.
clusterRadius?numberMapLibre's 50Cluster radius in pixels. Defaults to MapLibre's 50.
clusterMaxZoom?numberMapLibre's 14Max zoom to cluster at. Defaults to MapLibre's 14.
color?string | ExpressionSpecificationMapMap signal blue (#3a86ff)Pin colour: a CSS colour string, or a MapLibre expression evaluated against each feature's properties for per-category pins, e.g. ["match", ["get", "category"], "food", "#e63946", "#3a86ff"] (see Place.properties for what an expression can get). Defaults to MapMap signal blue (#3a86ff). Only styles the default circle pins - ignored with a custom icon. A cluster mixes categories, so an expression never applies to clusters: they use clusterColor.
clusterColor?stringcolor when that is a plain string, else to MapMap signal blue (a cluster mixes categories, so a data-driven color expression cannot apply to it)Cluster circle colour. Defaults to color when that is a plain string, else to MapMap signal blue (a cluster mixes categories, so a data-driven color expression cannot apply to it).
icon?PlacesIcon | Record<string, PlacesIcon>"kind"Custom pin image for unclustered places (a symbol layer instead of the default circle). If the image fails to load, the circle look is used. Also accepts a record of images keyed by a feature-property value for per-place icons - e.g. { cafe: { url: … }, fuel: { url: … } } picks an image per place from the property named by iconProperty (default "kind"). Places whose property value has no entry - or whose entry's image fails to load - keep the default circle look.
iconProperty?string"kind"Feature property that selects a per-place icon when icon is a record (ignored for a single icon). Defaults to "kind". Set place properties values to the record's keys.
label?boolean | PlacesLabelOptionsnot statedPer-place name labels beside the points. true labels every place with its name; an options object customises the property, size and colours (see PlacesLabelOptions). Labels are drawn in the map font with a halo, hide before they collide (text-optional), and only ever appear on unclustered points. Omit for no labels (today's behaviour).
fitBounds?booleanfalse (the map view is left alone)Fit the map to the places the first time they are set. Defaults to false (the map view is left alone).
id?string"mapmap-places"Unique id prefix for the source/layers. Defaults to "mapmap-places".
baseUrl?stringthe map's baseUrl when given a mapGateway base URL. Defaults to the map's baseUrl when given a map.
apiKey?stringthe map's apiKey when given a mapGateway API key. Defaults to the map's apiKey when given a map.
onPlaceClick?(place: Place, lngLat: { lng: number; lat: number; }) => voidnot statedCalled when an individual (unclustered) place is clicked.
popup?(place: Place) => string | HTMLElementnot statedBuilt-in popup: return HTML (a string is set with setHTML, an element with setDOMContent) and a maplibregl.Popup opens at the place on click. Omit for no popup.

PlacesSelectOptions

Interface

ts
interface PlacesSelectOptions

Options for PlacesLayer.select.

PropertyTypeDefaultDescription
popup?booleantrueOpen the layer's configured popup at the place. Defaults to true.
flyTo?booleantrueEase the camera to the place. Defaults to true.
zoom?numbernot statedZoom for the camera move (with flyTo). Keeps the current zoom if omitted.

PoiCategoryDesign

Interface

ts
interface PoiCategoryDesign

One category's overrides. Both fields optional: absent = built-in.

PropertyTypeDefaultDescription
color?stringnot statedDot fill colour (replaces the built-in category brand colour).
textColor?stringnot statedLabel text colour for this category (replaces textSecondary).

PoiDesign

Interface

ts
interface PoiDesign

The extra.poi block: POI category design.

PropertyTypeDefaultDescription
version1requiredBlock schema version; currently always 1.
categoriesRecord<string, PoiCategoryDesign>requiredOverrides by category id; empty = all built-in.

PositionPuckOptions

Interface

ts
interface PositionPuckOptions

Options for PositionPuck.

PropertyTypeDefaultDescription
interpolate?booleantrueAnimate between fixes instead of snapping (default true). Position lerps linearly and heading tweens along the shortest arc, over a duration adapted to the observed fix interval (like the NavigationCamera glide, so puck and camera arrive together). Falls back to instant placement where requestAnimationFrame is missing.
now?() => numberTest seam: clock override, defaults to Date.nowTest seam: clock override, defaults to Date.now.
requestFrame?(callback: () => void) => numberTest seam: frame scheduler override, defaults to rAFTest seam: frame scheduler override, defaults to rAF.
cancelFrame?(handle: number) => voidTest seam: frame canceller override, defaults to cancelAnimationFrameTest seam: frame canceller override, defaults to cancelAnimationFrame.

ProjectionArgs

Interface

ts
interface ProjectionArgs

The subset of MapLibre's CustomRenderMethodInput this helper reads.

PropertyTypeDefaultDescription
shaderData{ variantName: string; vertexShaderPrelude: string; define: string; }required
defaultProjectionData{ mainMatrix: ArrayLike<number>; fallbackMatrix: ArrayLike<number>; tileMercatorCoords: [number, number, number, number]; clippingPlane: [number, number, number, number]; projectionTransition: number; }required

Rendered

Interface

ts
interface Rendered

Where to draw one vehicle at the requested moment.

PropertyTypeDefaultDescription
idstringrequired
lngnumberrequired
latnumberrequired
bearingnumber | nullrequiredHeading in degrees clockwise from north, or null when unknown.
movingbooleanrequiredTrue while the vehicle is between two different fixes.
vehicleTransitVehiclerequiredThe newest fix's vehicle record (for labels and popups).

RenderedMarkerImage

Interface

ts
interface RenderedMarkerImage

What renderMarkerImage returns, ready for map.addImage.

PropertyTypeDefaultDescription
imageImageDatarequiredThe rasterised marker, drawn at 2x.
pixelRatio2requiredPass to addImage so the marker displays at its CSS pixel size.

RenderMarkerImageOptions

Interface

ts
interface RenderMarkerImageOptions

Options for renderMarkerImage.

PropertyTypeDefaultDescription
icon?MarkerGlyphId"pin"Glyph to draw. Default "pin".
colour?stringthe marker bluePin (or dot) colour. Default the marker blue.
size?MarkerSize"m" (32 CSS px)Size preset. Default "m" (32 CSS px).
text?stringnot statedShort text (1-3 characters) drawn in white in the pin head INSTEAD of the glyph - numbered waypoints ("1", "2") and lettered stops ("A", "B"). Longer strings are cut to MAX_MARKER_TEXT_LENGTH; blank strings fall back to the glyph. Text always draws the pin body, so icon: "dot" is ignored when text is given (a dot has no head to write in).

ReverseGeocodeOptions

Interface

ts
interface ReverseGeocodeOptions

Options for reverse geocoding (GET /geocode/reverse).

PropertyTypeDefaultDescription
limit?numbernot statedMaximum results.
kinds?GeocodeKind[]not statedRestrict hits to these kinds. ["poi"] is the "what place did the user tap" lookup. First-party backend only.
categories?string[]not statedCategory browse: the nearest places of these categories, nearest first (["cafe"], ["fuel", "charging_station"]). Implies kinds=poi. First-party backend only.
name?stringnot statedRestrict hits to places of this name or brand, nearest first - the "nearest Lloyds bank" question. First-party backend only.

RibbonMesh

Interface

ts
interface RibbonMesh

A tessellated route ribbon, ready for a TRIANGLE_STRIP draw.

PropertyTypeDefaultDescription
verticesFloat32ArrayrequiredInterleaved vertex data, RIBBON_FLOATS_PER_VERTEX floats per vertex: mercator position, the unit extrusion normal (the shader extrudes pos + normal * halfWidth, so width stays zoom-correct without re-tessellating), and progress along the route (0 at the start, 1 at the end - the flowing gradient's coordinate).
vertexCountnumberrequiredNumber of vertices (two per route point kept).

RouteEffectLayer

Interface

ts
interface RouteEffectLayer extends CustomLayerInterface

A route effect layer: a custom layer that can retarget its geometry.

Extends CustomLayerInterface.

Methods

  • setGeometry(geometry: RouteGeometry): void

RouteFlowOptions

Interface

ts
interface RouteFlowOptions

Options for the "flow" route effect (all optional).

PropertyTypeDefaultDescription
color?stringMapMap signal blueRibbon colour (hex or rgb()/rgba()). Defaults to MapMap signal blue.
width?number10Ribbon width in CSS pixels. Defaults to 10.
speed?number0.6Flow speed in pulse cycles per second. Defaults to 0.6.
id?string"mapmap-route-effect"MapLibre layer id. Defaults to "mapmap-route-effect".

RouteGeometry

Interface

ts
interface RouteGeometry

A parsed GeoJSON LineString geometry ([lng, lat] positions).

PropertyTypeDefaultDescription
type"LineString"required
coordinates[number, number][]required

RouteLayerIds

Interface

ts
interface RouteLayerIds

The MapLibre ids a RouteLayer owns (see RouteLayer.ids).

PropertyTypeDefaultDescription
sourcestringrequiredGeoJSON source holding the route line.
casingstringrequiredLine layer drawn under the route (the darker casing).
linestringrequiredLine layer for the route itself.
maneuverSourcestringrequiredGeoJSON source for the manoeuvre arrow.
maneuverstringrequiredSymbol layer for the manoeuvre arrow.
corridorSourcestringrequiredGeoJSON source for the average-speed corridors.
corridorstringrequiredLine layer tinting the average-speed corridors.
endpointsSourcestringrequiredGeoJSON source for the start/end/waypoint markers.
endpointsstringrequiredSymbol layer drawing the start/end/waypoint markers.

RouteLayerOptions

Interface

ts
interface RouteLayerOptions
PropertyTypeDefaultDescription
baseUrl?stringthe map's baseUrl when given a mapGateway base URL. Defaults to the map's baseUrl when given a map.
apiKey?stringthe map's apiKey when given a mapGateway API key. Defaults to the map's apiKey when given a map.
id?string"mapmap-route"Unique id prefix for the source/layers. Defaults to "mapmap-route".
design?NavRouteDesignthe map's navDesign.route when given a MapMapMap whose theme carried oneStudio route design (extra.nav route block). Defaults to the map's navDesign.route when given a MapMapMap whose theme carried one; without a design the layer keeps its built-in signal-blue look.
alertsDesign?NavAlertsDesignthe map's navDesign.alerts when given a MapMapMap whose theme carried oneStudio safety-alert design (extra.nav alerts block), used for the average-speed corridor highlight drawn by RouteLayer.setAlertCorridors. Defaults to the map's navDesign.alerts when given a MapMapMap whose theme carried one.
progressColor?stringa dimmed greyColour of the already-travelled part of the line once RouteLayer.setProgress is used (the Google-style "vanishing route line"). Defaults to a dimmed grey.
alternativeCasingColor?stringnot statedCasing colour for unselected alternative routes.
alternativeColor?stringnot statedLine colour for unselected alternative routes.
ferryColor?stringnot statedColour of the ferry dashes drawn over the selected route.
endpoints?boolean | EndpointsDesignOff by default: a layer built without this option behaves exactly as it always hasBranded start/end/waypoint markers on the drawn route. Off by default: a layer built without this option behaves exactly as it always has. true uses the brand defaults (green dot at the start, blue pin at the end, smaller numbered blue pins at each intermediate stop); an EndpointsDesign overrides any of them, and false on one endpoint drops just that one. The coordinates come from the route itself: first coordinate = start, last = end. Intermediate stops are remembered from RouteLayer.routePath's via points, or set explicitly with RouteLayer.setWaypoints when drawing a route parsed elsewhere. These are symbol-layer markers, not DOM maplibregl.Markers, so they appear in canvas exports and match the native SDKs.

RouteLineStyle

Interface

ts
interface RouteLineStyle

Runtime overrides for the drawn line, applied over the design or the built-in look. Every field is optional; omitted ones are left alone.

PropertyTypeDefaultDescription
color?stringnot statedLine colour.
dash?number[] | nullnot statedDash pattern in line-widths, or null for solid.
casingOpacity?numbernot statedCasing opacity, 0-1. Set 0 to hide the casing entirely.

RouteOptions

Interface

ts
interface RouteOptions

Options for a single route request.

PropertyTypeDefaultDescription
profile?RouteProfile"driving"Routing profile. Defaults to "driving".
truck?TruckParamsnot statedTruck / ADR parameters (only meaningful with profile: "truck").
voice?booleannot statedRequest spoken voiceInstructions on each step (see guidance.ts).
banner?booleannot statedRequest visual bannerInstructions (and lane data) on each step.
language?stringnot statedBCP 47 narration language, e.g. "en-GB".

SearchBoxMap

Interface

ts
interface SearchBoxMap

The slice of a MapLibre map this control uses. Declared structurally so the module never imports maplibre-gl, a maplibregl.Map and a MapMapMap's .map both satisfy it, and so does a test fake.

Methods

  • getCenter(): { lng: number; lat: number; }
  • flyTo(options: { center: [number, number]; zoom?: number; }): unknown
  • getSource(id: string): unknown
  • addSource(id: string, source: unknown): unknown
  • getLayer(id: string): unknown
  • addLayer(layer: unknown): unknown
  • removeLayer(id: string): unknown
  • removeSource(id: string): unknown
  • isStyleLoaded(): boolean
  • on(type: string, listener: () => void): unknown
  • off(type: string, listener: () => void): unknown

SearchBoxOptions

Interface

ts
interface SearchBoxOptions

Options for SearchBox.

PropertyTypeDefaultDescription
apiKey?stringnot statedGateway API key (snk_…). Omit on a deployment serving the keyless demo lane.
gatewayUrl?stringhttps://api.mapmap.aiGateway base URL. Default https://api.mapmap.ai.
placeholder?string"Search places"Placeholder text for the input. Default "Search places".
limit?number5Maximum suggestions per request, 1–10. Default 5.
debounceMs?numberDEFAULT_DEBOUNCE_MSMilliseconds of quiet before a keystroke becomes a request. Default DEFAULT_DEBOUNCE_MS. This is a billing control as well as a UX one: every request that reaches the gateway is a metered call.
bias?SearchBoxBiasnot statedLocation bias. "map-centre" (the default) reads the map's centre on each request, so results follow the view; an explicit { lat, lon } pins it; false sends no bias at all.
flyTo?booleantrueFly the map to the picked result. Default true.
marker?booleantrueDrop a marker on the picked result. Default true.

SearchBoxSelectEvent

Interface

ts
interface SearchBoxSelectEvent

What SearchBox emits when the user picks a result.

PropertyTypeDefaultDescription
suggestionSearchSuggestionrequiredThe row the user picked, exactly as the suggest endpoint sent it.
hit?GeocodeHitnot statedThe full feature from GET /geocode/retrieve, or undefined when the retrieve failed. The suggestion's own coordinates are always present, so a failed retrieve still leaves the caller with a usable point.
querystringrequiredThe query text that produced the suggestion.

SearchSuggestion

Interface

ts
interface SearchSuggestion

One row of the suggestion dropdown, as GET /geocode/suggest sends it.

PropertyTypeDefaultDescription
idstringrequiredStable document id, what GET /geocode/retrieve takes.
namestringrequiredPrimary line: the place's name.
contextstringrequiredSecondary line: street, city, region, postcode, country.
kindstringrequiredDocument kind: poi, address, street, postcode, city, …
latnumberrequiredLatitude (WGS84).
lonnumberrequiredLongitude (WGS84).

SetRouteEffectOptions

Interface

ts
interface SetRouteEffectOptions extends RouteFlowOptions

Options for MapMapMap.setRouteEffect.

Extends RouteFlowOptions.

PropertyTypeDefaultDescription
geometry?RouteGeometrynot statedThe route line to attach the effect to. Optional: when omitted the effect is ARMED and applies as soon as a RouteLayer draws a route (RouteLayer feeds every drawn geometry to the map automatically).

SeverityProsody

Interface

ts
interface SeverityProsody

Speech parameters for one severity level.

PropertyTypeDefaultDescription
ratenumberrequiredUtterance rate.
pitchnumberrequiredUtterance pitch (0–2, 1 = neutral).
interruptbooleanrequiredWhether pending speech is cancelled before this prompt.

ShowReachabilityOptions

Interface

ts
interface ShowReachabilityOptions
PropertyTypeDefaultDescription
originLngLatLikerequiredWhere the rings radiate from.
mode?ReachabilityMode"walk" - these are walkability ringsTravel mode. Defaults to "walk" - these are walkability rings.
minutesnumber[]requiredRing contours in minutes, e.g. [5, 10, 15]. At least one.
color?stringMapMap signal blueRing colour. Defaults to MapMap signal blue.
costingOptions?Record<string, unknown>not statedValhalla-style costing options forwarded verbatim, e.g. { pedestrian: { use_lit: 1.0 } }.

SnappedOrigin

Interface

ts
interface SnappedOrigin

Where the gateway moved the origin to: the nearest usable road.

PropertyTypeDefaultDescription
latnumberrequired
lonnumberrequired
distance_mnumberrequiredGreat-circle distance from the requested origin, in metres.

SpeakOptions

Interface

ts
interface SpeakOptions

Options for speak.

PropertyTypeDefaultDescription
lang?stringnot statedBCP 47 language for the utterance, e.g. en-GB.
rate?numbernot statedSpeech rate (0.1–10, default 1).

StepGuidance

Interface

ts
interface StepGuidance

Guidance data for one step of the route.

PropertyTypeDefaultDescription
stepIndexnumberrequiredStep index within the flattened route.
distanceMnumberrequiredStep length in metres.
instruction?stringnot statedWritten instruction for the step's upcoming maneuver. Taken from maneuver.instruction when a server emits it (Mapbox-style); the MapMap gateway does not, so it falls back to the step's final voice announcement (the pre-transition instruction) and then to the banner primary text. Undefined only when the step carries no guidance at all.
voiceVoiceInstruction[]requiredSpoken announcements, ordered by descending trigger distance.
bannersBannerInstruction[]requiredVisual banners for the upcoming maneuver.
mode?stringnot statedOSRM travel mode of the step (driving, ferry, …) where the server emits it. Pass the guidance entry as GuidanceBanner.update's second argument so ferry legs render the ferry icon.
drivingSide?stringnot statedleft/right: the side traffic drives on at this step's own manoeuvre, where the server emits it. The MapMap gateway sets it on roundabout enter/exit steps and u-turn steps (read from the engine, never assumed); OSRM and Mapbox routers set it on every step.
bannerIcon?DirectionIconNamenot statedThe direction glyph for the manoeuvre this step's banners describe. A banner on step N describes the manoeuvre that STARTS step N+1 (Mapbox convention), so this is resolved from that next step, not this one: its own driving_side, and for a roundabout the enter/exit pair's through angle (see iconNamesForSteps). GuidanceBanner draws it when you pass this entry as update's second argument. Undefined on a leg's last step, which has no banner.

SuggestUrlOptions

Interface

ts
interface SuggestUrlOptions

Query parameters buildSuggestUrl understands.

PropertyTypeDefaultDescription
limit?numbernot statedMaximum suggestions, 1–10.
bias?[number, number]not statedBias point as [lon, lat].
zoom?numbernot statedMap zoom, scaling the bias.

TerrainOptions

Interface

ts
interface TerrainOptions

Terrain configuration. true means "on, with sensible defaults".

PropertyTypeDefaultDescription
exaggeration?numbernot statedVertical exaggeration. 1 is true-to-life; 1.2–1.5 reads better on gentle terrain. Clamped to 0–8.
url?stringthe Mapzen terrarium set on AWS Open Data, the same dataset the MapMap gateway reports as mapzen-terrain-tiles from POST /elevation, so a map and an elevation query agree with each otherDEM tile template. Defaults to the Mapzen terrarium set on AWS Open Data, the same dataset the MapMap gateway reports as mapzen-terrain-tiles from POST /elevation, so a map and an elevation query agree with each other. Self-hosters: point this at your own terrarium tiles.
encoding?"terrarium" | "mapbox""terrarium"Encoding of the DEM tiles. Defaults to "terrarium".
maxzoom?number15Max zoom of the DEM tile set. Defaults to 15.
tileSize?number256Tile size in px. Defaults to 256.
attribution?stringthe Mapzen/AWS creditAttribution for the DEM. Defaults to the Mapzen/AWS credit.
hillshade?booleannot statedAdd a hillshade layer as well, for relief shading that reads even with the camera pointing straight down. Uses its own source (see 3).

Theme

Interface

ts
interface Theme

A MapMap Studio theme: the unit users and agents edit, store and publish. Mirrors sn_style::Theme (all fields carry serde defaults, so everything is optional here).

PropertyTypeDefaultDescription
name?stringnot statedHuman-readable theme name, e.g. "midnight-fleet".
base?MapMapTheme"light"Built-in palette to start from. Defaults to "light".
palette?Record<string, string>not statedPalette overrides by slot name (see PALETTE_SLOTS).
layers?Record<string, LayerOverride>not statedPer-layer overrides by skeleton layer id.
buildings_3d?booleanWeb-safe; native navigation SDKs should leave this off by default until MapLibre Native's fill-extrusion memory use at street zooms is fixed (maplibre-native#4107)Render buildings as 3D extrusions. Adds a building-3d fill-extrusion layer (zoom 15+) driven by the tiles' render_height / render_min_height attributes, and caps the flat building footprint layer at that zoom so the two hand off cleanly (the extrusion rises from flat as you zoom in). Web-safe; native navigation SDKs should leave this off by default until MapLibre Native's fill-extrusion memory use at street zooms is fixed (maplibre-native#4107). Mirrors Theme::buildings_3d.
fonts?{ regular?: string; }Every fontstack must exist on the glyph server; until that ships (P2), leave this at its default ("MapMap Sans Regular")Label fonts. Every fontstack must exist on the glyph server; until that ships (P2), leave this at its default ("MapMap Sans Regular").
glyphs?stringDEFAULT_GLYPHS_URLOverride the glyph endpoint (defaults to DEFAULT_GLYPHS_URL).
sprite?stringnot statedOptional sprite URL. Absent, the style uses DEFAULT_SPRITE_URL (which carries the road-shield blanks); a sheet that is not a MapMap /sprite/sprite drops the road-shield layer.
sources?Record<string, ThemeSource>not statedCustomer-hosted sources by id: GeoJSON, vector, raster or image, each by https:// or pmtiles://https:// URL (MapMap stores the URL, never the data). At most MAX_THEME_SOURCES. Compiled into the style's sources beside territory. Mirrors Theme::sources.
extra_layers?JsonObject[]not statedExtra fully-formed MapLibre layers. Each draws from the territory source (with a known source-layer) or from one of Theme.sources, and may name a slot ("bottom", "middle" or "top", see slots.ts). Without a slot a layer goes in middle: above the base map and 3D buildings, below labels.
effects?ThemeEffectsnot statedOptional visual effects (route ribbon etc.). Compiled into metadata["mapmap:effects"] on the style, see ThemeEffects. Mirrors Theme::effects.
extra?{ nav?: unknown; poi?: unknown; }not statedNon-style extras carried by the THEME DOCUMENT, not the compiled style. Studio stores its navigation design block here (extra.nav; see nav-design.ts) and its POI category design (extra.poi; see poi-design.ts). buildStyle ignores it entirely - the compiled style.json is byte-identical with or without it. Mirrors Theme::extra in the canonical Rust crate: the hosted styles API stores the block verbatim (bounded at 256 KB serialised) and serves it back from GET /styles/{id}/theme, so a Studio design survives publishing - consume it via createMap with a theme document or navDesignFromThemeUrl / poiDesignFromThemeUrl with the hosted theme URL.
color_theme?ColourThemenot statedA colour theme: a 16x16x16 LUT (base64 of 12288 bytes) that grades every colour of the compiled style, the compile-time twin of map.setColorTheme (Mapbox root color-theme). Absent, the style compiles byte-identically. Mirrors Theme::color_theme.

ThemeEffects

Interface

ts
interface ThemeEffects

The optional visual-effects block, mirroring sn_style::Effects. Unlike extra, this IS carried into the compiled style, as metadata["mapmap:effects"], so any consumer of a compiled style.json (hosted style URL, baked territory package) can honour it without the theme document. Renderers that do not know the effects engine ignore the metadata and render the style unchanged.

PropertyTypeDefaultDescription
route?"flow" | "none"not statedRoute-line effect: "flow" (animated energy ribbon) or "none".
params?Record<string, unknown>not statedEffect parameters, validated per effect. For flow: color (CSS colour), width (px, 0.5-40), speed (cycles/s, 0-10).

ThemeSchedulerOptions

Interface

ts
interface ThemeSchedulerOptions

Options for ThemeScheduler.

PropertyTypeDefaultDescription
latnumberrequiredLatitude used for the solar calculation.
lngnumberrequiredLongitude used for the solar calculation.
onLight() => voidrequiredCalled (immediately on construction, then at each sunrise) for light.
onDark() => voidrequiredCalled (immediately on construction, then at each sunset) for dark.
now?() => numberTest seam: clock override, defaults to Date.nowTest seam: clock override, defaults to Date.now.
setTimeoutFn?(callback: () => void, ms: number) => ReturnType<typeof setTimeout>Test seam: timer override, defaults to setTimeoutTest seam: timer override, defaults to setTimeout.
clearTimeoutFn?(handle: ReturnType<typeof setTimeout>) => voidTest seam: timer canceller, defaults to clearTimeoutTest seam: timer canceller, defaults to clearTimeout.

TransitFeedAnswer

Interface

ts
interface TransitFeedAnswer

The counts of the last successful answer (0.22.1).

PropertyTypeDefaultDescription
countnumberrequiredVehicles in the answer (the gateway's count).
matchednumber | nullrequiredVehicles the gateway matched before its limit (matched), null when the answer omits it.
truncatedbooleanrequiredTrue when the answer was cut at the limit (truncated).
receivedAtnumberrequiredWhen the answer arrived, epoch milliseconds.

TransitFeedReport

Interface

ts
interface TransitFeedReport

What onFeedStatus reports after every poll (0.22.1: answer and error added).

PropertyTypeDefaultDescription
statusTransitFeedStatusrequiredThe gateway's freshness state, unchanged.
ageSnumber | nullrequiredSeconds since the feed's newest data, or null when unknown.
labelstringrequiredThe standard freshness label (transitFreshnessLabel).
answerTransitFeedAnswer | nullrequiredThe last successful answer's counts; null before the first answer.
errorbooleanrequiredTrue when the LAST poll failed (HTTP error or network); the drawn vehicles are the previous answer's and the label ages honestly.

TransitFix

Interface

ts
interface TransitFix

One reported position, ready to interpolate.

PropertyTypeDefaultDescription
idstringrequired
lngnumberrequired
latnumberrequired
bearingnumber | nullrequiredThe feed's heading, or null.
recordedAtMsnumberrequiredrecorded_at in epoch milliseconds.
vehicleTransitVehiclerequiredThe vehicle this fix belongs to, as the gateway described it.

TransitStopFeature

Interface

ts
interface TransitStopFeature

One clicked stop, as the tiles carry it.

PropertyTypeDefaultDescription
idstringrequiredNaPTAN ATCO code: pass it to GET /v1/transit/departures?stop=.
namestringrequired
indicator?stringnot stated
locality?stringnot stated
bearing?stringnot statedNaPTAN compass point the stop faces, e.g. NE.
linesstring[]requiredLine names the timetable has calling here.

TransitStopsLayerOptions

Interface

ts
interface TransitStopsLayerOptions

Options for TransitStopsLayer.

PropertyTypeDefaultDescription
stops?booleantrueDraw the stops. Default true.
lines?booleantrueDraw the lines. Default true.
slot?Slot"middle" (above roads, below labels)Where in the style the layers sit. Default "middle" (above roads, below labels).
onStopClick?(stop: TransitStopFeature, lngLat: { lng: number; lat: number; }) => voidnot statedCalled with the stop under a click.
source?"auto" | "api" | "tiles-host"not statedWhere the tiles come from. "auto" (default): the keyed tile API when the map has an apiKey (the tiles host refuses other sites' browser origins), else the tiles host. "api" or "tiles-host" force one.
tilesIndexUrl?stringTRANSIT_TILES_INDEX_URLThe tiles index to read. Default TRANSIT_TILES_INDEX_URL.
stopsUrl?stringnot statedArchive URLs to use instead of the index (a self-hosted copy): https://...pmtiles or pmtiles://https://....
linesUrl?stringnot stated
lineColour?stringnot statedLine colour where the timetable gives none.
stopColour?stringthe MapMap marker blueStop badge colour. Default the MapMap marker blue.
id?string"mapmap-transit"Id prefix for the sources and layers. Default "mapmap-transit".

TransitVehicle

Interface

ts
interface TransitVehicle

A vehicle as the gateway describes it (one feature's properties).

PropertyTypeDefaultDescription
idstringrequiredStable per vehicle: <operator>:<vehicle>.
vehiclestringrequiredThe operator's vehicle reference.
operatorstringrequiredNational Operator Code, e.g. TFLO.
linestring | nullrequiredRider-facing line name, e.g. 88.
direction"outbound" | "inbound" | nullrequiredoutbound, inbound or null.
originstring | nullrequired
destinationstring | nullrequired
bearingnumber | nullrequiredThe feed's heading in degrees, or null.
recordedAtstring | nullrequiredWhen the vehicle reported this position (RFC 3339), or null.
ageSnumber | nullrequiredAge of recordedAt when the gateway answered, seconds.
journeystring | nullrequiredThe feed's journey reference, or null.
vehicleType?BusVehicleType | nullnot statedThe body type the feed names (vehicle_type, or deck), or null/absent when it names none.
lngnumberrequiredReported position.
latnumberrequired

TransitVehiclesLayerOptions

Interface

ts
interface TransitVehiclesLayerOptions

Options for TransitVehiclesLayer.

PropertyTypeDefaultDescription
bbox?[number, number, number, number] | "viewport"not statedThe area to poll: a fixed [west, south, east, north], or "viewport" (default) for the area on screen, refetched when the map stops moving. Areas over the gateway's 4 square degree cap are shrunk around their centre.
operator?stringnot statedOnly this operator's vehicles (National Operator Code, e.g. TFLO).
line?stringnot statedOnly this line, as riders see it (e.g. 88).
pollMs?number30,000Poll interval in milliseconds. Default 30,000; at least 15,000.
renderBehindMs?numberpollMs: one poll behind, so there is always a newer fix to move towardsHow far behind the data to draw, milliseconds. Default pollMs: one poll behind, so there is always a newer fix to move towards.
icon?{ url: string; size?: number; } | "arrow"not statedVehicle marker: "arrow" (default, a heading arrow, a dot when the heading is unknown) or your own image, rotated to the heading.
marker?"arrow" | "bus"not statedHow a vehicle is drawn. "arrow" (default): the signal-blue heading arrow, as before. "bus": neutral ink (#0f1115, 1.5 px white halo), a 7 px dot z8 to 12, an 18 px puck with the line number and a heading tick z12 to 15.5, and a top-down bus rotated to the heading from z15.5 (32 px, four times that by z20) with an upright line label. A vehicle whose position is over 90 s behind the feed's newest draws at 50 %. A custom icon image still wins when set.
defaultVehicleType?BusVehicleType"generic": a deliberately neutral bus, so an unknown vehicle is never drawn as a type it may not beWhat a bus is drawn as (the marker: "bus" sprite, and the 3D layer) when the feed names no body type (vehicle_type, or deck). Default "generic": a deliberately neutral bus, so an unknown vehicle is never drawn as a type it may not be.
slot?TransitSlot"top" (above POI labels, below place names)Where in the style the layer sits. Default "top" (above POI labels, below place names).
popup?(vehicle: TransitVehicle) => string | HTMLElementnot statedA popup for a clicked vehicle: HTML string or element. Omit for none.
onFeedStatus?(report: TransitFeedReport) => voidnot statedCalled after every poll with the feed's freshness, its label, the last answer's counts and whether this poll failed.
id?string"mapmap-transit-vehicles"Id prefix for the source and layers. Default "mapmap-transit-vehicles".
limit?numberthe gateway's default (2,000)Most vehicles per poll (gateway limit, 1 to 5,000). Default: the gateway's default (2,000).

TruckParams

Interface

ts
interface TruckParams

Truck / ADR vehicle parameters forwarded to the gateway's OSRM truck vendor extensions. All optional; only truck-profile requests honour them.

PropertyTypeDefaultDescription
heightM?numbernot statedVehicle height, metres.
widthM?numbernot statedVehicle width, metres.
lengthM?numbernot statedVehicle length, metres.
weightT?numbernot statedGross weight, tonnes.
hazmat?booleannot statedCarrying dangerous goods (ADR).
tunnelCode?stringnot statedADR 8.6.4 tunnel restriction code, e.g. "C" or "B/D". The slash is URL-encoded automatically.

UploadProbeOptions

Interface

ts
interface UploadProbeOptions

Options for uploadProbeBatch. All optional.

PropertyTypeDefaultDescription
fetch?typeof fetchthe globalInjectable fetch (defaults to the global).
maxAttempts?number4Total attempts including the first (default 4).
backoffMs?(attempt: number) => numberattempt*1000Attempt number → delay before the next try, ms (default attempt*1000).
sleep?(ms: number) => Promise<void>setTimeoutInjectable delay, for deterministic tests (default setTimeout).
signal?AbortSignalnot statedAbort signal forwarded to fetch. Once it has aborted the retry loop stops immediately (an abort is a caller decision, not a transient failure) and the upload resolves "gaveUp".

VoiceGuidanceOptions

Interface

ts
interface VoiceGuidanceOptions

Options for VoiceGuidance.

PropertyTypeDefaultDescription
lang?stringnot statedBCP 47 language for utterances, e.g. en-GB. An update's voiceLocale takes precedence when present.
rate?numbernot statedBase speech rate (0.1–10, default 1). Critical prompts speak slightly faster than this base.
volume?number1Volume for speech and earcons, 0–1 (default 1).
muted?booleannot statedStart muted.
earcons?Partial<Record<GuidanceSeverity, string>>not statedSeverity → earcon audio URL. Absent entries play nothing.

VoiceGuidanceUpdate

Interface

ts
interface VoiceGuidanceUpdate

The subset of a core guidance update that VoiceGuidance reads.

PropertyTypeDefaultDescription
state"navigating" | "arrived" | "offRoute"requiredGuidance state, as emitted by the wasm GuidanceSession.
spoken?GuidanceSpokenPrompt | nullnot statedSpoken prompt currently due (repeated until superseded).
severity?GuidanceSeverityinfoUrgency of the current step's instruction (default info).
voiceLocale?stringnot statedBCP 47 locale of the instruction text, when the payload carries one.

VoiceInstruction

Interface

ts
interface VoiceInstruction

A spoken instruction with its trigger distance before the maneuver.

PropertyTypeDefaultDescription
distanceAlongGeometrynumberrequiredMetres before the end of the step at which to announce.
announcementstringrequiredPlain text for speech synthesis.
ssmlAnnouncement?stringnot statedSSML form, preferred by engines that support it.

Types (@mapmap/maps)

AdrTunnelCategory, AttributionPosition, BusVehicleType, ClipType, CreditTier, DataLayerMode, DiagnosticIssue, DirectionIconName, FeaturesetId, FixSet, GeocodeKind, GuidanceSeverity, InteractionType, LngLatLike, LogoPosition, LutBytes, MapBrandTheme, MapDisplayMode, MapMapBaseGroup, MapMapBaseId, MapMapTheme, MarkerGlyphId, MarkerSize, NavAlertAudioMode, NavAlertChipPosition, NavAlertIconSet, NavAlertLeadDistance, NavAlertMode, NavAlertSound, NavCameraKind, NavigationCameraMode, PlacesInput, PlaceWithDistance, PlaceWithDriveTime, ProbeUploadOutcome, ProjectionUniform, ProjectionVariant, ProtocolHost, ReachabilityMode, RouteEffectName, RouteProfile, SearchBoxBias, SearchBoxSelectListener, Slot, SunTimes, ThemeSource, TransitDrawnVehicle, TransitFeedStatus, TransitSlot, UseTheme, Vec3

AdrTunnelCategory

Type

ts
type AdrTunnelCategory = "A" | "B" | "C" | "D" | "E";

The ADR category of a tunnel, "A" (least restrictive) … "E".

AttributionPosition

Type

ts
type AttributionPosition = "bottom-left" | "bottom-right" | "top-left" | "top-right";

Map corners an enforced control (attribution, mark) can be mounted in.

BusVehicleType

Type

ts
type BusVehicleType = "generic" | "double" | "single" | "mini";

A bus body type: "generic" (a deliberately neutral bus of single-deck proportions, for a vehicle whose body type is not known), "double" (double-decker), "single" (single-decker), "mini" (midi or minibus).

ClipType

Type

ts
type ClipType = keyof typeof CLIP_TARGETS;

CreditTier

Type

ts
type CreditTier = "full" | "short" | "osm-and-more";

Which line a credit shows (0.22.1). "full": the whole wording, fitted to one line at 5px or more. "short": each source's own short credit plus the (i), fitted the same way and never under 6px. "osm-and-more": when even the short line would need less than 5px, the OpenStreetMap credit verbatim followed by the other sources' names, as many as fit at 5px or more, then " and <n> more" for the rest, plus the (i). No line is ever set under infoBelow; every source's whole wording is in the panel.

DataLayerMode

Type

ts
type DataLayerMode = "auto" | "point" | "line" | "polygon" | "cluster" | "heatmap" | "extrusion";

How a DataLayer draws its features.

DiagnosticIssue

Type

ts
type DiagnosticIssue = "container-zero-height" | "container-detached" | "duplicate-maplibre" | "webgl-unavailable" | "invalid-api-key" | "basemap-not-found" | "basemap-forbidden";

The distinct issues the diagnostics can report.

DirectionIconName

Type · also exported from @mapmap/maps/direction-icons

ts
type DirectionIconName = keyof typeof directionIcons;

A valid icon name (turn_left, roundabout_right, ferry, ...).

FeaturesetId

Type

ts
type FeaturesetId = "poi" | "place-labels" | "buildings";

A named group of basemap layers, as in Mapbox Standard featuresets.

FixSet

Type

ts
type FixSet = ReadonlyMap<string, TransitFix>;

One poll's fixes, by vehicle id.

GeocodeKind

Type

ts
type GeocodeKind = "address" | "street" | "locality" | "poi" | "postcode";

The document kinds the reverse endpoint can filter by.

GuidanceSeverity

Type

ts
type GuidanceSeverity = "info" | "warning" | "critical";

Instruction urgency, as emitted by the core (InstructionSeverity).

InteractionType

Type

ts
type InteractionType = "click" | "mouseenter" | "mouseleave" | "mousemove";

The mouse events an interaction can listen for.

LngLatLike

Type

ts
type LngLatLike = [number, number] | {
    lng: number;
    lat: number;
} | {
    lon: number;
    lat: number;
};

A longitude/latitude pair, accepted in the three common shapes.

LogoPosition

Type

ts
type LogoPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";

Corner positions accepted by the logo control.

LutBytes

Type

ts
type LutBytes = Uint8Array;

A colour-theme LUT: exactly LUT_BYTES bytes, layout as above.

MapBrandTheme

Type

ts
type MapBrandTheme = "day" | "night";

Day (dark ink on light maps) or Night (white on dark maps).

MapDisplayMode

Type

ts
type MapDisplayMode = "browse" | "navigating";

Whether the map is being browsed or actively navigated.

MapMapBaseGroup

Type

ts
type MapMapBaseGroup = "base" | "designed";

Which half of the catalogue an entry belongs to.

MapMapBaseId

Type

ts
type MapMapBaseId = "light" | "dark" | "streets" | "midnight" | "navigator-day" | "navigator-night" | "fleet" | "outdoor" | "dataviz" | "backdrop" | "print";

Every first-party base id.

MapMapTheme

Type

ts
type MapMapTheme = "light" | "dark";

Which built-in palette a theme starts from.

MarkerGlyphId

Type

ts
type MarkerGlyphId = (typeof MARKER_GLYPH_IDS)[number];

One marker glyph id ("pin", "star", "fuel", ...).

MarkerSize

Type

ts
type MarkerSize = "s" | "m" | "l";

One marker size preset.

Type

ts
type NavAlertAudioMode = (typeof NAV_ALERT_AUDIO_MODES)[number];

One audio mode.

Type

ts
type NavAlertChipPosition = (typeof NAV_ALERT_CHIP_POSITIONS)[number];

One chip position slot.

Type

ts
type NavAlertIconSet = (typeof NAV_ALERT_ICON_SETS)[number];

One curated icon set. "brand" means "use my iconUrlOverrides".

Type

ts
type NavAlertLeadDistance = (typeof NAV_ALERT_LEAD_DISTANCES)[number];

One lead-distance preset.

Type

ts
type NavAlertMode = (typeof NAV_ALERT_MODES)[number];

One alert mode.

Type

ts
type NavAlertSound = (typeof NAV_ALERT_SOUNDS)[number];

One built-in earcon.

Type

ts
type NavCameraKind = (typeof NAV_CAMERA_KINDS)[number];

One safety-camera kind.

Type

ts
type NavigationCameraMode = "follow" | "overview" | "free";

The camera's current behaviour.

PlacesInput

Type

ts
type PlacesInput = Place[] | PlacesFeatureCollection;

Either input shape for PlacesLayer / setPlaces.

PlaceWithDistance

Type

ts
type PlaceWithDistance = Place & {
    distanceM: number;
};

A place with its straight-line distance attached (see nearest).

PropertyTypeDefaultDescription
distanceMnumberrequiredStraight-line (haversine) distance from the origin, metres.

PlaceWithDriveTime

Type

ts
type PlaceWithDriveTime = Place & {
    durationS: number;
    distanceM: number | null;
};

A place with gateway drive time attached (see nearestByDriveTime).

PropertyTypeDefaultDescription
durationSnumberrequiredDrive time from the origin, seconds.
distanceMnumber | nullrequiredDriven distance from the origin, metres (null when not returned).

ProbeUploadOutcome

Type

ts
type ProbeUploadOutcome = "accepted" | "refused" | "notEnabled" | "rejected" | "gaveUp";

The outcome of an upload attempt.

ProjectionUniform

Type

ts
type ProjectionUniform = (typeof PROJECTION_UNIFORMS)[number];

ProjectionVariant

Type

ts
type ProjectionVariant = "mercator" | "globe";

The shaderData.variantName values MapLibre has used from 5.6 to 6.11. Anything else is treated as "mercator" by projectionVariant, with one console warning.

ProtocolHost

Type

ts
type ProtocolHost = Pick<typeof maplibregl, "addProtocol">;

The part of a maplibre-gl module this SDK needs to install a protocol on. Structural on purpose: a MapLibre 5 host passes its default import and a MapLibre 6 host passes the namespace (6.x has no default export), and the two are different TypeScript types. Both carry addProtocol.

ReachabilityMode

Type

ts
type ReachabilityMode = "walk" | "cycle" | "drive" | "truck" | (string & {});

Travel mode for the rings. The friendly names map onto gateway costings (walk → pedestrian, cycle → bicycle, drive → auto); any other string is passed through as a raw Valhalla costing (e.g. "truck", "motor_scooter").

RouteEffectName

Type

ts
type RouteEffectName = "flow";

The names the effects registry knows. Grows as effects land.

RouteProfile

Type

ts
type RouteProfile = "driving" | "walking" | "truck" | (string & {});

OSRM routing profile. MapMap ships driving, walking and truck.

SearchBoxBias

Type

ts
type SearchBoxBias = "map-centre" | {
    lat: number;
    lon: number;
} | false;

Where a suggest request should bias its results.

SearchBoxSelectListener

Type

ts
type SearchBoxSelectListener = (event: SearchBoxSelectEvent) => void;

The listener signature for the "select" event.

Slot

Type

ts
type Slot = "bottom" | "middle" | "top";

A named insertion point in the MapMap layer stack.

SunTimes

Type

ts
type SunTimes = {
    sunrise: Date;
    sunset: Date;
} | "polarDay" | "polarNight";

Sun-times result: either both events, or a polar day/night marker.

ThemeSource

Type

ts
type ThemeSource = {
    type: "geojson";
    data: string;
    attribution?: string;
    maxzoom?: number;
    promoteId?: string;
    cluster?: boolean;
    clusterRadius?: number;
    clusterMaxZoom?: number;
} | {
    type: "vector";
    url?: string;
    tiles?: string[];
    minzoom?: number;
    maxzoom?: number;
    bounds?: [number, number, number, number];
    attribution?: string;
    promoteId?: string | Record<string, string>;
} | {
    type: "raster";
    url?: string;
    tiles?: string[];
    tileSize?: number;
    minzoom?: number;
    maxzoom?: number;
    bounds?: [number, number, number, number];
    attribution?: string;
} | {
    type: "image";
    url: string;
    coordinates: [
        [number, number],
        [number, number],
        [number, number],
        [number, number]
   ];
};

A customer-hosted source on a theme. MapMap stores the URL, never the data: the compiled style lists the source and the viewer's map fetches it directly. Every URL is https:// (or pmtiles://https:// for an archive url). Mirrors sn_style::ThemeSource.

TransitDrawnVehicle

Type

ts
type TransitDrawnVehicle = TransitVehicle & {
    stale: boolean;
    followed: boolean;
    drawAs: BusVehicleType;
    fade: number;
};

A vehicle as drawn, with the marker's per-vehicle state (TransitVehiclesLayer.onDraw).

PropertyTypeDefaultDescription
stalebooleanrequiredIts last fix is over 90 s behind the feed's newest.
followedbooleanrequiredIt is the vehicle passed to setFollowed.
drawAsBusVehicleTyperequiredThe body type it is drawn as: its feed type, else the layer's defaultVehicleType.
fadenumberrequired1 normally; below 1 while the vehicle fades out after leaving the feed.

TransitFeedStatus

Type

ts
type TransitFeedStatus = "ok" | "stale" | "unknown";

The gateway's freshness states for the feed.

TransitSlot

Type

ts
type TransitSlot = "bottom" | "middle" | "top";

Where in the style the layer sits (the SDK slot names).

UseTheme

Type

ts
type UseTheme = "default" | "none";

LayerOverride.use_theme (Mapbox *-use-theme). Absent means "default".

Vec3

Type

ts
type Vec3 = [number, number, number];

Constants (@mapmap/maps)

ALERT_CONTRAST_MIN, BAKED_MARKERS_GLYPH_ID, BASE_ID_ALIASES, BODS_SHORT_CREDIT, BUS_DEFAULT_VEHICLE_TYPE, BUS_IMAGES, BUS_INK, BUS_RING_IMAGES, BUS_SPRITE_IMAGES, BUS_STALE_AFTER_S, BUS_VEHICLE_TYPES, CLIP_DEFAULT_MINZOOM, CLIP_MAX_VERTICES, CLIP_TARGETS, COLOUR_THEME_LAYER_ID, COLOUR_THEME_METADATA_KEY, DEFAULT_DEBOUNCE_MS, DEFAULT_GATEWAY_URL, DEFAULT_GLYPHS_URL, DEFAULT_MAX_MERCATOR_SEGMENT, DEFAULT_TERRAIN_ATTRIBUTION, DEFAULT_TERRAIN_URL, DEFAULT_TERRITORY_TILES_URL, directionIcons, EFFECTS_METADATA_KEY, FEATURESETS, FLOW_DEFAULTS, FULL_ATTRIBUTION, GLOBE_BLEND_GLSL, GLOBE_RADIUS_M, IDENTITY_LUT, KEYED_TILES_TERRITORY, LOGO_SVG, LUT_BYTES, LUT_SIZE, MAPMAP_BASES, MARKER_DEFAULT_COLOUR, MARKER_GLYPH_IDS, MARKER_GLYPH_VIEWBOX, MARKER_LABEL_TEXT_SIZES, MARKER_PIN_BODY_PATH, MARKER_SIZES, MARKER_SIZES_PX, markerGlyphPaths, MARKERS_ID, MAX_MARKER_ID_LENGTH, MAX_MARKER_IMAGE_BYTES, MAX_MARKER_ITEMS, MAX_MARKER_LABEL_LENGTH, MAX_MARKER_TEXT_LENGTH, MAX_PUCK_IMAGE_BYTES, MAX_THEME_GEOJSON_SOURCES, MAX_THEME_SOURCES, NAPTAN_SHORT_CREDIT, NAV_ALERT_AUDIO_MODES, NAV_ALERT_CHIP_POSITIONS, NAV_ALERT_ICON_SETS, NAV_ALERT_LEAD_DISTANCE_M, NAV_ALERT_LEAD_DISTANCES, NAV_ALERT_MODES, NAV_ALERT_SOUND_BASE_URL, NAV_ALERT_SOUND_FILES, NAV_ALERT_SOUNDS, NAV_CAMERA_DEFAULTS, NAV_CAMERA_KINDS, NO_ROADS_NEAR_ORIGIN, OPENMAPTILES_ATTRIBUTION, OSM_ATTRIBUTION, PALETTE_SLOTS, POI_CATEGORY_COLORS, POI_CATEGORY_IDS, POI_CLASS_CATEGORIES, PROJECTION_UNIFORMS, RIBBON_FLOATS_PER_VERTEX, ROUTE_EFFECTS, SIGNAL_BLUE, SLOT_ANCHORS, SLOTS, SOURCE_LAYERS, TRANSIT_LINE_FALLBACK_COLOUR, TRANSIT_TILES_INDEX_URL

ALERT_CONTRAST_MIN

Constant

ts
const ALERT_CONTRAST_MIN = 4.5;

Minimum acceptable contrast ratio for alert-chip text on its background.

BAKED_MARKERS_GLYPH_ID

Constant

ts
const BAKED_MARKERS_GLYPH_ID = "mm-user-markers-glyph";

The SECOND symbol layer a BAKED style carries, the glyph-and-label layer the theme compiler appends next to mm-user-markers when it translates extra.markers into style constructs (sn_style::MARKERS_GLYPH_LAYER_ID).

This layer is the reliable "already baked" signal: MarkersLayer never creates it, so finding it means the style itself is drawing the markers and a naive install would draw them TWICE.

BASE_ID_ALIASES

Constant

ts
const BASE_ID_ALIASES: Readonly<Record<string, MapMapBaseId>>;

Retired ids, mapped to the entry that replaced them. The Navigator pair shipped as "Calm Cab Day"/"Calm Cab Night"; the old ids are on disk in every document saved while those labels shipped, so baseTheme keeps resolving them. Mirrors sn_style::BASE_ID_ALIASES.

BODS_SHORT_CREDIT

Constant

ts
const BODS_SHORT_CREDIT = "Bus data: DfT Bus Open Data Service, OGL v3.0";

The short BODS credit the layer adds to the map's credit line. The full OGL wording is in every API answer's attribution and in THIRD-PARTY-NOTICES.md.

BUS_DEFAULT_VEHICLE_TYPE

Constant

ts
const BUS_DEFAULT_VEHICLE_TYPE: BusVehicleType;

What a vehicle with no sourced body type is drawn as, unless defaultVehicleType says otherwise.

BUS_IMAGES

Constant

ts
const BUS_IMAGES: {
    readonly puck: "mapmap-transit-bus-puck";
    readonly puckFollowed: "mapmap-transit-bus-puck-followed";
    readonly tick: "mapmap-transit-bus-tick";
    readonly sprite: "mapmap-transit-bus";
    readonly ring: "mapmap-transit-bus-ring";
    readonly spriteDouble: "mapmap-transit-bus-double";
    readonly ringDouble: "mapmap-transit-bus-double-ring";
    readonly spriteSingle: "mapmap-transit-bus-single";
    readonly ringSingle: "mapmap-transit-bus-single-ring";
    readonly spriteMini: "mapmap-transit-bus-mini";
    readonly ringMini: "mapmap-transit-bus-mini-ring";
};

Image ids the bus marker adds to the style (shared by every layer instance). sprite and ring are the generic bus (the default look); each body type has its own.

BUS_INK

Constant

ts
const BUS_INK = "#0f1115";

The bus marker's neutral ink.

BUS_RING_IMAGES

Constant

ts
const BUS_RING_IMAGES: Record<BusVehicleType, string>;

The followed ring's under-image id for each body type.

BUS_SPRITE_IMAGES

Constant

ts
const BUS_SPRITE_IMAGES: Record<BusVehicleType, string>;

The top-down sprite's image id for each body type.

BUS_STALE_AFTER_S

Constant

ts
const BUS_STALE_AFTER_S = 90;

A vehicle whose last fix is this far behind the feed's newest fix (recorded_at_max) reads stale (drawn at 50 %), seconds.

BUS_VEHICLE_TYPES

Constant

ts
const BUS_VEHICLE_TYPES: readonly BusVehicleType[];

Every BusVehicleType.

CLIP_DEFAULT_MINZOOM

Constant

ts
const CLIP_DEFAULT_MINZOOM = 13;

Default ClipOptions.minzoom: the street zooms where buildings draw.

CLIP_MAX_VERTICES

Constant

ts
const CLIP_MAX_VERTICES = 500;

The vertex cap for one clip polygon. The distance expression is evaluated for every feature in every tile the clipped layers draw, against every segment of the polygon, so its cost grows with both.

CLIP_TARGETS

Constant

ts
const CLIP_TARGETS: {
    readonly buildings: readonly ["building", "building-3d", "building-outline"];
    readonly symbols: readonly ["poi-labels", "housenumber"];
};

The MapMap skeleton layers each clip type hides (the compiled style's ids, CONTRACT.md 2.1). building-3d is the runtime extrusion setBuildings3d adds.

COLOUR_THEME_LAYER_ID

Constant

ts
const COLOUR_THEME_LAYER_ID = "mapmap-colour-theme";

The default layer id map.setColorTheme uses.

COLOUR_THEME_METADATA_KEY

Constant

ts
const COLOUR_THEME_METADATA_KEY = "mapmap:color-theme";

The compiled style's metadata key for the theme summary.

DEFAULT_DEBOUNCE_MS

Constant

ts
const DEFAULT_DEBOUNCE_MS = 250;

Default debounce between the last keystroke and the suggest request.

DEFAULT_GATEWAY_URL

Constant

ts
const DEFAULT_GATEWAY_URL = "https://api.mapmap.ai";

The MapMap gateway, the default for MapMapOptions.baseUrl.

DEFAULT_GLYPHS_URL

Constant

ts
const DEFAULT_GLYPHS_URL = "https://fonts.mapmap.ai/{fontstack}/{range}.pbf";

Default glyph endpoint (PBF fontstacks), mirroring sn_style::DEFAULT_GLYPHS_URL.

DEFAULT_MAX_MERCATOR_SEGMENT

Constant

ts
const DEFAULT_MAX_MERCATOR_SEGMENT: number;

Default subdivideMercator limit: 1/512 mercator units, about 78 km at the equator.

DEFAULT_TERRAIN_ATTRIBUTION

Constant

ts
const DEFAULT_TERRAIN_ATTRIBUTION: string;

DEFAULT_TERRAIN_URL

Constant

ts
const DEFAULT_TERRAIN_URL = "https://mapmap.ai/terrain/{z}/{x}/{y}.png";

DEFAULT_TERRITORY_TILES_URL

Constant

ts
const DEFAULT_TERRITORY_TILES_URL = "pmtiles://https://tiles.mapmap.ai/planet.pmtiles";

The keyless default territory tiles URL (overridable per map).

tiles.mapmap.ai serves this archive only to mapmap.ai, localhost, 127.0.0.1 and callers that send no Origin/Referer (QGIS, curl, a native app). A browser page on any other site gets a 403, so a style built with an API key reads the same archive through the keyed gateway instead: see keyedTilesUrl and territoryTilesSourceUrl.

directionIcons

Constant · also exported from @mapmap/maps/direction-icons

ts
const directionIcons: {
    readonly arrive: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M4.991 4.000C4.596 4.000 4.209 3.883 3.880 3.663C3.551 3.443 3.295 3.131 3.144 2.765C2.992 2.400 2.953 1.998 3.030 1.610C3.107 1.222 3.297 0.865 3.577 0.586C3.857 0.306 4.213 0.116 4.601 0.038C4.989 -0.039 5.391 0.001 5.757 0.152C6.122 0.304 6.435 0.560 6.654 0.889C6.874 1.218 6.991 1.604 6.991 2.000C6.991 2.530 6.781 3.039 6.406 3.414C6.031 3.789 5.522 4.000 4.991 4.000Z M9.904 12.351C9.904 12.351 5.001 6.008 5.001 6.008C5.001 6.008 0.097 12.351 0.097 12.351C0.041 12.415 0.007 12.495 0.001 12.580C-0.005 12.664 0.017 12.748 0.063 12.819C0.110 12.890 0.179 12.944 0.259 12.972C0.339 13.000 0.426 13.001 0.506 12.975C0.506 12.975 3.458 11.631 3.458 11.631C3.517 11.593 3.585 11.573 3.655 11.574C3.725 11.575 3.793 11.597 3.851 11.636C3.909 11.675 3.954 11.731 3.980 11.796C4.006 11.860 4.013 11.931 3.999 12.000C3.999 12.000 3.991 12.000 3.991 12.000C3.991 12.000 3.991 17.500 3.991 17.500C3.991 17.566 4.004 17.631 4.029 17.691C4.055 17.752 4.091 17.807 4.138 17.854C4.184 17.900 4.239 17.937 4.300 17.962C4.361 17.987 4.426 18.000 4.491 18.000C4.491 18.000 5.491 18.000 5.491 18.000C5.557 18.000 5.622 17.987 5.683 17.962C5.743 17.937 5.799 17.900 5.845 17.854C5.891 17.807 5.928 17.752 5.953 17.691C5.978 17.631 5.991 17.566 5.991 17.500C5.991 17.500 5.991 12.008 5.991 12.008C5.991 12.008 6.001 12.008 6.001 12.008C5.985 11.939 5.991 11.867 6.017 11.801C6.043 11.735 6.088 11.679 6.146 11.638C6.204 11.598 6.272 11.576 6.343 11.574C6.414 11.573 6.483 11.593 6.543 11.631C6.543 11.631 9.495 12.975 9.495 12.975C9.575 13.001 9.662 13.000 9.742 12.972C9.823 12.944 9.891 12.890 9.938 12.819C9.984 12.748 10.006 12.664 10.000 12.580C9.994 12.495 9.960 12.415 9.904 12.351Z\" fill=\"currentColor\" fill-rule=\"evenodd\" transform=\"translate(5.009 1)\"/></svg>";
    readonly arrive_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M2.000 6.955C1.604 6.955 1.218 6.837 0.889 6.618C0.560 6.398 0.304 6.086 0.152 5.720C0.001 5.355 -0.039 4.952 0.038 4.565C0.116 4.177 0.306 3.820 0.586 3.540C0.865 3.261 1.222 3.070 1.610 2.993C1.998 2.916 2.400 2.956 2.765 3.107C3.131 3.258 3.443 3.515 3.663 3.844C3.883 4.172 4.000 4.559 4.000 4.955C4.000 5.485 3.789 5.994 3.414 6.369C3.039 6.744 2.530 6.955 2.000 6.955Z M12.003 5.991C13.070 6.010 14.087 6.447 14.833 7.210C15.580 7.972 15.996 8.998 15.992 10.065C15.992 10.065 16.000 10.065 16.000 10.065C16.000 10.065 16.000 11.442 16.000 11.442C16.000 11.510 16.013 11.576 16.039 11.638C16.065 11.701 16.102 11.757 16.150 11.805C16.198 11.852 16.254 11.890 16.316 11.916C16.378 11.941 16.445 11.955 16.512 11.955C16.512 11.955 17.488 11.955 17.488 11.955C17.555 11.955 17.622 11.941 17.684 11.916C17.746 11.890 17.802 11.852 17.850 11.805C17.898 11.757 17.935 11.701 17.961 11.638C17.987 11.576 18.000 11.510 18.000 11.442C18.000 11.442 18.000 9.955 18.000 9.955C18.000 9.955 17.986 9.955 17.986 9.955C17.962 8.377 17.323 6.871 16.206 5.758C15.088 4.644 13.580 4.010 12.003 3.991C12.003 3.991 11.992 3.990 11.992 3.990C11.992 3.990 11.992 4.010 11.992 4.010C11.992 4.010 11.000 4.010 11.000 4.010C11.000 4.010 11.000 4.001 11.000 4.001C10.931 4.016 10.859 4.010 10.793 3.984C10.727 3.958 10.670 3.914 10.630 3.855C10.590 3.797 10.567 3.729 10.566 3.658C10.565 3.587 10.584 3.518 10.623 3.458C10.623 3.458 11.966 0.506 11.966 0.506C11.993 0.426 11.992 0.339 11.964 0.259C11.935 0.179 11.882 0.110 11.811 0.063C11.740 0.017 11.656 -0.005 11.571 0.001C11.487 0.007 11.406 0.041 11.343 0.097C11.343 0.097 5.000 5.001 5.000 5.001C5.000 5.001 11.343 9.904 11.343 9.904C11.406 9.960 11.487 9.994 11.571 10.000C11.656 10.006 11.740 9.984 11.811 9.938C11.882 9.891 11.935 9.823 11.964 9.743C11.992 9.662 11.993 9.575 11.966 9.495C11.966 9.495 10.623 6.543 10.623 6.543C10.584 6.483 10.565 6.414 10.566 6.343C10.567 6.272 10.590 6.204 10.630 6.146C10.670 6.088 10.727 6.043 10.793 6.017C10.859 5.991 10.931 5.985 11.000 6.001C11.000 6.001 11.000 6.010 11.000 6.010C11.000 6.010 12.000 6.010 12.000 6.010Z\" fill=\"currentColor\" fill-rule=\"evenodd\" transform=\"translate(1 5.045)\"/></svg>";
    readonly arrive_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M14.000 4.955C14.000 4.559 14.117 4.172 14.337 3.844C14.557 3.515 14.869 3.258 15.235 3.107C15.600 2.956 16.002 2.916 16.390 2.993C16.778 3.070 17.135 3.261 17.414 3.540C17.694 3.820 17.884 4.177 17.962 4.565C18.039 4.952 17.999 5.355 17.848 5.720C17.696 6.086 17.440 6.398 17.111 6.618C16.782 6.837 16.396 6.955 16.000 6.955C15.470 6.955 14.961 6.744 14.586 6.369C14.211 5.994 14.000 5.485 14.000 4.955Z M6.000 6.010C6.000 6.010 7.000 6.010 7.000 6.010C7.000 6.010 7.000 6.001 7.000 6.001C7.069 5.985 7.141 5.991 7.207 6.017C7.273 6.043 7.330 6.088 7.370 6.146C7.410 6.204 7.433 6.272 7.434 6.343C7.435 6.414 7.416 6.483 7.377 6.543C7.377 6.543 6.034 9.495 6.034 9.495C6.007 9.575 6.008 9.662 6.036 9.743C6.065 9.823 6.118 9.891 6.189 9.938C6.260 9.984 6.344 10.006 6.429 10.000C6.513 9.994 6.594 9.960 6.657 9.904C6.657 9.904 13.000 5.001 13.000 5.001C13.000 5.001 6.657 0.097 6.657 0.097C6.594 0.041 6.513 0.007 6.429 0.001C6.344 -0.005 6.260 0.017 6.189 0.063C6.118 0.110 6.065 0.179 6.036 0.259C6.008 0.339 6.007 0.426 6.034 0.506C6.034 0.506 7.377 3.458 7.377 3.458C7.416 3.518 7.435 3.587 7.434 3.658C7.433 3.729 7.410 3.797 7.370 3.855C7.330 3.914 7.273 3.958 7.207 3.984C7.141 4.010 7.069 4.016 7.000 4.001C7.000 4.001 7.000 4.010 7.000 4.010C7.000 4.010 6.008 4.010 6.008 4.010C6.008 4.010 6.008 3.990 6.008 3.990C6.008 3.990 5.997 3.991 5.997 3.991C4.420 4.010 2.912 4.644 1.794 5.758C0.677 6.871 0.038 8.377 0.014 9.955C0.014 9.955 0.000 9.955 0.000 9.955C0.000 9.955 0.000 11.442 0.000 11.442C-0.000 11.510 0.013 11.576 0.039 11.638C0.065 11.701 0.102 11.757 0.150 11.805C0.198 11.852 0.254 11.890 0.316 11.916C0.378 11.941 0.445 11.955 0.512 11.955C0.512 11.955 1.488 11.955 1.488 11.955C1.555 11.955 1.622 11.941 1.684 11.916C1.746 11.890 1.802 11.852 1.850 11.805C1.898 11.757 1.935 11.701 1.961 11.638C1.987 11.576 2.000 11.510 2.000 11.442C2.000 11.442 2.000 10.065 2.000 10.065C2.000 10.065 2.008 10.065 2.008 10.065C2.004 8.998 2.420 7.972 3.167 7.210C3.913 6.447 4.930 6.010 5.997 5.991Z\" fill=\"currentColor\" fill-rule=\"evenodd\" transform=\"translate(1 5.045)\"/></svg>";
    readonly arrive_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M4.991 4.000C4.596 4.000 4.209 3.883 3.880 3.663C3.551 3.443 3.295 3.131 3.144 2.765C2.992 2.400 2.953 1.998 3.030 1.610C3.107 1.222 3.297 0.865 3.577 0.586C3.857 0.306 4.213 0.116 4.601 0.038C4.989 -0.039 5.391 0.001 5.757 0.152C6.122 0.304 6.435 0.560 6.654 0.889C6.874 1.218 6.991 1.604 6.991 2.000C6.991 2.530 6.781 3.039 6.406 3.414C6.031 3.789 5.522 4.000 4.991 4.000Z M9.904 12.351C9.904 12.351 5.001 6.008 5.001 6.008C5.001 6.008 0.097 12.351 0.097 12.351C0.041 12.415 0.007 12.495 0.001 12.580C-0.005 12.664 0.017 12.748 0.063 12.819C0.110 12.890 0.179 12.944 0.259 12.972C0.339 13.000 0.426 13.001 0.506 12.975C0.506 12.975 3.458 11.631 3.458 11.631C3.517 11.593 3.585 11.573 3.655 11.574C3.725 11.575 3.793 11.597 3.851 11.636C3.909 11.675 3.954 11.731 3.980 11.796C4.006 11.860 4.013 11.931 3.999 12.000C3.999 12.000 3.991 12.000 3.991 12.000C3.991 12.000 3.991 17.500 3.991 17.500C3.991 17.566 4.004 17.631 4.029 17.691C4.055 17.752 4.091 17.807 4.138 17.854C4.184 17.900 4.239 17.937 4.300 17.962C4.361 17.987 4.426 18.000 4.491 18.000C4.491 18.000 5.491 18.000 5.491 18.000C5.557 18.000 5.622 17.987 5.683 17.962C5.743 17.937 5.799 17.900 5.845 17.854C5.891 17.807 5.928 17.752 5.953 17.691C5.978 17.631 5.991 17.566 5.991 17.500C5.991 17.500 5.991 12.008 5.991 12.008C5.991 12.008 6.001 12.008 6.001 12.008C5.985 11.939 5.991 11.867 6.017 11.801C6.043 11.735 6.088 11.679 6.146 11.638C6.204 11.598 6.272 11.576 6.343 11.574C6.414 11.573 6.483 11.593 6.543 11.631C6.543 11.631 9.495 12.975 9.495 12.975C9.575 13.001 9.662 13.000 9.742 12.972C9.823 12.944 9.891 12.890 9.938 12.819C9.984 12.748 10.006 12.664 10.000 12.580C9.994 12.495 9.960 12.415 9.904 12.351Z\" fill=\"currentColor\" fill-rule=\"evenodd\" transform=\"translate(5.009 1)\"/></svg>";
    readonly close: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M14.857 1.560C14.857 1.560 9.267 7.150 9.267 7.150C9.173 7.243 9.121 7.369 9.121 7.501C9.121 7.633 9.173 7.759 9.267 7.853C9.267 7.853 14.857 13.443 14.857 13.443C14.950 13.536 15.002 13.662 15.002 13.794C15.002 13.926 14.950 14.052 14.857 14.146C14.857 14.146 14.146 14.857 14.146 14.857C14.052 14.950 13.926 15.002 13.794 15.002C13.662 15.002 13.536 14.950 13.443 14.857C13.443 14.857 7.853 9.267 7.853 9.267C7.759 9.173 7.633 9.121 7.501 9.121C7.369 9.121 7.243 9.173 7.150 9.267C7.150 9.267 1.560 14.857 1.560 14.857C1.466 14.950 1.340 15.002 1.208 15.002C1.076 15.002 0.950 14.950 0.857 14.857C0.857 14.857 0.146 14.146 0.146 14.146C0.052 14.052 0.000 13.926 0.000 13.794C0.000 13.662 0.052 13.536 0.146 13.443C0.146 13.443 5.736 7.853 5.736 7.853C5.829 7.759 5.881 7.633 5.881 7.501C5.881 7.369 5.829 7.243 5.736 7.150C5.736 7.150 0.146 1.560 0.146 1.560C0.052 1.466 0.000 1.340 0.000 1.208C-0.000 1.076 0.052 0.950 0.146 0.857C0.146 0.857 0.857 0.146 0.857 0.146C0.950 0.052 1.076 0.000 1.208 0.000C1.340 0.000 1.466 0.052 1.560 0.146C1.560 0.146 7.150 5.736 7.150 5.736C7.243 5.829 7.369 5.881 7.501 5.881C7.633 5.881 7.759 5.829 7.853 5.736C7.853 5.736 13.443 0.146 13.443 0.146C13.536 0.052 13.662 -0.000 13.794 0.000C13.926 -0.000 14.052 0.052 14.146 0.146C14.146 0.146 14.857 0.857 14.857 0.857C14.903 0.903 14.939 0.958 14.964 1.018C14.989 1.078 15.002 1.143 15.002 1.208C15.002 1.273 14.989 1.338 14.964 1.398C14.939 1.459 14.903 1.513 14.857 1.560Z\" fill=\"currentColor\" transform=\"translate(2.499 2.499)\"/></svg>";
    readonly continue: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.495 6.966C9.495 6.966 6.543 5.623 6.543 5.623C6.483 5.584 6.414 5.565 6.343 5.566C6.272 5.567 6.204 5.590 6.146 5.630C6.088 5.670 6.043 5.727 6.017 5.793C5.991 5.859 5.985 5.931 6.001 6.000C6.001 6.000 6.001 15.497 6.001 15.497C6.001 15.563 5.988 15.628 5.962 15.689C5.937 15.750 5.900 15.806 5.853 15.853C5.806 15.899 5.751 15.936 5.690 15.962C5.629 15.987 5.563 16.000 5.497 16.000C5.497 16.000 4.504 16.000 4.504 16.000C4.438 16.000 4.372 15.987 4.311 15.962C4.250 15.936 4.195 15.899 4.148 15.853C4.101 15.806 4.064 15.750 4.039 15.689C4.014 15.628 4.001 15.563 4.001 15.497C4.001 15.497 4.001 6.000 4.001 6.000C4.016 5.931 4.010 5.859 3.984 5.793C3.958 5.727 3.914 5.670 3.856 5.630C3.797 5.590 3.729 5.567 3.658 5.566C3.587 5.565 3.518 5.584 3.458 5.623C3.458 5.623 0.506 6.966 0.506 6.966C0.426 6.993 0.339 6.992 0.259 6.964C0.179 6.935 0.110 6.882 0.063 6.811C0.017 6.740 -0.005 6.656 0.001 6.571C0.007 6.487 0.041 6.406 0.097 6.343C0.097 6.343 5.001 0.000 5.001 0.000C5.001 0.000 9.904 6.343 9.904 6.343C9.960 6.406 9.994 6.487 10.000 6.571C10.006 6.656 9.984 6.740 9.938 6.811C9.891 6.882 9.823 6.935 9.743 6.964C9.662 6.992 9.575 6.993 9.495 6.966Z\" fill=\"currentColor\" transform=\"translate(5.009 2)\"/></svg>";
    readonly continue_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M7.992 3.999C7.992 3.999 8.003 4.001 8.003 4.001C9.600 4.019 11.125 4.668 12.247 5.805C13.368 6.942 13.995 8.477 13.992 10.074C13.992 10.074 13.992 14.019 13.992 14.019C13.992 14.019 13.989 14.019 13.989 14.019C13.989 14.019 13.991 15.522 13.991 15.522C13.991 15.587 13.978 15.652 13.953 15.712C13.928 15.772 13.892 15.827 13.845 15.873C13.799 15.919 13.745 15.956 13.684 15.981C13.624 16.006 13.560 16.019 13.494 16.019C13.494 16.019 12.488 16.019 12.488 16.019C12.356 16.019 12.230 15.967 12.137 15.874C12.044 15.780 11.992 15.654 11.992 15.523C11.992 15.523 11.992 10.074 11.992 10.074C11.996 9.007 11.580 7.981 10.833 7.219C10.087 6.456 9.070 6.019 8.003 6.001C8.003 6.001 6.004 6.001 6.004 6.001C5.935 5.985 5.863 5.991 5.797 6.017C5.731 6.043 5.675 6.088 5.634 6.146C5.594 6.204 5.572 6.272 5.570 6.343C5.569 6.414 5.589 6.483 5.627 6.543C5.627 6.543 6.971 9.495 6.971 9.495C6.997 9.576 6.996 9.663 6.968 9.743C6.940 9.823 6.886 9.891 6.815 9.938C6.744 9.984 6.660 10.006 6.575 10.000C6.491 9.994 6.411 9.960 6.347 9.904C6.347 9.904 0.000 5.019 0.000 5.019C0.000 5.019 6.347 0.097 6.347 0.097C6.411 0.041 6.491 0.007 6.575 0.001C6.660 -0.005 6.744 0.017 6.815 0.063C6.886 0.110 6.940 0.179 6.968 0.259C6.996 0.339 6.997 0.426 6.971 0.506C6.971 0.506 5.627 3.458 5.627 3.458C5.589 3.518 5.569 3.587 5.570 3.658C5.572 3.729 5.594 3.797 5.634 3.855C5.675 3.914 5.731 3.958 5.797 3.984C5.863 4.010 5.935 4.016 6.004 4.001C6.004 4.001 7.992 4.001 7.992 4.001Z\" fill=\"currentColor\" transform=\"translate(2.008 1.981)\"/></svg>";
    readonly continue_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M5.989 6.001C4.922 6.019 3.905 6.456 3.159 7.219C2.412 7.981 1.996 9.007 2.000 10.074C2.000 10.074 2.000 15.523 2.000 15.523C2.000 15.654 1.948 15.780 1.855 15.874C1.762 15.967 1.635 16.019 1.504 16.019C1.504 16.019 0.497 16.019 0.497 16.019C0.432 16.019 0.368 16.006 0.307 15.981C0.247 15.956 0.192 15.919 0.146 15.873C0.100 15.827 0.064 15.772 0.039 15.712C0.014 15.652 0.001 15.587 0.001 15.522C0.001 15.522 0.003 14.019 0.003 14.019C0.003 14.019 0.000 14.019 0.000 14.019C0.000 14.019 0.000 10.074 0.000 10.074C-0.004 8.477 0.624 6.942 1.745 5.805C2.867 4.668 4.392 4.019 5.989 4.001C5.989 4.001 6.000 3.999 6.000 3.999C6.000 3.999 6.000 4.001 6.000 4.001C6.000 4.001 7.988 4.001 7.988 4.001C8.057 4.016 8.129 4.010 8.195 3.984C8.260 3.958 8.317 3.914 8.358 3.855C8.398 3.797 8.420 3.729 8.422 3.658C8.423 3.587 8.403 3.518 8.365 3.458C8.365 3.458 7.021 0.506 7.021 0.506C6.995 0.426 6.996 0.339 7.024 0.259C7.052 0.179 7.106 0.110 7.177 0.063C7.247 0.017 7.332 -0.005 7.416 0.001C7.501 0.007 7.581 0.041 7.645 0.097C7.645 0.097 13.992 5.019 13.992 5.019C13.992 5.019 7.645 9.904 7.645 9.904C7.581 9.960 7.501 9.994 7.416 10.000C7.332 10.006 7.247 9.984 7.177 9.938C7.106 9.891 7.052 9.823 7.024 9.743C6.996 9.663 6.995 9.576 7.021 9.495C7.021 9.495 8.365 6.543 8.365 6.543C8.403 6.483 8.423 6.414 8.422 6.343C8.420 6.272 8.398 6.204 8.358 6.146C8.317 6.088 8.260 6.043 8.195 6.017C8.129 5.991 8.057 5.985 7.988 6.001C7.988 6.001 5.989 6.001 5.989 6.001Z\" fill=\"currentColor\" transform=\"translate(4 1.981)\"/></svg>";
    readonly continue_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.986 11.043C9.986 11.043 9.986 14.504 9.986 14.504C9.986 14.635 9.934 14.762 9.841 14.855C9.748 14.948 9.621 15.000 9.490 15.000C9.490 15.000 8.483 15.000 8.483 15.000C8.418 15.000 8.353 14.987 8.293 14.962C8.233 14.937 8.178 14.901 8.132 14.854C8.086 14.808 8.050 14.754 8.025 14.693C8.000 14.633 7.987 14.568 7.987 14.503C7.987 14.503 7.992 10.896 7.992 10.896C8.038 10.125 7.913 9.353 7.625 8.636C7.337 7.920 6.894 7.276 6.327 6.752C6.327 6.752 3.879 4.686 3.879 4.686C3.836 4.629 3.778 4.586 3.711 4.563C3.645 4.539 3.572 4.536 3.504 4.553C3.435 4.571 3.373 4.608 3.326 4.660C3.279 4.713 3.248 4.778 3.238 4.849C3.238 4.849 2.320 7.959 2.320 7.959C2.287 8.037 2.229 8.102 2.155 8.144C2.082 8.186 1.996 8.203 1.912 8.192C1.828 8.181 1.750 8.142 1.690 8.082C1.630 8.022 1.592 7.944 1.580 7.860C1.580 7.860 0.000 0.000 0.000 0.000C0.000 0.000 8.005 0.450 8.005 0.450C8.090 0.449 8.172 0.476 8.240 0.527C8.308 0.578 8.357 0.649 8.380 0.731C8.403 0.813 8.399 0.900 8.368 0.978C8.337 1.057 8.280 1.124 8.208 1.167C8.208 1.167 5.259 2.518 5.259 2.518C5.191 2.538 5.130 2.577 5.085 2.631C5.040 2.686 5.012 2.752 5.004 2.823C4.997 2.893 5.010 2.964 5.043 3.027C5.076 3.089 5.126 3.141 5.189 3.175C5.189 3.175 7.646 5.249 7.646 5.249C8.443 5.979 9.067 6.878 9.472 7.881C9.877 8.883 10.053 9.964 9.986 11.043Z\" fill=\"currentColor\" transform=\"translate(5 3)\"/></svg>";
    readonly continue_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M2.354 5.249C2.354 5.249 4.811 3.175 4.811 3.175C4.873 3.141 4.924 3.089 4.957 3.027C4.990 2.964 5.003 2.893 4.996 2.823C4.988 2.752 4.960 2.686 4.915 2.631C4.869 2.577 4.809 2.538 4.741 2.518C4.741 2.518 1.792 1.167 1.792 1.167C1.719 1.124 1.663 1.057 1.632 0.978C1.601 0.900 1.596 0.813 1.619 0.731C1.642 0.649 1.692 0.578 1.760 0.527C1.827 0.476 1.910 0.449 1.995 0.450C1.995 0.450 10.000 0.000 10.000 0.000C10.000 0.000 8.419 7.860 8.419 7.860C8.408 7.944 8.369 8.022 8.309 8.082C8.249 8.142 8.171 8.181 8.087 8.192C8.003 8.203 7.918 8.186 7.844 8.144C7.771 8.102 7.713 8.037 7.680 7.959C7.680 7.959 6.762 4.849 6.762 4.849C6.752 4.778 6.721 4.713 6.674 4.660C6.626 4.608 6.564 4.571 6.496 4.553C6.427 4.536 6.355 4.539 6.288 4.563C6.222 4.586 6.163 4.629 6.121 4.686C6.121 4.686 3.673 6.751 3.673 6.751C3.106 7.276 2.663 7.920 2.375 8.636C2.087 9.353 1.962 10.125 2.008 10.895C2.008 10.895 2.013 14.503 2.013 14.503C2.013 14.568 2.000 14.633 1.975 14.693C1.950 14.754 1.914 14.808 1.868 14.854C1.821 14.901 1.767 14.937 1.707 14.962C1.646 14.987 1.582 15.000 1.516 15.000C1.516 15.000 0.510 15.000 0.510 15.000C0.378 15.000 0.252 14.948 0.159 14.855C0.066 14.762 0.014 14.635 0.014 14.504C0.014 14.504 0.014 11.043 0.014 11.043C-0.053 9.964 0.123 8.883 0.528 7.881C0.932 6.878 1.556 5.979 2.354 5.249Z\" fill=\"currentColor\" transform=\"translate(5 3)\"/></svg>";
    readonly continue_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.495 6.966C9.495 6.966 6.543 5.623 6.543 5.623C6.483 5.584 6.414 5.565 6.343 5.566C6.272 5.567 6.204 5.590 6.146 5.630C6.088 5.670 6.043 5.727 6.017 5.793C5.991 5.859 5.985 5.931 6.001 6.000C6.001 6.000 6.001 15.497 6.001 15.497C6.001 15.563 5.988 15.628 5.962 15.689C5.937 15.750 5.900 15.806 5.853 15.853C5.806 15.899 5.751 15.936 5.690 15.962C5.629 15.987 5.563 16.000 5.497 16.000C5.497 16.000 4.504 16.000 4.504 16.000C4.438 16.000 4.372 15.987 4.311 15.962C4.250 15.936 4.195 15.899 4.148 15.853C4.101 15.806 4.064 15.750 4.039 15.689C4.014 15.628 4.001 15.563 4.001 15.497C4.001 15.497 4.001 6.000 4.001 6.000C4.016 5.931 4.010 5.859 3.984 5.793C3.958 5.727 3.914 5.670 3.856 5.630C3.797 5.590 3.729 5.567 3.658 5.566C3.587 5.565 3.518 5.584 3.458 5.623C3.458 5.623 0.506 6.966 0.506 6.966C0.426 6.993 0.339 6.992 0.259 6.964C0.179 6.935 0.110 6.882 0.063 6.811C0.017 6.740 -0.005 6.656 0.001 6.571C0.007 6.487 0.041 6.406 0.097 6.343C0.097 6.343 5.001 0.000 5.001 0.000C5.001 0.000 9.904 6.343 9.904 6.343C9.960 6.406 9.994 6.487 10.000 6.571C10.006 6.656 9.984 6.740 9.938 6.811C9.891 6.882 9.823 6.935 9.743 6.964C9.662 6.992 9.575 6.993 9.495 6.966Z\" fill=\"currentColor\" transform=\"translate(5.009 2)\"/></svg>";
    readonly continue_uturn: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M15.010 5.500C15.010 5.500 15.010 14.997 15.010 14.997C15.010 15.063 14.997 15.128 14.971 15.189C14.946 15.250 14.909 15.306 14.862 15.353C14.815 15.399 14.760 15.436 14.699 15.462C14.638 15.487 14.572 15.500 14.506 15.500C14.506 15.500 13.513 15.500 13.513 15.500C13.447 15.500 13.382 15.487 13.321 15.462C13.259 15.436 13.204 15.399 13.157 15.353C13.110 15.306 13.073 15.250 13.048 15.189C13.023 15.128 13.010 15.063 13.010 14.997C13.010 14.997 13.010 5.500 13.010 5.500C13.010 4.572 12.641 3.682 11.985 3.025C11.328 2.369 10.438 2.000 9.510 2.000C8.581 2.000 7.691 2.369 7.035 3.025C6.378 3.682 6.010 4.572 6.010 5.500C6.010 5.500 6.010 9.500 6.010 9.500C6.010 9.500 6.001 9.500 6.001 9.500C5.985 9.569 5.991 9.641 6.017 9.707C6.043 9.773 6.088 9.830 6.146 9.870C6.204 9.910 6.272 9.933 6.343 9.934C6.414 9.935 6.483 9.916 6.543 9.877C6.543 9.877 9.495 8.534 9.495 8.534C9.575 8.507 9.663 8.508 9.743 8.536C9.823 8.565 9.891 8.618 9.938 8.689C9.984 8.760 10.006 8.844 10.000 8.929C9.994 9.013 9.960 9.094 9.904 9.157C9.904 9.157 5.001 15.500 5.001 15.500C5.001 15.500 0.097 9.157 0.097 9.157C0.041 9.094 0.007 9.013 0.001 8.929C-0.005 8.844 0.017 8.760 0.063 8.689C0.110 8.618 0.179 8.565 0.259 8.536C0.339 8.508 0.426 8.507 0.506 8.534C0.506 8.534 3.458 9.877 3.458 9.877C3.518 9.916 3.587 9.935 3.658 9.934C3.729 9.933 3.797 9.910 3.855 9.870C3.914 9.830 3.958 9.773 3.984 9.707C4.010 9.641 4.016 9.569 4.001 9.500C4.001 9.500 4.010 9.500 4.010 9.500C4.010 9.500 4.010 5.500 4.010 5.500C4.010 4.041 4.589 2.642 5.621 1.611C6.652 0.579 8.051 0.000 9.510 0.000C10.968 0.000 12.367 0.579 13.399 1.611C14.430 2.642 15.010 4.041 15.010 5.500Z\" fill=\"currentColor\" transform=\"translate(1.999 2.5)\"/></svg>";
    readonly depart: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M4.991 18.000C4.596 18.000 4.209 17.883 3.880 17.663C3.551 17.443 3.295 17.131 3.144 16.765C2.992 16.400 2.953 15.998 3.030 15.610C3.107 15.222 3.297 14.865 3.577 14.586C3.857 14.306 4.213 14.116 4.601 14.038C4.989 13.961 5.391 14.001 5.757 14.152C6.122 14.304 6.435 14.560 6.654 14.889C6.874 15.218 6.991 15.604 6.991 16.000C6.991 16.530 6.781 17.039 6.406 17.414C6.031 17.789 5.522 18.000 4.991 18.000Z M9.904 6.343C9.904 6.343 5.001 0.000 5.001 0.000C5.001 0.000 0.097 6.343 0.097 6.343C0.041 6.406 0.007 6.487 0.001 6.571C-0.005 6.656 0.017 6.740 0.063 6.811C0.110 6.882 0.179 6.935 0.259 6.964C0.339 6.992 0.426 6.993 0.506 6.966C0.506 6.966 3.458 5.623 3.458 5.623C3.517 5.585 3.585 5.565 3.655 5.566C3.725 5.567 3.793 5.588 3.851 5.628C3.909 5.667 3.954 5.723 3.980 5.787C4.006 5.852 4.013 5.923 3.999 5.992C3.999 5.992 3.991 5.992 3.991 5.992C3.991 5.992 3.991 11.492 3.991 11.492C3.991 11.557 4.004 11.622 4.029 11.683C4.055 11.744 4.091 11.799 4.138 11.845C4.184 11.892 4.239 11.929 4.300 11.954C4.361 11.979 4.426 11.992 4.491 11.992C4.491 11.992 5.491 11.992 5.491 11.992C5.557 11.992 5.622 11.979 5.683 11.954C5.743 11.929 5.799 11.892 5.845 11.845C5.891 11.799 5.928 11.744 5.953 11.683C5.978 11.622 5.991 11.557 5.991 11.492C5.991 11.492 5.991 6.000 5.991 6.000C5.991 6.000 6.001 6.000 6.001 6.000C5.985 5.931 5.991 5.859 6.017 5.793C6.043 5.727 6.088 5.670 6.146 5.630C6.204 5.590 6.272 5.567 6.343 5.566C6.414 5.565 6.483 5.584 6.543 5.623C6.543 5.623 9.495 6.966 9.495 6.966C9.575 6.993 9.662 6.992 9.743 6.964C9.823 6.935 9.891 6.882 9.938 6.811C9.984 6.740 10.006 6.656 10.000 6.571C9.994 6.487 9.960 6.406 9.904 6.343Z\" fill=\"currentColor\" fill-rule=\"evenodd\" transform=\"translate(4.99 1)\"/></svg>";
    readonly depart_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M12.000 16.955C11.604 16.955 11.218 16.837 10.889 16.618C10.560 16.398 10.304 16.086 10.152 15.720C10.001 15.355 9.961 14.952 10.038 14.565C10.116 14.177 10.306 13.820 10.586 13.540C10.865 13.261 11.222 13.070 11.610 12.993C11.998 12.916 12.400 12.956 12.765 13.107C13.131 13.258 13.443 13.515 13.663 13.844C13.883 14.172 14.000 14.559 14.000 14.955C14.000 15.485 13.789 15.994 13.414 16.369C13.039 16.744 12.530 16.955 12.000 16.955Z M7.003 5.991C8.070 6.010 9.087 6.447 9.833 7.210C10.580 7.972 10.996 8.998 10.992 10.065C10.992 10.065 11.000 10.065 11.000 10.065C11.000 10.065 11.000 11.442 11.000 11.442C11.000 11.510 11.013 11.576 11.039 11.638C11.065 11.701 11.102 11.757 11.150 11.805C11.198 11.852 11.254 11.890 11.316 11.916C11.378 11.941 11.445 11.955 11.512 11.955C11.512 11.955 12.488 11.955 12.488 11.955C12.555 11.955 12.622 11.941 12.684 11.916C12.746 11.890 12.802 11.852 12.850 11.805C12.898 11.757 12.935 11.701 12.961 11.638C12.987 11.576 13.000 11.510 13.000 11.442C13.000 11.442 13.000 9.955 13.000 9.955C13.000 9.955 12.986 9.955 12.986 9.955C12.962 8.377 12.323 6.871 11.206 5.758C10.088 4.644 8.580 4.010 7.003 3.991C7.003 3.991 6.992 3.990 6.992 3.990C6.992 3.990 6.992 4.010 6.992 4.010C6.992 4.010 6.000 4.010 6.000 4.010C6.000 4.010 6.000 4.001 6.000 4.001C5.931 4.016 5.859 4.010 5.793 3.984C5.727 3.958 5.670 3.914 5.630 3.855C5.590 3.797 5.567 3.729 5.566 3.658C5.565 3.587 5.584 3.518 5.623 3.458C5.623 3.458 6.966 0.506 6.966 0.506C6.993 0.426 6.992 0.339 6.964 0.259C6.935 0.179 6.882 0.110 6.811 0.063C6.740 0.017 6.656 -0.005 6.571 0.001C6.487 0.007 6.406 0.041 6.343 0.097C6.343 0.097 0.000 5.001 0.000 5.001C0.000 5.001 6.343 9.904 6.343 9.904C6.406 9.960 6.487 9.994 6.571 10.000C6.656 10.006 6.740 9.984 6.811 9.938C6.882 9.891 6.935 9.823 6.964 9.743C6.992 9.662 6.993 9.575 6.966 9.495C6.966 9.495 5.623 6.543 5.623 6.543C5.584 6.483 5.565 6.414 5.566 6.343C5.567 6.272 5.590 6.204 5.630 6.146C5.670 6.088 5.727 6.043 5.793 6.017C5.859 5.991 5.931 5.985 6.000 6.001C6.000 6.001 6.000 6.010 6.000 6.010C6.000 6.010 7.000 6.010 7.000 6.010Z\" fill=\"currentColor\" fill-rule=\"evenodd\" transform=\"translate(3 2.045)\"/></svg>";
    readonly depart_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M0.000 14.955C0.000 14.559 0.117 14.172 0.337 13.844C0.557 13.515 0.869 13.258 1.235 13.107C1.600 12.956 2.002 12.916 2.390 12.993C2.778 13.070 3.135 13.261 3.414 13.540C3.694 13.820 3.884 14.177 3.962 14.565C4.039 14.952 3.999 15.355 3.848 15.720C3.696 16.086 3.440 16.398 3.111 16.618C2.782 16.837 2.396 16.955 2.000 16.955C1.470 16.955 0.961 16.744 0.586 16.369C0.211 15.994 0.000 15.485 0.000 14.955Z M7.000 6.010C7.000 6.010 8.000 6.010 8.000 6.010C8.000 6.010 8.000 6.001 8.000 6.001C8.069 5.985 8.141 5.991 8.207 6.017C8.273 6.043 8.330 6.088 8.370 6.146C8.410 6.204 8.433 6.272 8.434 6.343C8.435 6.414 8.416 6.483 8.377 6.543C8.377 6.543 7.034 9.495 7.034 9.495C7.007 9.575 7.008 9.662 7.036 9.743C7.065 9.823 7.118 9.891 7.189 9.938C7.260 9.984 7.344 10.006 7.429 10.000C7.513 9.994 7.594 9.960 7.657 9.904C7.657 9.904 14.000 5.001 14.000 5.001C14.000 5.001 7.657 0.097 7.657 0.097C7.594 0.041 7.513 0.007 7.429 0.001C7.344 -0.005 7.260 0.017 7.189 0.063C7.118 0.110 7.065 0.179 7.036 0.259C7.008 0.339 7.007 0.426 7.034 0.506C7.034 0.506 8.377 3.458 8.377 3.458C8.416 3.518 8.435 3.587 8.434 3.658C8.433 3.729 8.410 3.797 8.370 3.855C8.330 3.914 8.273 3.958 8.207 3.984C8.141 4.010 8.069 4.016 8.000 4.001C8.000 4.001 8.000 4.010 8.000 4.010C8.000 4.010 7.008 4.010 7.008 4.010C7.008 4.010 7.008 3.990 7.008 3.990C7.008 3.990 6.997 3.991 6.997 3.991C5.420 4.010 3.912 4.644 2.794 5.758C1.677 6.871 1.038 8.377 1.014 9.955C1.014 9.955 1.000 9.955 1.000 9.955C1.000 9.955 1.000 11.442 1.000 11.442C1.000 11.510 1.013 11.576 1.039 11.638C1.065 11.701 1.102 11.757 1.150 11.805C1.198 11.852 1.254 11.890 1.316 11.916C1.378 11.941 1.445 11.955 1.512 11.955C1.512 11.955 2.488 11.955 2.488 11.955C2.555 11.955 2.622 11.941 2.684 11.916C2.746 11.890 2.802 11.852 2.850 11.805C2.898 11.757 2.935 11.701 2.961 11.638C2.987 11.576 3.000 11.510 3.000 11.442C3.000 11.442 3.000 10.065 3.000 10.065C3.000 10.065 3.008 10.065 3.008 10.065C3.004 8.998 3.420 7.972 4.167 7.210C4.913 6.447 5.930 6.010 6.997 5.991Z\" fill=\"currentColor\" fill-rule=\"evenodd\" transform=\"translate(3 2.045)\"/></svg>";
    readonly depart_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M4.991 18.000C4.596 18.000 4.209 17.883 3.880 17.663C3.551 17.443 3.295 17.131 3.144 16.765C2.992 16.400 2.953 15.998 3.030 15.610C3.107 15.222 3.297 14.865 3.577 14.586C3.857 14.306 4.213 14.116 4.601 14.038C4.989 13.961 5.391 14.001 5.757 14.152C6.122 14.304 6.435 14.560 6.654 14.889C6.874 15.218 6.991 15.604 6.991 16.000C6.991 16.530 6.781 17.039 6.406 17.414C6.031 17.789 5.522 18.000 4.991 18.000Z M9.904 6.343C9.904 6.343 5.001 0.000 5.001 0.000C5.001 0.000 0.097 6.343 0.097 6.343C0.041 6.406 0.007 6.487 0.001 6.571C-0.005 6.656 0.017 6.740 0.063 6.811C0.110 6.882 0.179 6.935 0.259 6.964C0.339 6.992 0.426 6.993 0.506 6.966C0.506 6.966 3.458 5.623 3.458 5.623C3.517 5.585 3.585 5.565 3.655 5.566C3.725 5.567 3.793 5.588 3.851 5.628C3.909 5.667 3.954 5.723 3.980 5.787C4.006 5.852 4.013 5.923 3.999 5.992C3.999 5.992 3.991 5.992 3.991 5.992C3.991 5.992 3.991 11.492 3.991 11.492C3.991 11.557 4.004 11.622 4.029 11.683C4.055 11.744 4.091 11.799 4.138 11.845C4.184 11.892 4.239 11.929 4.300 11.954C4.361 11.979 4.426 11.992 4.491 11.992C4.491 11.992 5.491 11.992 5.491 11.992C5.557 11.992 5.622 11.979 5.683 11.954C5.743 11.929 5.799 11.892 5.845 11.845C5.891 11.799 5.928 11.744 5.953 11.683C5.978 11.622 5.991 11.557 5.991 11.492C5.991 11.492 5.991 6.000 5.991 6.000C5.991 6.000 6.001 6.000 6.001 6.000C5.985 5.931 5.991 5.859 6.017 5.793C6.043 5.727 6.088 5.670 6.146 5.630C6.204 5.590 6.272 5.567 6.343 5.566C6.414 5.565 6.483 5.584 6.543 5.623C6.543 5.623 9.495 6.966 9.495 6.966C9.575 6.993 9.662 6.992 9.743 6.964C9.823 6.935 9.891 6.882 9.938 6.811C9.984 6.740 10.006 6.656 10.000 6.571C9.994 6.487 9.960 6.406 9.904 6.343Z\" fill=\"currentColor\" fill-rule=\"evenodd\" transform=\"translate(5.009 1)\"/></svg>";
    readonly end_of_road_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M14.495 4.019C14.495 4.019 4.992 4.019 4.992 4.019C4.992 4.019 4.992 6.019 4.992 6.019C4.992 6.019 14.495 6.019 14.495 6.019C14.560 6.019 14.625 6.006 14.685 5.981C14.745 5.956 14.800 5.920 14.846 5.873C14.892 5.827 14.929 5.773 14.954 5.712C14.979 5.652 14.992 5.588 14.992 5.522C14.992 5.522 14.992 4.515 14.992 4.515C14.992 4.450 14.979 4.386 14.954 4.325C14.929 4.265 14.892 4.210 14.846 4.164C14.800 4.118 14.745 4.082 14.685 4.057C14.625 4.032 14.560 4.019 14.495 4.019Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(2.008 1.981)\"/><path d=\"M7.992 4.001C7.992 4.001 6.004 4.001 6.004 4.001C5.935 4.016 5.863 4.010 5.797 3.984C5.731 3.958 5.675 3.914 5.634 3.855C5.594 3.797 5.572 3.729 5.570 3.658C5.569 3.587 5.589 3.518 5.627 3.458C5.627 3.458 6.971 0.506 6.971 0.506C6.997 0.426 6.996 0.339 6.968 0.259C6.940 0.179 6.886 0.110 6.815 0.063C6.744 0.017 6.660 -0.005 6.575 0.001C6.491 0.007 6.411 0.041 6.347 0.097C6.347 0.097 0.000 5.019 0.000 5.019C0.000 5.019 6.347 9.904 6.347 9.904C6.411 9.960 6.491 9.994 6.575 10.000C6.660 10.006 6.744 9.984 6.815 9.938C6.886 9.891 6.940 9.823 6.968 9.743C6.996 9.663 6.997 9.575 6.971 9.495C6.971 9.495 5.627 6.543 5.627 6.543C5.589 6.483 5.569 6.414 5.570 6.343C5.572 6.272 5.594 6.204 5.634 6.146C5.675 6.088 5.731 6.043 5.797 6.017C5.863 5.991 5.935 5.985 6.004 6.001C6.004 6.001 8.003 6.001 8.003 6.001C9.070 6.019 10.087 6.456 10.833 7.219C11.580 7.981 11.996 9.007 11.992 10.074C11.992 10.074 11.992 15.523 11.992 15.523C11.992 15.654 12.044 15.780 12.137 15.874C12.230 15.967 12.356 16.019 12.488 16.019C12.488 16.019 13.494 16.019 13.494 16.019C13.560 16.019 13.624 16.006 13.684 15.981C13.745 15.956 13.799 15.919 13.845 15.873C13.892 15.827 13.928 15.772 13.953 15.712C13.978 15.652 13.991 15.587 13.991 15.522C13.991 15.522 13.989 14.019 13.989 14.019C13.989 14.019 13.992 14.019 13.992 14.019C13.992 14.019 13.992 10.074 13.992 10.074C13.995 8.477 13.368 6.942 12.247 5.805C11.125 4.668 9.600 4.019 8.003 4.001C8.003 4.001 7.992 3.999 7.992 3.999Z\" fill=\"currentColor\" transform=\"translate(2.008 1.981)\"/></svg>";
    readonly end_of_road_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M11.000 4.019C11.000 4.019 0.501 4.019 0.501 4.019C0.368 4.019 0.241 4.072 0.147 4.166C0.053 4.260 0.000 4.387 0.000 4.520C0.000 4.520 0.000 5.518 0.000 5.518C0.000 5.651 0.053 5.778 0.147 5.872C0.241 5.966 0.368 6.019 0.501 6.019C0.501 6.019 11.000 6.019 11.000 6.019C11.000 6.019 11.000 4.019 11.000 4.019Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(2 1.981)\"/><path d=\"M8.000 6.001C8.000 6.001 9.988 6.001 9.988 6.001C10.057 5.985 10.129 5.991 10.195 6.017C10.260 6.043 10.317 6.088 10.358 6.146C10.398 6.204 10.420 6.272 10.422 6.343C10.423 6.414 10.403 6.483 10.365 6.543C10.365 6.543 9.021 9.495 9.021 9.495C8.995 9.576 8.996 9.663 9.024 9.743C9.052 9.823 9.106 9.891 9.177 9.938C9.247 9.984 9.332 10.006 9.416 10.000C9.501 9.994 9.581 9.960 9.645 9.904C9.645 9.904 15.992 5.019 15.992 5.019C15.992 5.019 9.645 0.097 9.645 0.097C9.581 0.041 9.501 0.007 9.416 0.001C9.332 -0.005 9.247 0.017 9.177 0.063C9.106 0.110 9.052 0.179 9.024 0.259C8.996 0.339 8.995 0.426 9.021 0.506C9.021 0.506 10.365 3.458 10.365 3.458C10.403 3.518 10.423 3.587 10.421 3.658C10.420 3.729 10.398 3.797 10.357 3.855C10.317 3.914 10.260 3.958 10.195 3.984C10.129 4.010 10.057 4.016 9.988 4.001C9.988 4.001 8.000 4.001 8.000 4.001C8.000 4.001 8.000 3.999 8.000 3.999C8.000 3.999 7.989 4.001 7.989 4.001C6.392 4.019 4.867 4.668 3.745 5.805C2.624 6.942 1.996 8.477 2.000 10.074C2.000 10.074 2.000 14.019 2.000 14.019C2.000 14.019 2.003 14.019 2.003 14.019C2.003 14.019 2.001 15.522 2.001 15.522C2.001 15.587 2.014 15.652 2.039 15.712C2.064 15.772 2.100 15.827 2.146 15.873C2.192 15.919 2.247 15.956 2.307 15.981C2.368 16.006 2.432 16.019 2.497 16.019C2.497 16.019 3.504 16.019 3.504 16.019C3.635 16.019 3.762 15.967 3.855 15.874C3.948 15.780 4.000 15.654 4.000 15.523C4.000 15.523 4.000 10.074 4.000 10.074C3.996 9.007 4.412 7.981 5.159 7.219C5.905 6.456 6.922 6.019 7.989 6.001C7.989 6.001 8.000 6.001 8.000 6.001Z\" fill=\"currentColor\" transform=\"translate(2 1.981)\"/></svg>";
    readonly ferry: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M2.6 16.2 C4.1 14.9 5.9 14.9 7.4 16.2 C8.9 17.5 11.1 17.5 12.6 16.2 C14.1 14.9 15.9 14.9 17.4 16.2\" fill=\"none\" stroke=\"currentColor\" stroke-opacity=\"0.35\" stroke-width=\"1.8\" stroke-linecap=\"round\"/><path d=\"M6.7 3.6 H13.3 C13.6 3.6 13.8 3.8 13.8 4.1 V7 H6.2 V4.1 C6.2 3.8 6.4 3.6 6.7 3.6 Z\" fill=\"currentColor\" stroke=\"currentColor\" stroke-width=\"0.7\" stroke-linejoin=\"round\"/><path d=\"M3.4 8.2 H16.6 C17 8.2 17.2 8.6 17 9 L15.3 12.2 C15 12.8 14.4 13.2 13.7 13.2 H6.3 C5.6 13.2 5 12.8 4.7 12.2 L3 9 C2.8 8.6 3 8.2 3.4 8.2 Z\" fill=\"currentColor\" stroke=\"currentColor\" stroke-width=\"0.7\" stroke-linejoin=\"round\"/></svg>";
    readonly flag: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M0.500 15.000C0.367 15.000 0.240 14.947 0.146 14.854C0.053 14.760 0.000 14.633 0.000 14.500C0.000 14.500 0.000 0.500 0.000 0.500C0.000 0.367 0.053 0.240 0.146 0.146C0.240 0.053 0.367 -0.000 0.500 0.000C0.633 0.000 0.760 0.053 0.854 0.146C0.947 0.240 1.000 0.367 1.000 0.500C1.000 0.500 1.000 14.500 1.000 14.500C1.000 14.633 0.947 14.760 0.854 14.854C0.760 14.947 0.633 15.000 0.500 15.000Z M10.333 4.000C10.333 4.000 14.000 0.000 14.000 0.000C14.000 0.000 3.000 0.000 3.000 0.000C3.000 0.000 3.000 8.000 3.000 8.000C3.000 8.000 14.000 8.000 14.000 8.000C14.000 8.000 10.333 4.000 10.333 4.000Z\" fill=\"currentColor\" fill-rule=\"evenodd\" transform=\"translate(3 3)\"/></svg>";
    readonly fork: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M18.000 0.000C18.000 0.000 16.420 7.860 16.420 7.860C16.408 7.944 16.370 8.022 16.310 8.082C16.250 8.142 16.172 8.181 16.088 8.192C16.004 8.203 15.918 8.186 15.845 8.144C15.771 8.102 15.713 8.037 15.680 7.959C15.680 7.959 14.762 4.849 14.762 4.849C14.752 4.778 14.721 4.713 14.674 4.660C14.627 4.608 14.565 4.571 14.496 4.553C14.428 4.536 14.355 4.539 14.289 4.563C14.222 4.586 14.164 4.629 14.122 4.686C14.122 4.686 11.673 6.751 11.673 6.751C11.106 7.276 10.663 7.920 10.375 8.636C10.087 9.353 9.962 10.125 10.008 10.895C10.008 10.895 10.013 14.503 10.013 14.503C10.013 14.568 10.000 14.633 9.975 14.693C9.951 14.754 9.914 14.808 9.868 14.854C9.822 14.901 9.767 14.937 9.707 14.962C9.647 14.987 9.582 15.000 9.517 15.000C9.517 15.000 8.483 15.000 8.483 15.000C8.418 15.000 8.353 14.987 8.293 14.962C8.233 14.937 8.178 14.901 8.132 14.854C8.086 14.808 8.050 14.754 8.025 14.693C8.000 14.633 7.987 14.568 7.987 14.503C7.987 14.503 7.992 10.896 7.992 10.896C8.038 10.125 7.913 9.353 7.625 8.636C7.337 7.920 6.894 7.276 6.327 6.752C6.327 6.752 3.879 4.686 3.879 4.686C3.836 4.629 3.778 4.586 3.711 4.563C3.645 4.539 3.572 4.536 3.504 4.553C3.435 4.571 3.373 4.608 3.326 4.660C3.279 4.713 3.248 4.778 3.238 4.849C3.238 4.849 2.320 7.959 2.320 7.959C2.287 8.037 2.229 8.102 2.155 8.144C2.082 8.186 1.996 8.203 1.912 8.192C1.828 8.181 1.750 8.142 1.690 8.082C1.630 8.022 1.592 7.944 1.580 7.860C1.580 7.860 0.000 0.000 0.000 0.000C0.000 0.000 8.005 0.450 8.005 0.450C8.090 0.449 8.172 0.476 8.240 0.527C8.308 0.578 8.357 0.649 8.380 0.731C8.403 0.813 8.399 0.900 8.368 0.978C8.337 1.057 8.280 1.124 8.208 1.167C8.208 1.167 5.259 2.518 5.259 2.518C5.191 2.538 5.130 2.577 5.085 2.631C5.040 2.686 5.012 2.752 5.004 2.823C4.997 2.893 5.010 2.964 5.043 3.027C5.076 3.089 5.126 3.141 5.189 3.175C5.189 3.175 7.646 5.249 7.646 5.249C8.183 5.720 8.640 6.275 9.000 6.891C9.360 6.275 9.817 5.720 10.354 5.249C10.354 5.249 12.811 3.175 12.811 3.175C12.874 3.141 12.924 3.089 12.957 3.027C12.990 2.964 13.003 2.893 12.996 2.823C12.988 2.752 12.960 2.686 12.915 2.631C12.870 2.577 12.809 2.538 12.741 2.518C12.741 2.518 9.792 1.167 9.792 1.167C9.720 1.124 9.663 1.057 9.632 0.978C9.601 0.900 9.597 0.813 9.620 0.731C9.643 0.649 9.692 0.578 9.760 0.527C9.828 0.476 9.910 0.449 9.995 0.450C9.995 0.450 18.000 0.000 18.000 0.000Z\" fill=\"currentColor\" transform=\"translate(1 3)\"/></svg>";
    readonly fork_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M16.727 4.396C16.608 4.396 16.493 4.438 16.402 4.515C16.402 4.515 14.325 6.267 14.325 6.267C13.528 6.998 12.904 7.897 12.499 8.900C12.094 9.902 11.918 10.983 11.985 12.062C11.985 12.062 11.985 15.523 11.985 15.523C11.985 15.654 12.037 15.780 12.130 15.874C12.223 15.967 12.350 16.019 12.481 16.019C12.481 16.019 13.488 16.019 13.488 16.019C13.553 16.019 13.618 16.006 13.678 15.981C13.738 15.956 13.793 15.919 13.839 15.873C13.885 15.827 13.921 15.772 13.946 15.712C13.971 15.652 13.984 15.587 13.984 15.522C13.984 15.522 13.979 11.914 13.979 11.914C13.933 11.143 14.058 10.372 14.346 9.655C14.634 8.939 15.077 8.295 15.644 7.770C15.644 7.770 17.702 6.034 17.702 6.034C17.753 5.991 17.795 5.939 17.825 5.879C17.856 5.820 17.874 5.755 17.879 5.688C17.884 5.621 17.876 5.554 17.855 5.491C17.835 5.428 17.801 5.369 17.757 5.318C17.757 5.318 17.108 4.570 17.108 4.570C17.061 4.515 17.003 4.471 16.937 4.441C16.871 4.411 16.799 4.396 16.727 4.396Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(1.009 1.981)\"/><path d=\"M7.992 4.001C7.992 4.001 6.004 4.001 6.004 4.001C5.935 4.016 5.863 4.010 5.797 3.984C5.731 3.958 5.675 3.914 5.634 3.855C5.594 3.797 5.572 3.729 5.570 3.658C5.569 3.587 5.589 3.518 5.627 3.458C5.627 3.458 6.971 0.506 6.971 0.506C6.997 0.426 6.996 0.339 6.968 0.259C6.940 0.179 6.886 0.110 6.815 0.063C6.744 0.017 6.660 -0.005 6.575 0.001C6.491 0.007 6.411 0.041 6.347 0.097C6.347 0.097 0.000 5.019 0.000 5.019C0.000 5.019 6.347 9.904 6.347 9.904C6.411 9.960 6.491 9.994 6.575 10.000C6.660 10.006 6.744 9.984 6.815 9.938C6.886 9.891 6.940 9.823 6.968 9.743C6.996 9.663 6.997 9.576 6.971 9.495C6.971 9.495 5.627 6.543 5.627 6.543C5.589 6.483 5.569 6.414 5.570 6.343C5.572 6.273 5.594 6.204 5.634 6.146C5.675 6.088 5.731 6.043 5.797 6.017C5.863 5.991 5.935 5.985 6.004 6.001C6.004 6.001 8.003 6.001 8.003 6.001C9.070 6.019 10.087 6.456 10.833 7.219C11.580 7.981 11.996 9.007 11.992 10.074C11.992 10.074 11.992 15.523 11.992 15.523C11.992 15.588 12.005 15.652 12.029 15.713C12.054 15.773 12.091 15.827 12.137 15.874C12.183 15.920 12.238 15.956 12.298 15.981C12.358 16.006 12.423 16.019 12.488 16.019C12.488 16.019 13.494 16.019 13.494 16.019C13.560 16.019 13.624 16.006 13.684 15.981C13.745 15.956 13.799 15.919 13.845 15.873C13.892 15.827 13.928 15.772 13.953 15.712C13.978 15.652 13.991 15.587 13.991 15.522C13.991 15.522 13.989 14.019 13.989 14.019C13.989 14.019 13.992 14.019 13.992 14.019C13.992 14.019 13.992 10.074 13.992 10.074C13.995 8.477 13.368 6.942 12.247 5.805C11.125 4.668 9.600 4.019 8.003 4.001C8.003 4.001 7.992 3.999 7.992 3.999Z\" fill=\"currentColor\" transform=\"translate(1.009 1.981)\"/></svg>";
    readonly fork_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M1.154 4.396C1.081 4.396 1.010 4.411 0.944 4.441C0.878 4.471 0.820 4.515 0.772 4.570C0.772 4.570 0.123 5.318 0.123 5.318C0.080 5.369 0.046 5.428 0.025 5.491C0.004 5.554 -0.004 5.621 0.002 5.688C0.007 5.755 0.025 5.820 0.056 5.879C0.086 5.939 0.128 5.991 0.179 6.034C0.179 6.034 2.237 7.770 2.237 7.770C2.803 8.295 3.247 8.939 3.535 9.655C3.823 10.372 3.948 11.143 3.902 11.914C3.902 11.914 3.897 15.522 3.897 15.522C3.897 15.587 3.910 15.652 3.934 15.712C3.959 15.772 3.996 15.827 4.042 15.873C4.088 15.919 4.143 15.956 4.203 15.981C4.263 16.006 4.328 16.019 4.393 16.019C4.393 16.019 5.400 16.019 5.400 16.019C5.531 16.019 5.657 15.967 5.750 15.874C5.843 15.780 5.896 15.654 5.896 15.523C5.896 15.523 5.896 12.062 5.896 12.062C5.962 10.983 5.787 9.902 5.382 8.900C4.977 7.897 4.353 6.998 3.556 6.267C3.556 6.267 1.479 4.515 1.479 4.515C1.388 4.438 1.273 4.396 1.154 4.396Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(1.12 1.981)\"/><path d=\"M9.888 6.001C9.888 6.001 11.876 6.001 11.876 6.001C11.945 5.985 12.017 5.991 12.083 6.017C12.149 6.043 12.205 6.088 12.246 6.146C12.286 6.204 12.308 6.272 12.310 6.343C12.311 6.414 12.291 6.483 12.253 6.543C12.253 6.543 10.909 9.495 10.909 9.495C10.883 9.576 10.884 9.663 10.912 9.743C10.940 9.823 10.994 9.891 11.065 9.938C11.136 9.984 11.220 10.006 11.304 10.000C11.389 9.994 11.469 9.960 11.533 9.904C11.533 9.904 17.880 5.019 17.880 5.019C17.880 5.019 11.533 0.097 11.533 0.097C11.469 0.041 11.389 0.007 11.304 0.001C11.220 -0.005 11.136 0.017 11.065 0.063C10.994 0.110 10.940 0.179 10.912 0.259C10.884 0.339 10.883 0.426 10.909 0.506C10.909 0.506 12.253 3.458 12.253 3.458C12.291 3.518 12.311 3.587 12.310 3.658C12.308 3.729 12.286 3.797 12.246 3.855C12.205 3.914 12.149 3.958 12.083 3.984C12.017 4.010 11.945 4.016 11.876 4.001C11.876 4.001 9.888 4.001 9.888 4.001C9.888 4.001 9.888 3.999 9.888 3.999C9.888 3.999 9.877 4.001 9.877 4.001C8.280 4.019 6.755 4.668 5.633 5.805C4.512 6.942 3.885 8.477 3.888 10.074C3.888 10.074 3.888 14.019 3.888 14.019C3.888 14.019 3.891 14.019 3.891 14.019C3.891 14.019 3.889 15.522 3.889 15.522C3.889 15.587 3.902 15.652 3.927 15.712C3.952 15.772 3.988 15.827 4.034 15.873C4.080 15.919 4.135 15.956 4.195 15.981C4.256 16.006 4.320 16.019 4.386 16.019C4.386 16.019 5.392 16.019 5.392 16.019C5.524 16.019 5.650 15.967 5.743 15.874C5.836 15.780 5.888 15.654 5.888 15.523C5.888 15.523 5.888 10.074 5.888 10.074C5.884 9.007 6.300 7.981 7.047 7.219C7.793 6.456 8.810 6.019 9.877 6.001C9.877 6.001 9.888 6.001 9.888 6.001Z\" fill=\"currentColor\" transform=\"translate(1.12 1.981)\"/></svg>";
    readonly fork_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M12.756 3.377C12.637 3.377 12.522 3.419 12.431 3.496C12.431 3.496 10.354 5.249 10.354 5.249C9.557 5.979 8.933 6.878 8.528 7.881C8.123 8.883 7.947 9.964 8.014 11.043C8.014 11.043 8.014 14.504 8.014 14.504C8.014 14.635 8.066 14.762 8.159 14.855C8.253 14.948 8.379 15.000 8.510 15.000C8.510 15.000 9.517 15.000 9.517 15.000C9.582 15.000 9.647 14.987 9.707 14.962C9.767 14.937 9.822 14.901 9.868 14.854C9.914 14.808 9.950 14.754 9.975 14.693C10.000 14.633 10.013 14.568 10.013 14.503C10.013 14.503 10.008 10.896 10.008 10.896C9.962 10.125 10.087 9.353 10.375 8.636C10.663 7.920 11.106 7.276 11.673 6.751C11.673 6.751 13.731 5.016 13.731 5.016C13.782 4.973 13.824 4.920 13.854 4.860C13.885 4.801 13.903 4.736 13.908 4.669C13.913 4.603 13.905 4.536 13.884 4.472C13.864 4.409 13.830 4.350 13.787 4.299C13.787 4.299 13.138 3.551 13.138 3.551C13.090 3.496 13.032 3.452 12.966 3.422C12.900 3.392 12.828 3.377 12.756 3.377Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(3 3)\"/><path d=\"M7.646 5.249C7.646 5.249 5.189 3.175 5.189 3.175C5.126 3.141 5.076 3.089 5.043 3.027C5.010 2.964 4.997 2.893 5.004 2.823C5.012 2.752 5.040 2.686 5.085 2.631C5.130 2.577 5.191 2.538 5.259 2.518C5.259 2.518 8.208 1.167 8.208 1.167C8.280 1.124 8.337 1.057 8.368 0.978C8.399 0.900 8.403 0.813 8.380 0.731C8.357 0.649 8.308 0.578 8.240 0.527C8.172 0.476 8.090 0.449 8.005 0.450C8.005 0.450 0.000 0.000 0.000 0.000C0.000 0.000 1.580 7.860 1.580 7.860C1.592 7.944 1.630 8.022 1.690 8.082C1.750 8.142 1.828 8.181 1.912 8.192C1.996 8.203 2.082 8.186 2.155 8.144C2.229 8.102 2.287 8.037 2.320 7.959C2.320 7.959 3.238 4.849 3.238 4.849C3.248 4.778 3.279 4.713 3.326 4.660C3.373 4.608 3.435 4.571 3.504 4.553C3.572 4.536 3.645 4.539 3.711 4.563C3.778 4.586 3.836 4.629 3.878 4.686C3.878 4.686 6.327 6.751 6.327 6.751C6.894 7.276 7.337 7.920 7.625 8.636C7.913 9.353 8.038 10.125 7.992 10.895C7.992 10.895 7.987 14.503 7.987 14.503C7.987 14.568 8.000 14.633 8.025 14.693C8.049 14.754 8.086 14.808 8.132 14.854C8.178 14.901 8.233 14.937 8.293 14.962C8.353 14.987 8.418 15.000 8.483 15.000C8.483 15.000 9.490 15.000 9.490 15.000C9.621 15.000 9.748 14.948 9.841 14.855C9.934 14.762 9.986 14.635 9.986 14.504C9.986 14.504 9.986 11.043 9.986 11.043C10.053 9.964 9.877 8.883 9.472 7.881C9.067 6.878 8.443 5.979 7.646 5.249Z\" fill=\"currentColor\" transform=\"translate(3 3)\"/></svg>";
    readonly fork_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M1.154 3.377C1.081 3.377 1.010 3.392 0.944 3.422C0.878 3.452 0.820 3.496 0.772 3.551C0.772 3.551 0.123 4.299 0.123 4.299C0.080 4.350 0.046 4.409 0.025 4.472C0.004 4.536 -0.004 4.603 0.002 4.669C0.007 4.736 0.025 4.801 0.056 4.860C0.086 4.920 0.128 4.973 0.179 5.016C0.179 5.016 2.237 6.751 2.237 6.751C2.803 7.276 3.247 7.920 3.535 8.636C3.823 9.353 3.948 10.125 3.902 10.896C3.902 10.896 3.897 14.503 3.897 14.503C3.897 14.568 3.910 14.633 3.934 14.693C3.959 14.754 3.996 14.808 4.042 14.854C4.088 14.901 4.143 14.937 4.203 14.962C4.263 14.987 4.328 15.000 4.393 15.000C4.393 15.000 5.400 15.000 5.400 15.000C5.531 15.000 5.657 14.948 5.750 14.855C5.843 14.762 5.896 14.635 5.896 14.504C5.896 14.504 5.896 11.043 5.896 11.043C5.962 9.964 5.787 8.883 5.382 7.881C4.977 6.878 4.353 5.979 3.556 5.249C3.556 5.249 1.479 3.496 1.479 3.496C1.388 3.419 1.273 3.377 1.154 3.377Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(3.115 3)\"/><path d=\"M3.899 11.043C3.899 11.043 3.899 14.504 3.899 14.504C3.899 14.635 3.952 14.762 4.045 14.855C4.138 14.948 4.264 15.000 4.395 15.000C4.395 15.000 5.402 15.000 5.402 15.000C5.467 15.000 5.532 14.987 5.592 14.962C5.652 14.937 5.707 14.901 5.753 14.854C5.799 14.808 5.836 14.754 5.861 14.693C5.885 14.633 5.898 14.568 5.898 14.503C5.898 14.503 5.893 10.896 5.893 10.896C5.847 10.125 5.972 9.353 6.260 8.636C6.548 7.920 6.991 7.276 7.558 6.752C7.558 6.752 10.007 4.686 10.007 4.686C10.049 4.629 10.107 4.586 10.174 4.563C10.240 4.539 10.313 4.536 10.381 4.553C10.450 4.571 10.512 4.608 10.559 4.661C10.606 4.713 10.637 4.779 10.647 4.849C10.647 4.849 11.565 7.959 11.565 7.959C11.598 8.037 11.656 8.102 11.730 8.145C11.803 8.187 11.889 8.203 11.973 8.192C12.057 8.181 12.135 8.142 12.195 8.082C12.255 8.022 12.293 7.944 12.305 7.860C12.305 7.860 13.885 0.000 13.885 0.000C13.885 0.000 5.880 0.450 5.880 0.450C5.796 0.449 5.713 0.476 5.645 0.527C5.577 0.578 5.528 0.649 5.505 0.731C5.482 0.813 5.486 0.900 5.517 0.978C5.549 1.057 5.605 1.124 5.677 1.167C5.677 1.167 8.626 2.518 8.626 2.518C8.694 2.538 8.755 2.577 8.800 2.631C8.845 2.686 8.874 2.752 8.881 2.823C8.889 2.893 8.875 2.964 8.842 3.027C8.809 3.089 8.759 3.141 8.697 3.175C8.697 3.175 6.239 5.249 6.239 5.249C5.442 5.979 4.818 6.878 4.413 7.881C4.008 8.883 3.833 9.964 3.899 11.043Z\" fill=\"currentColor\" transform=\"translate(3.115 3)\"/></svg>";
    readonly fork_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M16.666 4.398C16.547 4.398 16.432 4.440 16.341 4.517C16.341 4.517 14.264 6.269 14.264 6.269C13.466 7.000 12.843 7.899 12.438 8.902C12.033 9.904 11.857 10.985 11.924 12.064C11.924 12.064 11.924 15.525 11.924 15.525C11.924 15.656 11.976 15.782 12.069 15.875C12.162 15.969 12.289 16.021 12.420 16.021C12.420 16.021 13.427 16.021 13.427 16.021C13.492 16.021 13.556 16.008 13.617 15.983C13.677 15.958 13.732 15.921 13.778 15.875C13.824 15.829 13.860 15.774 13.885 15.714C13.910 15.654 13.923 15.589 13.923 15.524C13.923 15.524 13.918 11.916 13.918 11.916C13.872 11.145 13.997 10.374 14.285 9.657C14.573 8.941 15.016 8.297 15.583 7.772C15.583 7.772 17.640 6.036 17.640 6.036C17.692 5.993 17.734 5.941 17.764 5.881C17.795 5.822 17.813 5.757 17.818 5.690C17.823 5.623 17.815 5.556 17.794 5.493C17.773 5.429 17.740 5.371 17.696 5.320C17.696 5.320 17.047 4.572 17.047 4.572C17.000 4.517 16.941 4.473 16.876 4.443C16.810 4.413 16.738 4.398 16.666 4.398Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(1.09 2)\"/><path class=\"mm2\" d=\"M1.154 4.377C1.081 4.377 1.010 4.392 0.944 4.422C0.878 4.452 0.820 4.496 0.772 4.551C0.772 4.551 0.123 5.299 0.123 5.299C0.080 5.350 0.046 5.409 0.025 5.472C0.004 5.536 -0.004 5.603 0.002 5.669C0.007 5.736 0.025 5.801 0.056 5.860C0.086 5.920 0.128 5.973 0.179 6.016C0.179 6.016 2.237 7.751 2.237 7.751C2.803 8.276 3.247 8.920 3.535 9.636C3.823 10.353 3.948 11.125 3.902 11.896C3.902 11.896 3.897 15.503 3.897 15.503C3.897 15.568 3.910 15.633 3.934 15.693C3.959 15.754 3.996 15.808 4.042 15.854C4.088 15.901 4.143 15.937 4.203 15.962C4.263 15.987 4.328 16.000 4.393 16.000C4.393 16.000 5.400 16.000 5.400 16.000C5.531 16.000 5.657 15.948 5.750 15.855C5.843 15.762 5.896 15.635 5.896 15.504C5.896 15.504 5.896 12.043 5.896 12.043C5.962 10.964 5.787 9.883 5.382 8.881C4.977 7.878 4.353 6.979 3.556 6.249C3.556 6.249 1.479 4.496 1.479 4.496C1.388 4.419 1.273 4.377 1.154 4.377Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(1.09 2)\"/><path d=\"M13.823 6.343C13.823 6.343 8.919 0.000 8.919 0.000C8.919 0.000 4.015 6.343 4.015 6.343C3.959 6.406 3.925 6.487 3.919 6.571C3.913 6.656 3.935 6.740 3.982 6.811C4.028 6.882 4.097 6.935 4.177 6.964C4.257 6.992 4.344 6.993 4.425 6.966C4.425 6.966 7.377 5.623 7.377 5.623C7.436 5.584 7.506 5.565 7.576 5.566C7.647 5.567 7.716 5.590 7.774 5.630C7.832 5.670 7.877 5.727 7.903 5.793C7.928 5.859 7.934 5.931 7.919 6.000C7.919 6.000 7.919 15.497 7.919 15.497C7.919 15.563 7.932 15.628 7.957 15.689C7.983 15.750 8.020 15.806 8.066 15.853C8.113 15.899 8.169 15.936 8.230 15.962C8.291 15.987 8.356 16.000 8.422 16.000C8.422 16.000 9.415 16.000 9.415 16.000C9.482 16.000 9.547 15.987 9.608 15.962C9.669 15.936 9.725 15.899 9.771 15.853C9.818 15.806 9.855 15.750 9.881 15.689C9.906 15.628 9.919 15.563 9.919 15.497C9.919 15.497 9.919 6.000 9.919 6.000C9.904 5.931 9.909 5.859 9.935 5.793C9.961 5.727 10.006 5.670 10.064 5.630C10.122 5.590 10.191 5.567 10.262 5.566C10.332 5.565 10.402 5.584 10.461 5.623C10.461 5.623 13.413 6.966 13.413 6.966C13.494 6.993 13.581 6.992 13.661 6.964C13.741 6.935 13.810 6.882 13.856 6.811C13.903 6.740 13.925 6.656 13.919 6.571C13.912 6.487 13.879 6.406 13.823 6.343Z\" fill=\"currentColor\" transform=\"translate(1.09 2)\"/></svg>";
    readonly invalid: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.495 6.966C9.495 6.966 6.543 5.623 6.543 5.623C6.483 5.584 6.414 5.565 6.343 5.566C6.272 5.567 6.204 5.590 6.146 5.630C6.088 5.670 6.043 5.727 6.017 5.793C5.991 5.859 5.985 5.931 6.001 6.000C6.001 6.000 6.001 15.497 6.001 15.497C6.001 15.563 5.988 15.628 5.962 15.689C5.937 15.750 5.900 15.806 5.853 15.853C5.806 15.899 5.751 15.936 5.690 15.962C5.629 15.987 5.563 16.000 5.497 16.000C5.497 16.000 4.504 16.000 4.504 16.000C4.438 16.000 4.372 15.987 4.311 15.962C4.250 15.936 4.195 15.899 4.148 15.853C4.101 15.806 4.064 15.750 4.039 15.689C4.014 15.628 4.001 15.563 4.001 15.497C4.001 15.497 4.001 6.000 4.001 6.000C4.016 5.931 4.010 5.859 3.984 5.793C3.958 5.727 3.914 5.670 3.856 5.630C3.797 5.590 3.729 5.567 3.658 5.566C3.587 5.565 3.518 5.584 3.458 5.623C3.458 5.623 0.506 6.966 0.506 6.966C0.426 6.993 0.339 6.992 0.259 6.964C0.179 6.935 0.110 6.882 0.063 6.811C0.017 6.740 -0.005 6.656 0.001 6.571C0.007 6.487 0.041 6.406 0.097 6.343C0.097 6.343 5.001 0.000 5.001 0.000C5.001 0.000 9.904 6.343 9.904 6.343C9.960 6.406 9.994 6.487 10.000 6.571C10.006 6.656 9.984 6.740 9.938 6.811C9.891 6.882 9.823 6.935 9.743 6.964C9.662 6.992 9.575 6.993 9.495 6.966Z\" fill=\"currentColor\" transform=\"translate(5.009 2)\"/></svg>";
    readonly invalid_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M7.992 3.999C7.992 3.999 8.003 4.001 8.003 4.001C9.600 4.019 11.125 4.668 12.247 5.805C13.368 6.942 13.995 8.477 13.992 10.074C13.992 10.074 13.992 14.019 13.992 14.019C13.992 14.019 13.989 14.019 13.989 14.019C13.989 14.019 13.991 15.522 13.991 15.522C13.991 15.587 13.978 15.652 13.953 15.712C13.928 15.772 13.892 15.827 13.845 15.873C13.799 15.919 13.745 15.956 13.684 15.981C13.624 16.006 13.560 16.019 13.494 16.019C13.494 16.019 12.488 16.019 12.488 16.019C12.356 16.019 12.230 15.967 12.137 15.874C12.044 15.780 11.992 15.654 11.992 15.523C11.992 15.523 11.992 10.074 11.992 10.074C11.996 9.007 11.580 7.981 10.833 7.219C10.087 6.456 9.070 6.019 8.003 6.001C8.003 6.001 6.004 6.001 6.004 6.001C5.935 5.985 5.863 5.991 5.797 6.017C5.731 6.043 5.675 6.088 5.634 6.146C5.594 6.204 5.572 6.272 5.570 6.343C5.569 6.414 5.589 6.483 5.627 6.543C5.627 6.543 6.971 9.495 6.971 9.495C6.997 9.576 6.996 9.663 6.968 9.743C6.940 9.823 6.886 9.891 6.815 9.938C6.744 9.984 6.660 10.006 6.575 10.000C6.491 9.994 6.411 9.960 6.347 9.904C6.347 9.904 0.000 5.019 0.000 5.019C0.000 5.019 6.347 0.097 6.347 0.097C6.411 0.041 6.491 0.007 6.575 0.001C6.660 -0.005 6.744 0.017 6.815 0.063C6.886 0.110 6.940 0.179 6.968 0.259C6.996 0.339 6.997 0.426 6.971 0.506C6.971 0.506 5.627 3.458 5.627 3.458C5.589 3.518 5.569 3.587 5.570 3.658C5.572 3.729 5.594 3.797 5.634 3.855C5.675 3.914 5.731 3.958 5.797 3.984C5.863 4.010 5.935 4.016 6.004 4.001C6.004 4.001 7.992 4.001 7.992 4.001Z\" fill=\"currentColor\" transform=\"translate(2.008 1.981)\"/></svg>";
    readonly invalid_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M5.989 6.001C4.922 6.019 3.905 6.456 3.159 7.219C2.412 7.981 1.996 9.007 2.000 10.074C2.000 10.074 2.000 15.523 2.000 15.523C2.000 15.654 1.948 15.780 1.855 15.874C1.762 15.967 1.635 16.019 1.504 16.019C1.504 16.019 0.497 16.019 0.497 16.019C0.432 16.019 0.368 16.006 0.307 15.981C0.247 15.956 0.192 15.919 0.146 15.873C0.100 15.827 0.064 15.772 0.039 15.712C0.014 15.652 0.001 15.587 0.001 15.522C0.001 15.522 0.003 14.019 0.003 14.019C0.003 14.019 0.000 14.019 0.000 14.019C0.000 14.019 0.000 10.074 0.000 10.074C-0.004 8.477 0.624 6.942 1.745 5.805C2.867 4.668 4.392 4.019 5.989 4.001C5.989 4.001 6.000 3.999 6.000 3.999C6.000 3.999 6.000 4.001 6.000 4.001C6.000 4.001 7.988 4.001 7.988 4.001C8.057 4.016 8.129 4.010 8.195 3.984C8.260 3.958 8.317 3.914 8.358 3.855C8.398 3.797 8.420 3.729 8.422 3.658C8.423 3.587 8.403 3.518 8.365 3.458C8.365 3.458 7.021 0.506 7.021 0.506C6.995 0.426 6.996 0.339 7.024 0.259C7.052 0.179 7.106 0.110 7.177 0.063C7.247 0.017 7.332 -0.005 7.416 0.001C7.501 0.007 7.581 0.041 7.645 0.097C7.645 0.097 13.992 5.019 13.992 5.019C13.992 5.019 7.645 9.904 7.645 9.904C7.581 9.960 7.501 9.994 7.416 10.000C7.332 10.006 7.247 9.984 7.177 9.938C7.106 9.891 7.052 9.823 7.024 9.743C6.996 9.663 6.995 9.576 7.021 9.495C7.021 9.495 8.365 6.543 8.365 6.543C8.403 6.483 8.423 6.414 8.422 6.343C8.420 6.272 8.398 6.204 8.358 6.146C8.317 6.088 8.260 6.043 8.195 6.017C8.129 5.991 8.057 5.985 7.988 6.001C7.988 6.001 5.989 6.001 5.989 6.001Z\" fill=\"currentColor\" transform=\"translate(4 1.981)\"/></svg>";
    readonly invalid_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.986 11.043C9.986 11.043 9.986 14.504 9.986 14.504C9.986 14.635 9.934 14.762 9.841 14.855C9.748 14.948 9.621 15.000 9.490 15.000C9.490 15.000 8.483 15.000 8.483 15.000C8.418 15.000 8.353 14.987 8.293 14.962C8.233 14.937 8.178 14.901 8.132 14.854C8.086 14.808 8.050 14.754 8.025 14.693C8.000 14.633 7.987 14.568 7.987 14.503C7.987 14.503 7.992 10.896 7.992 10.896C8.038 10.125 7.913 9.353 7.625 8.636C7.337 7.920 6.894 7.276 6.327 6.752C6.327 6.752 3.879 4.686 3.879 4.686C3.836 4.629 3.778 4.586 3.711 4.563C3.645 4.539 3.572 4.536 3.504 4.553C3.435 4.571 3.373 4.608 3.326 4.660C3.279 4.713 3.248 4.778 3.238 4.849C3.238 4.849 2.320 7.959 2.320 7.959C2.287 8.037 2.229 8.102 2.155 8.144C2.082 8.186 1.996 8.203 1.912 8.192C1.828 8.181 1.750 8.142 1.690 8.082C1.630 8.022 1.592 7.944 1.580 7.860C1.580 7.860 0.000 0.000 0.000 0.000C0.000 0.000 8.005 0.450 8.005 0.450C8.090 0.449 8.172 0.476 8.240 0.527C8.308 0.578 8.357 0.649 8.380 0.731C8.403 0.813 8.399 0.900 8.368 0.978C8.337 1.057 8.280 1.124 8.208 1.167C8.208 1.167 5.259 2.518 5.259 2.518C5.191 2.538 5.130 2.577 5.085 2.631C5.040 2.686 5.012 2.752 5.004 2.823C4.997 2.893 5.010 2.964 5.043 3.027C5.076 3.089 5.126 3.141 5.189 3.175C5.189 3.175 7.646 5.249 7.646 5.249C8.443 5.979 9.067 6.878 9.472 7.881C9.877 8.883 10.053 9.964 9.986 11.043Z\" fill=\"currentColor\" transform=\"translate(5 3)\"/></svg>";
    readonly invalid_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M2.354 5.249C2.354 5.249 4.811 3.175 4.811 3.175C4.873 3.141 4.924 3.089 4.957 3.027C4.990 2.964 5.003 2.893 4.996 2.823C4.988 2.752 4.960 2.686 4.915 2.631C4.869 2.577 4.809 2.538 4.741 2.518C4.741 2.518 1.792 1.167 1.792 1.167C1.719 1.124 1.663 1.057 1.632 0.978C1.601 0.900 1.596 0.813 1.619 0.731C1.642 0.649 1.692 0.578 1.760 0.527C1.827 0.476 1.910 0.449 1.995 0.450C1.995 0.450 10.000 0.000 10.000 0.000C10.000 0.000 8.419 7.860 8.419 7.860C8.408 7.944 8.369 8.022 8.309 8.082C8.249 8.142 8.171 8.181 8.087 8.192C8.003 8.203 7.918 8.186 7.844 8.144C7.771 8.102 7.713 8.037 7.680 7.959C7.680 7.959 6.762 4.849 6.762 4.849C6.752 4.778 6.721 4.713 6.674 4.660C6.626 4.608 6.564 4.571 6.496 4.553C6.427 4.536 6.355 4.539 6.288 4.563C6.222 4.586 6.163 4.629 6.121 4.686C6.121 4.686 3.673 6.751 3.673 6.751C3.106 7.276 2.663 7.920 2.375 8.636C2.087 9.353 1.962 10.125 2.008 10.895C2.008 10.895 2.013 14.503 2.013 14.503C2.013 14.568 2.000 14.633 1.975 14.693C1.950 14.754 1.914 14.808 1.868 14.854C1.821 14.901 1.767 14.937 1.707 14.962C1.646 14.987 1.582 15.000 1.516 15.000C1.516 15.000 0.510 15.000 0.510 15.000C0.378 15.000 0.252 14.948 0.159 14.855C0.066 14.762 0.014 14.635 0.014 14.504C0.014 14.504 0.014 11.043 0.014 11.043C-0.053 9.964 0.123 8.883 0.528 7.881C0.932 6.878 1.556 5.979 2.354 5.249Z\" fill=\"currentColor\" transform=\"translate(5 3)\"/></svg>";
    readonly invalid_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.495 6.966C9.495 6.966 6.543 5.623 6.543 5.623C6.483 5.584 6.414 5.565 6.343 5.566C6.272 5.567 6.204 5.590 6.146 5.630C6.088 5.670 6.043 5.727 6.017 5.793C5.991 5.859 5.985 5.931 6.001 6.000C6.001 6.000 6.001 15.497 6.001 15.497C6.001 15.563 5.988 15.628 5.962 15.689C5.937 15.750 5.900 15.806 5.853 15.853C5.806 15.899 5.751 15.936 5.690 15.962C5.629 15.987 5.563 16.000 5.497 16.000C5.497 16.000 4.504 16.000 4.504 16.000C4.438 16.000 4.372 15.987 4.311 15.962C4.250 15.936 4.195 15.899 4.148 15.853C4.101 15.806 4.064 15.750 4.039 15.689C4.014 15.628 4.001 15.563 4.001 15.497C4.001 15.497 4.001 6.000 4.001 6.000C4.016 5.931 4.010 5.859 3.984 5.793C3.958 5.727 3.914 5.670 3.856 5.630C3.797 5.590 3.729 5.567 3.658 5.566C3.587 5.565 3.518 5.584 3.458 5.623C3.458 5.623 0.506 6.966 0.506 6.966C0.426 6.993 0.339 6.992 0.259 6.964C0.179 6.935 0.110 6.882 0.063 6.811C0.017 6.740 -0.005 6.656 0.001 6.571C0.007 6.487 0.041 6.406 0.097 6.343C0.097 6.343 5.001 0.000 5.001 0.000C5.001 0.000 9.904 6.343 9.904 6.343C9.960 6.406 9.994 6.487 10.000 6.571C10.006 6.656 9.984 6.740 9.938 6.811C9.891 6.882 9.823 6.935 9.743 6.964C9.662 6.992 9.575 6.993 9.495 6.966Z\" fill=\"currentColor\" transform=\"translate(5.009 2)\"/></svg>";
    readonly invalid_uturn: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M15.010 5.500C15.010 5.500 15.010 14.997 15.010 14.997C15.010 15.063 14.997 15.128 14.971 15.189C14.946 15.250 14.909 15.306 14.862 15.353C14.815 15.399 14.760 15.436 14.699 15.462C14.638 15.487 14.572 15.500 14.506 15.500C14.506 15.500 13.513 15.500 13.513 15.500C13.447 15.500 13.382 15.487 13.321 15.462C13.259 15.436 13.204 15.399 13.157 15.353C13.110 15.306 13.073 15.250 13.048 15.189C13.023 15.128 13.010 15.063 13.010 14.997C13.010 14.997 13.010 5.500 13.010 5.500C13.010 4.572 12.641 3.682 11.985 3.025C11.328 2.369 10.438 2.000 9.510 2.000C8.581 2.000 7.691 2.369 7.035 3.025C6.378 3.682 6.010 4.572 6.010 5.500C6.010 5.500 6.010 9.500 6.010 9.500C6.010 9.500 6.001 9.500 6.001 9.500C5.985 9.569 5.991 9.641 6.017 9.707C6.043 9.773 6.088 9.830 6.146 9.870C6.204 9.910 6.272 9.933 6.343 9.934C6.414 9.935 6.483 9.916 6.543 9.877C6.543 9.877 9.495 8.534 9.495 8.534C9.575 8.507 9.663 8.508 9.743 8.536C9.823 8.565 9.891 8.618 9.938 8.689C9.984 8.760 10.006 8.844 10.000 8.929C9.994 9.013 9.960 9.094 9.904 9.157C9.904 9.157 5.001 15.500 5.001 15.500C5.001 15.500 0.097 9.157 0.097 9.157C0.041 9.094 0.007 9.013 0.001 8.929C-0.005 8.844 0.017 8.760 0.063 8.689C0.110 8.618 0.179 8.565 0.259 8.536C0.339 8.508 0.426 8.507 0.506 8.534C0.506 8.534 3.458 9.877 3.458 9.877C3.518 9.916 3.587 9.935 3.658 9.934C3.729 9.933 3.797 9.910 3.855 9.870C3.914 9.830 3.958 9.773 3.984 9.707C4.010 9.641 4.016 9.569 4.001 9.500C4.001 9.500 4.010 9.500 4.010 9.500C4.010 9.500 4.010 5.500 4.010 5.500C4.010 4.041 4.589 2.642 5.621 1.611C6.652 0.579 8.051 0.000 9.510 0.000C10.968 0.000 12.367 0.579 13.399 1.611C14.430 2.642 15.010 4.041 15.010 5.500Z\" fill=\"currentColor\" transform=\"translate(1.999 2.5)\"/></svg>";
    readonly merge_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M6.019 4.992C6.019 4.992 4.019 4.992 4.019 4.992C4.019 4.992 4.019 15.494 4.019 15.494C4.019 15.560 4.032 15.624 4.057 15.685C4.082 15.745 4.118 15.800 4.165 15.846C4.211 15.892 4.266 15.929 4.326 15.954C4.386 15.979 4.451 15.992 4.516 15.992C4.516 15.992 5.521 15.992 5.521 15.992C5.587 15.992 5.651 15.979 5.712 15.954C5.772 15.929 5.827 15.892 5.873 15.846C5.919 15.800 5.956 15.745 5.981 15.685C6.006 15.624 6.019 15.560 6.019 15.494C6.019 15.494 6.019 4.992 6.019 4.992Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(1.981 2.008)\"/><path d=\"M6.001 7.992C6.001 7.992 6.001 6.004 6.001 6.004C5.985 5.935 5.991 5.863 6.017 5.797C6.043 5.731 6.088 5.675 6.146 5.634C6.204 5.594 6.272 5.572 6.343 5.570C6.414 5.569 6.483 5.589 6.543 5.627C6.543 5.627 9.495 6.971 9.495 6.971C9.576 6.997 9.663 6.996 9.743 6.968C9.823 6.940 9.891 6.886 9.938 6.815C9.984 6.744 10.006 6.660 10.000 6.575C9.994 6.491 9.960 6.411 9.904 6.347C9.904 6.347 5.019 0.000 5.019 0.000C5.019 0.000 0.097 6.347 0.097 6.347C0.041 6.411 0.007 6.491 0.001 6.575C-0.005 6.660 0.017 6.744 0.063 6.815C0.110 6.886 0.179 6.940 0.259 6.968C0.339 6.996 0.426 6.997 0.506 6.971C0.506 6.971 3.458 5.627 3.458 5.627C3.518 5.589 3.587 5.569 3.658 5.570C3.729 5.572 3.797 5.594 3.855 5.634C3.914 5.675 3.958 5.731 3.984 5.797C4.010 5.863 4.016 5.935 4.001 6.004C4.001 6.004 4.001 7.992 4.001 7.992C4.001 7.992 3.999 7.992 3.999 7.992C3.999 7.992 4.001 8.003 4.001 8.003C4.019 9.600 4.668 11.125 5.805 12.247C6.942 13.368 8.477 13.995 10.074 13.992C10.074 13.992 14.019 13.992 14.019 13.992C14.019 13.992 14.019 13.989 14.019 13.989C14.019 13.989 15.522 13.991 15.522 13.991C15.587 13.991 15.652 13.978 15.712 13.953C15.772 13.928 15.827 13.892 15.873 13.845C15.919 13.799 15.956 13.745 15.981 13.684C16.006 13.624 16.019 13.560 16.019 13.494C16.019 13.494 16.019 12.488 16.019 12.488C16.019 12.356 15.967 12.230 15.874 12.137C15.780 12.044 15.654 11.992 15.523 11.992C15.523 11.992 10.074 11.992 10.074 11.992C9.007 11.996 7.981 11.580 7.219 10.833C6.456 10.087 6.019 9.070 6.001 8.003C6.001 8.003 6.001 7.992 6.001 7.992Z\" fill=\"currentColor\" transform=\"translate(1.981 2.008)\"/></svg>";
    readonly merge_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M12.000 4.992C12.000 4.992 10.000 4.992 10.000 4.992C10.000 4.992 10.000 15.491 10.000 15.491C10.000 15.624 10.053 15.751 10.147 15.845C10.241 15.939 10.368 15.992 10.501 15.992C10.501 15.992 11.499 15.992 11.499 15.992C11.565 15.992 11.630 15.979 11.691 15.954C11.752 15.928 11.807 15.892 11.853 15.845C11.900 15.799 11.937 15.743 11.962 15.683C11.987 15.622 12.000 15.557 12.000 15.491C12.000 15.491 12.000 4.992 12.000 4.992Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(2 2.008)\"/><path d=\"M12.018 7.992C12.018 7.992 12.018 6.004 12.018 6.004C12.003 5.935 12.009 5.863 12.035 5.797C12.061 5.731 12.105 5.675 12.163 5.634C12.221 5.594 12.290 5.572 12.361 5.570C12.432 5.569 12.501 5.589 12.561 5.627C12.561 5.627 15.513 6.971 15.513 6.971C15.593 6.997 15.680 6.996 15.760 6.968C15.840 6.940 15.909 6.886 15.955 6.815C16.002 6.744 16.024 6.660 16.018 6.575C16.012 6.491 15.978 6.411 15.922 6.347C15.922 6.347 11.000 0.000 11.000 0.000C11.000 0.000 6.115 6.347 6.115 6.347C6.058 6.411 6.025 6.491 6.019 6.575C6.013 6.660 6.035 6.744 6.081 6.815C6.128 6.886 6.196 6.940 6.276 6.968C6.356 6.996 6.443 6.997 6.524 6.971C6.524 6.971 9.476 5.627 9.476 5.627C9.535 5.589 9.605 5.569 9.676 5.570C9.746 5.572 9.815 5.594 9.873 5.634C9.931 5.675 9.976 5.731 10.002 5.797C10.028 5.863 10.033 5.935 10.018 6.004C10.018 6.004 10.018 8.003 10.018 8.003C10.000 9.070 9.563 10.087 8.800 10.833C8.038 11.580 7.012 11.996 5.945 11.992C5.945 11.992 0.496 11.992 0.496 11.992C0.365 11.992 0.238 12.044 0.145 12.137C0.052 12.230 0.000 12.356 0.000 12.488C0.000 12.488 0.000 13.494 0.000 13.494C-0.000 13.560 0.013 13.624 0.038 13.684C0.063 13.745 0.099 13.799 0.146 13.845C0.192 13.892 0.246 13.928 0.307 13.953C0.367 13.978 0.432 13.991 0.497 13.991C0.497 13.991 2.000 13.989 2.000 13.989C2.000 13.989 2.000 13.992 2.000 13.992C2.000 13.992 5.945 13.992 5.945 13.992C7.542 13.995 9.076 13.368 10.214 12.247C11.351 11.125 12.000 9.600 12.018 8.003C12.018 8.003 12.020 7.992 12.020 7.992Z\" fill=\"currentColor\" transform=\"translate(2 2.008)\"/></svg>";
    readonly merge_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M6.015 8.007C6.015 8.007 4.015 8.007 4.015 8.007C4.015 8.007 4.015 16.502 4.015 16.502C4.015 16.568 4.028 16.634 4.053 16.695C4.079 16.756 4.116 16.812 4.163 16.859C4.210 16.906 4.265 16.943 4.327 16.968C4.388 16.994 4.453 17.007 4.520 17.007C4.520 17.007 5.510 17.007 5.510 17.007C5.644 17.007 5.772 16.954 5.867 16.859C5.962 16.764 6.015 16.636 6.015 16.502C6.015 16.502 6.015 8.007 6.015 8.007Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(4.011 0.993)\"/><path d=\"M0.506 6.966C0.506 6.966 3.458 5.623 3.458 5.623C3.518 5.584 3.587 5.565 3.658 5.566C3.729 5.567 3.797 5.590 3.855 5.630C3.914 5.670 3.958 5.727 3.984 5.793C4.010 5.859 4.016 5.931 4.001 6.000C4.001 6.000 4.002 6.000 4.002 6.000C4.002 6.000 4.002 7.965 4.002 7.965C4.009 9.133 4.326 10.277 4.920 11.282C5.515 12.287 6.365 13.116 7.384 13.686C7.384 13.686 11.695 16.371 11.695 16.371C11.751 16.406 11.813 16.429 11.878 16.440C11.943 16.451 12.010 16.449 12.074 16.434C12.139 16.419 12.199 16.392 12.253 16.353C12.307 16.315 12.352 16.266 12.387 16.210C12.387 16.210 12.913 15.366 12.913 15.366C12.948 15.310 12.972 15.248 12.982 15.183C12.993 15.118 12.991 15.051 12.976 14.987C12.961 14.922 12.934 14.862 12.895 14.808C12.857 14.754 12.808 14.708 12.752 14.674C12.752 14.674 8.447 11.992 8.447 11.992C7.728 11.605 7.123 11.036 6.694 10.341C6.264 9.646 6.024 8.851 5.999 8.035C5.999 8.035 6.001 5.999 6.001 5.999C5.986 5.930 5.992 5.858 6.018 5.792C6.044 5.726 6.088 5.670 6.146 5.630C6.204 5.589 6.273 5.567 6.344 5.566C6.414 5.565 6.484 5.585 6.543 5.623C6.543 5.623 9.495 6.966 9.495 6.966C9.576 6.993 9.663 6.992 9.743 6.964C9.823 6.936 9.891 6.882 9.938 6.811C9.984 6.740 10.006 6.656 10.000 6.571C9.994 6.487 9.960 6.406 9.904 6.343C9.904 6.343 5.001 0.000 5.001 0.000C5.001 0.000 0.097 6.343 0.097 6.343C0.041 6.406 0.007 6.487 0.001 6.571C-0.005 6.656 0.017 6.740 0.063 6.811C0.110 6.882 0.179 6.935 0.259 6.964C0.339 6.992 0.426 6.993 0.506 6.966Z\" fill=\"currentColor\" transform=\"translate(4.011 0.993)\"/></svg>";
    readonly merge_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M8.974 8.007C8.974 8.007 6.974 8.007 6.974 8.007C6.974 8.007 6.974 16.502 6.974 16.502C6.974 16.568 6.987 16.634 7.013 16.695C7.038 16.756 7.075 16.812 7.122 16.859C7.169 16.906 7.225 16.943 7.286 16.968C7.347 16.994 7.413 17.007 7.479 17.007C7.479 17.007 8.469 17.007 8.469 17.007C8.603 17.007 8.732 16.954 8.826 16.859C8.921 16.764 8.974 16.636 8.974 16.502C8.974 16.502 8.974 8.007 8.974 8.007Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(3.018 0.993)\"/><path d=\"M12.892 6.343C12.892 6.343 7.989 0.000 7.989 0.000C7.989 0.000 3.085 6.343 3.085 6.343C3.029 6.406 2.995 6.487 2.989 6.571C2.983 6.656 3.005 6.740 3.051 6.811C3.098 6.882 3.167 6.935 3.247 6.964C3.327 6.992 3.414 6.993 3.494 6.966C3.494 6.966 6.446 5.623 6.446 5.623C6.506 5.584 6.575 5.565 6.646 5.566C6.716 5.567 6.785 5.589 6.843 5.630C6.901 5.670 6.946 5.726 6.972 5.792C6.997 5.858 7.003 5.930 6.988 5.999C6.988 5.999 6.990 8.035 6.990 8.035C6.965 8.851 6.725 9.646 6.296 10.341C5.866 11.036 5.261 11.605 4.542 11.992C4.542 11.992 0.237 14.674 0.237 14.674C0.181 14.708 0.132 14.754 0.094 14.808C0.055 14.862 0.028 14.922 0.013 14.987C-0.002 15.051 -0.004 15.118 0.007 15.183C0.018 15.248 0.041 15.310 0.076 15.366C0.076 15.366 0.602 16.210 0.602 16.210C0.637 16.266 0.682 16.315 0.736 16.353C0.790 16.392 0.851 16.419 0.915 16.434C0.979 16.449 1.046 16.451 1.111 16.440C1.176 16.429 1.238 16.406 1.294 16.371C1.294 16.371 5.605 13.686 5.605 13.686C6.625 13.116 7.475 12.287 8.069 11.282C8.663 10.277 8.980 9.133 8.988 7.965C8.988 7.965 8.988 6.000 8.988 6.000C8.972 5.931 8.979 5.859 9.005 5.793C9.031 5.727 9.076 5.670 9.134 5.630C9.192 5.590 9.261 5.567 9.331 5.566C9.402 5.565 9.472 5.584 9.531 5.623C9.531 5.623 12.483 6.966 12.483 6.966C12.564 6.993 12.651 6.992 12.731 6.964C12.811 6.935 12.879 6.882 12.926 6.811C12.972 6.740 12.994 6.656 12.988 6.571C12.982 6.487 12.949 6.406 12.892 6.343Z\" fill=\"currentColor\" transform=\"translate(3.018 0.993)\"/></svg>";
    readonly merge_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M0 1 C0 0.448 0.448 0 1 0 C1.552 0 2 0.448 2 1 L2 6 C2 6.552 1.552 7 1 7 C0.448 7 0 6.552 0 6 Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(3.9 10.1) rotate(20 1 6)\"/><path class=\"mm2\" d=\"M0 1 C0 0.448 0.448 0 1 0 C1.552 0 2 0.448 2 1 L2 6 C2 6.552 1.552 7 1 7 C0.448 7 0 6.552 0 6 Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(14.1 10.1) rotate(-20 1 6)\"/><path d=\"M9.495 6.966C9.495 6.966 6.543 5.623 6.543 5.623C6.483 5.584 6.414 5.565 6.343 5.566C6.272 5.567 6.204 5.590 6.146 5.630C6.088 5.670 6.043 5.727 6.017 5.793C5.991 5.859 5.985 5.931 6.001 6.000C6.001 6.000 6.001 15.497 6.001 15.497C6.001 15.563 5.988 15.628 5.962 15.689C5.937 15.750 5.900 15.806 5.853 15.853C5.806 15.899 5.751 15.936 5.690 15.962C5.629 15.987 5.563 16.000 5.497 16.000C5.497 16.000 4.504 16.000 4.504 16.000C4.438 16.000 4.372 15.987 4.311 15.962C4.250 15.936 4.195 15.899 4.148 15.853C4.101 15.806 4.064 15.750 4.039 15.689C4.014 15.628 4.001 15.563 4.001 15.497C4.001 15.497 4.001 6.000 4.001 6.000C4.016 5.931 4.010 5.859 3.984 5.793C3.958 5.727 3.914 5.670 3.856 5.630C3.797 5.590 3.729 5.567 3.658 5.566C3.587 5.565 3.518 5.584 3.458 5.623C3.458 5.623 0.506 6.966 0.506 6.966C0.426 6.993 0.339 6.992 0.259 6.964C0.179 6.935 0.110 6.882 0.063 6.811C0.017 6.740 -0.005 6.656 0.001 6.571C0.007 6.487 0.041 6.406 0.097 6.343C0.097 6.343 5.001 0.000 5.001 0.000C5.001 0.000 9.904 6.343 9.904 6.343C9.960 6.406 9.994 6.487 10.000 6.571C10.006 6.656 9.984 6.740 9.938 6.811C9.891 6.882 9.823 6.935 9.743 6.964C9.662 6.992 9.575 6.993 9.495 6.966Z\" fill=\"currentColor\" transform=\"translate(5 2)\"/></svg>";
    readonly mini_roundabout_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M-1.750 0.000A1.750 1.750 0 1 0 1.750 0.000A1.750 1.750 0 1 0 -1.750 0.000Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -5.000 0.000L-3.000 0.000A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/><path d=\"M-4.000 -1.000L-7.750 -1.000L-7.750 1.000L-4.000 1.000Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/><path d=\"M-5.784 -4.494C-5.784 -4.494 -7.127 -1.542 -7.127 -1.542C-7.166 -1.482 -7.185 -1.413 -7.184 -1.342C-7.183 -1.271 -7.160 -1.203 -7.120 -1.145C-7.080 -1.087 -7.023 -1.042 -6.957 -1.016C-6.891 -0.990 -6.819 -0.984 -6.750 -1.000L-6.750 1.000C-6.819 0.985 -6.891 0.991 -6.957 1.017C-7.023 1.043 -7.080 1.087 -7.120 1.145C-7.160 1.204 -7.183 1.272 -7.184 1.343C-7.185 1.414 -7.166 1.483 -7.127 1.543C-7.127 1.543 -5.784 4.495 -5.784 4.495C-5.757 4.575 -5.758 4.662 -5.786 4.742C-5.815 4.822 -5.868 4.891 -5.939 4.938C-6.010 4.984 -6.094 5.006 -6.179 5.000C-6.263 4.994 -6.344 4.960 -6.407 4.904L-12.750 0.000L-6.407 -4.903C-6.344 -4.959 -6.263 -4.993 -6.179 -4.999C-6.094 -5.005 -6.010 -4.983 -5.939 -4.937C-5.868 -4.890 -5.815 -4.822 -5.786 -4.742C-5.758 -4.661 -5.757 -4.574 -5.784 -4.494Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/></svg>";
    readonly mini_roundabout_lht_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M-1.750 0.000A1.750 1.750 0 1 0 1.750 0.000A1.750 1.750 0 1 0 -1.750 0.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 15.500 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 15.500 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 5.000 0.000L3.000 0.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 15.500 9.000)\"/><path d=\"M4.000 1.000L7.750 1.000L7.750 -1.000L4.000 -1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 15.500 9.000)\"/><path d=\"M5.784 4.494C5.784 4.494 7.127 1.542 7.127 1.542C7.166 1.482 7.185 1.413 7.184 1.342C7.183 1.271 7.160 1.203 7.120 1.145C7.080 1.087 7.023 1.042 6.957 1.016C6.891 0.990 6.819 0.984 6.750 1.000L6.750 -1.000C6.819 -0.985 6.891 -0.991 6.957 -1.017C7.023 -1.043 7.080 -1.087 7.120 -1.145C7.160 -1.204 7.183 -1.272 7.184 -1.343C7.185 -1.414 7.166 -1.483 7.127 -1.543C7.127 -1.543 5.784 -4.495 5.784 -4.495C5.757 -4.575 5.758 -4.662 5.786 -4.742C5.815 -4.822 5.868 -4.891 5.939 -4.938C6.010 -4.984 6.094 -5.006 6.179 -5.000C6.263 -4.994 6.344 -4.960 6.407 -4.904L12.750 0.000L6.407 4.903C6.344 4.959 6.263 4.993 6.179 4.999C6.094 5.005 6.010 4.983 5.939 4.937C5.868 4.890 5.815 4.822 5.786 4.742C5.758 4.661 5.757 4.574 5.784 4.494Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 15.500 9.000)\"/></svg>";
    readonly mini_roundabout_lht_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M-1.750 0.000A1.750 1.750 0 1 0 1.750 0.000A1.750 1.750 0 1 0 -1.750 0.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -5.000 0.000L-3.000 0.000A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M-4.000 -1.000L-7.750 -1.000L-7.750 1.000L-4.000 1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M-5.784 -4.494C-5.784 -4.494 -7.127 -1.542 -7.127 -1.542C-7.166 -1.482 -7.185 -1.413 -7.184 -1.342C-7.183 -1.271 -7.160 -1.203 -7.120 -1.145C-7.080 -1.087 -7.023 -1.042 -6.957 -1.016C-6.891 -0.990 -6.819 -0.984 -6.750 -1.000L-6.750 1.000C-6.819 0.985 -6.891 0.991 -6.957 1.017C-7.023 1.043 -7.080 1.087 -7.120 1.145C-7.160 1.204 -7.183 1.272 -7.184 1.343C-7.185 1.414 -7.166 1.483 -7.127 1.543C-7.127 1.543 -5.784 4.495 -5.784 4.495C-5.757 4.575 -5.758 4.662 -5.786 4.742C-5.815 4.822 -5.868 4.891 -5.939 4.938C-6.010 4.984 -6.094 5.006 -6.179 5.000C-6.263 4.994 -6.344 4.960 -6.407 4.904L-12.750 0.000L-6.407 -4.903C-6.344 -4.959 -6.263 -4.993 -6.179 -4.999C-6.094 -5.005 -6.010 -4.983 -5.939 -4.937C-5.868 -4.890 -5.815 -4.822 -5.786 -4.742C-5.758 -4.661 -5.757 -4.574 -5.784 -4.494Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/></svg>";
    readonly mini_roundabout_lht_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M-1.750 0.000A1.750 1.750 0 1 0 1.750 0.000A1.750 1.750 0 1 0 -1.750 0.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M-1.000 2.828L-1.000 6.000Q-1.000 6.500 -0.500 6.500L0.500 6.500Q1.000 6.500 1.000 6.000L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 0.000 -5.000L0.000 -3.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M1.000 -4.000L1.000 -7.000L-1.000 -7.000L-1.000 -4.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M4.494 -5.034C4.494 -5.034 1.542 -6.377 1.542 -6.377C1.482 -6.416 1.413 -6.435 1.342 -6.434C1.271 -6.433 1.203 -6.410 1.145 -6.370C1.087 -6.330 1.042 -6.273 1.016 -6.207C0.990 -6.141 0.984 -6.069 1.000 -6.000L-1.000 -6.000C-0.985 -6.069 -0.991 -6.141 -1.017 -6.207C-1.043 -6.273 -1.087 -6.330 -1.145 -6.370C-1.204 -6.410 -1.272 -6.433 -1.343 -6.434C-1.414 -6.435 -1.483 -6.416 -1.543 -6.377C-1.543 -6.377 -4.495 -5.034 -4.495 -5.034C-4.575 -5.007 -4.662 -5.008 -4.742 -5.036C-4.822 -5.065 -4.891 -5.118 -4.938 -5.189C-4.984 -5.260 -5.006 -5.344 -5.000 -5.429C-4.994 -5.513 -4.960 -5.594 -4.904 -5.657L0.000 -12.000L4.903 -5.657C4.959 -5.594 4.993 -5.513 4.999 -5.429C5.005 -5.344 4.983 -5.260 4.937 -5.189C4.890 -5.118 4.822 -5.065 4.742 -5.036C4.661 -5.008 4.574 -5.007 4.494 -5.034Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/></svg>";
    readonly mini_roundabout_lht_uturn: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M-1.750 0.000A1.750 1.750 0 1 0 1.750 0.000A1.750 1.750 0 1 0 -1.750 0.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 8.000 6.000)\"/><path d=\"M2.750 1.199L2.750 12.300Q2.750 12.800 3.250 12.800L4.250 12.800Q4.750 12.800 4.750 12.300L4.750 1.199Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 8.000 6.000)\"/><path d=\"M4.672 1.782A5.000 5.000 0 1 0 -4.672 1.782L-2.803 1.069A3.000 3.000 0 1 1 2.803 1.069Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 8.000 6.000)\"/><path d=\"M-4.750 1.199L-4.750 7.800L-2.750 7.800L-2.750 1.199Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 8.000 6.000)\"/><path d=\"M-8.244 5.834C-8.244 5.834 -5.292 7.177 -5.292 7.177C-5.232 7.216 -5.163 7.235 -5.092 7.234C-5.021 7.233 -4.953 7.210 -4.895 7.170C-4.837 7.130 -4.792 7.073 -4.766 7.007C-4.740 6.941 -4.734 6.869 -4.750 6.800L-2.750 6.800C-2.765 6.869 -2.759 6.941 -2.733 7.007C-2.707 7.073 -2.663 7.130 -2.605 7.170C-2.546 7.210 -2.478 7.233 -2.407 7.234C-2.336 7.235 -2.267 7.216 -2.207 7.177C-2.207 7.177 0.745 5.834 0.745 5.834C0.825 5.807 0.912 5.808 0.992 5.836C1.072 5.865 1.141 5.918 1.188 5.989C1.234 6.060 1.256 6.144 1.250 6.229C1.244 6.313 1.210 6.394 1.154 6.457L-3.750 12.800L-8.653 6.457C-8.709 6.394 -8.743 6.313 -8.749 6.229C-8.755 6.144 -8.733 6.060 -8.687 5.989C-8.640 5.918 -8.572 5.865 -8.492 5.836C-8.411 5.808 -8.324 5.807 -8.244 5.834Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 8.000 6.000)\"/></svg>";
    readonly mini_roundabout_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M-1.750 0.000A1.750 1.750 0 1 0 1.750 0.000A1.750 1.750 0 1 0 -1.750 0.000Z\" fill=\"currentColor\" transform=\"translate(4.500 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(4.500 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 5.000 0.000L3.000 0.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(4.500 9.000)\"/><path d=\"M4.000 1.000L7.750 1.000L7.750 -1.000L4.000 -1.000Z\" fill=\"currentColor\" transform=\"translate(4.500 9.000)\"/><path d=\"M5.784 4.494C5.784 4.494 7.127 1.542 7.127 1.542C7.166 1.482 7.185 1.413 7.184 1.342C7.183 1.271 7.160 1.203 7.120 1.145C7.080 1.087 7.023 1.042 6.957 1.016C6.891 0.990 6.819 0.984 6.750 1.000L6.750 -1.000C6.819 -0.985 6.891 -0.991 6.957 -1.017C7.023 -1.043 7.080 -1.087 7.120 -1.145C7.160 -1.204 7.183 -1.272 7.184 -1.343C7.185 -1.414 7.166 -1.483 7.127 -1.543C7.127 -1.543 5.784 -4.495 5.784 -4.495C5.757 -4.575 5.758 -4.662 5.786 -4.742C5.815 -4.822 5.868 -4.891 5.939 -4.938C6.010 -4.984 6.094 -5.006 6.179 -5.000C6.263 -4.994 6.344 -4.960 6.407 -4.904L12.750 0.000L6.407 4.903C6.344 4.959 6.263 4.993 6.179 4.999C6.094 5.005 6.010 4.983 5.939 4.937C5.868 4.890 5.815 4.822 5.786 4.742C5.758 4.661 5.757 4.574 5.784 4.494Z\" fill=\"currentColor\" transform=\"translate(4.500 9.000)\"/></svg>";
    readonly mini_roundabout_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M-1.750 0.000A1.750 1.750 0 1 0 1.750 0.000A1.750 1.750 0 1 0 -1.750 0.000Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/><path d=\"M-1.000 2.828L-1.000 6.000Q-1.000 6.500 -0.500 6.500L0.500 6.500Q1.000 6.500 1.000 6.000L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 0.000 -5.000L0.000 -3.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/><path d=\"M1.000 -4.000L1.000 -7.000L-1.000 -7.000L-1.000 -4.000Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/><path d=\"M4.494 -5.034C4.494 -5.034 1.542 -6.377 1.542 -6.377C1.482 -6.416 1.413 -6.435 1.342 -6.434C1.271 -6.433 1.203 -6.410 1.145 -6.370C1.087 -6.330 1.042 -6.273 1.016 -6.207C0.990 -6.141 0.984 -6.069 1.000 -6.000L-1.000 -6.000C-0.985 -6.069 -0.991 -6.141 -1.017 -6.207C-1.043 -6.273 -1.087 -6.330 -1.145 -6.370C-1.204 -6.410 -1.272 -6.433 -1.343 -6.434C-1.414 -6.435 -1.483 -6.416 -1.543 -6.377C-1.543 -6.377 -4.495 -5.034 -4.495 -5.034C-4.575 -5.007 -4.662 -5.008 -4.742 -5.036C-4.822 -5.065 -4.891 -5.118 -4.938 -5.189C-4.984 -5.260 -5.006 -5.344 -5.000 -5.429C-4.994 -5.513 -4.960 -5.594 -4.904 -5.657L0.000 -12.000L4.903 -5.657C4.959 -5.594 4.993 -5.513 4.999 -5.429C5.005 -5.344 4.983 -5.260 4.937 -5.189C4.890 -5.118 4.822 -5.065 4.742 -5.036C4.661 -5.008 4.574 -5.007 4.494 -5.034Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/></svg>";
    readonly mini_roundabout_uturn: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M-1.750 0.000A1.750 1.750 0 1 0 1.750 0.000A1.750 1.750 0 1 0 -1.750 0.000Z\" fill=\"currentColor\" transform=\"translate(12.000 6.000)\"/><path d=\"M2.750 1.199L2.750 12.300Q2.750 12.800 3.250 12.800L4.250 12.800Q4.750 12.800 4.750 12.300L4.750 1.199Z\" fill=\"currentColor\" transform=\"translate(12.000 6.000)\"/><path d=\"M4.672 1.782A5.000 5.000 0 1 0 -4.672 1.782L-2.803 1.069A3.000 3.000 0 1 1 2.803 1.069Z\" fill=\"currentColor\" transform=\"translate(12.000 6.000)\"/><path d=\"M-4.750 1.199L-4.750 7.800L-2.750 7.800L-2.750 1.199Z\" fill=\"currentColor\" transform=\"translate(12.000 6.000)\"/><path d=\"M-8.244 5.834C-8.244 5.834 -5.292 7.177 -5.292 7.177C-5.232 7.216 -5.163 7.235 -5.092 7.234C-5.021 7.233 -4.953 7.210 -4.895 7.170C-4.837 7.130 -4.792 7.073 -4.766 7.007C-4.740 6.941 -4.734 6.869 -4.750 6.800L-2.750 6.800C-2.765 6.869 -2.759 6.941 -2.733 7.007C-2.707 7.073 -2.663 7.130 -2.605 7.170C-2.546 7.210 -2.478 7.233 -2.407 7.234C-2.336 7.235 -2.267 7.216 -2.207 7.177C-2.207 7.177 0.745 5.834 0.745 5.834C0.825 5.807 0.912 5.808 0.992 5.836C1.072 5.865 1.141 5.918 1.188 5.989C1.234 6.060 1.256 6.144 1.250 6.229C1.244 6.313 1.210 6.394 1.154 6.457L-3.750 12.800L-8.653 6.457C-8.709 6.394 -8.743 6.313 -8.749 6.229C-8.755 6.144 -8.733 6.060 -8.687 5.989C-8.640 5.918 -8.572 5.865 -8.492 5.836C-8.411 5.808 -8.324 5.807 -8.244 5.834Z\" fill=\"currentColor\" transform=\"translate(12.000 6.000)\"/></svg>";
    readonly new_name_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M7.992 3.999C7.992 3.999 8.003 4.001 8.003 4.001C9.600 4.019 11.125 4.668 12.247 5.805C13.368 6.942 13.995 8.477 13.992 10.074C13.992 10.074 13.992 14.019 13.992 14.019C13.992 14.019 13.989 14.019 13.989 14.019C13.989 14.019 13.991 15.522 13.991 15.522C13.991 15.587 13.978 15.652 13.953 15.712C13.928 15.772 13.892 15.827 13.845 15.873C13.799 15.919 13.745 15.956 13.684 15.981C13.624 16.006 13.560 16.019 13.494 16.019C13.494 16.019 12.488 16.019 12.488 16.019C12.356 16.019 12.230 15.967 12.137 15.874C12.044 15.780 11.992 15.654 11.992 15.523C11.992 15.523 11.992 10.074 11.992 10.074C11.996 9.007 11.580 7.981 10.833 7.219C10.087 6.456 9.070 6.019 8.003 6.001C8.003 6.001 6.004 6.001 6.004 6.001C5.935 5.985 5.863 5.991 5.797 6.017C5.731 6.043 5.675 6.088 5.634 6.146C5.594 6.204 5.572 6.272 5.570 6.343C5.569 6.414 5.589 6.483 5.627 6.543C5.627 6.543 6.971 9.495 6.971 9.495C6.997 9.576 6.996 9.663 6.968 9.743C6.940 9.823 6.886 9.891 6.815 9.938C6.744 9.984 6.660 10.006 6.575 10.000C6.491 9.994 6.411 9.960 6.347 9.904C6.347 9.904 0.000 5.019 0.000 5.019C0.000 5.019 6.347 0.097 6.347 0.097C6.411 0.041 6.491 0.007 6.575 0.001C6.660 -0.005 6.744 0.017 6.815 0.063C6.886 0.110 6.940 0.179 6.968 0.259C6.996 0.339 6.997 0.426 6.971 0.506C6.971 0.506 5.627 3.458 5.627 3.458C5.589 3.518 5.569 3.587 5.570 3.658C5.572 3.729 5.594 3.797 5.634 3.855C5.675 3.914 5.731 3.958 5.797 3.984C5.863 4.010 5.935 4.016 6.004 4.001C6.004 4.001 7.992 4.001 7.992 4.001Z\" fill=\"currentColor\" transform=\"translate(2.008 1.981)\"/></svg>";
    readonly new_name_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M5.989 6.001C4.922 6.019 3.905 6.456 3.159 7.219C2.412 7.981 1.996 9.007 2.000 10.074C2.000 10.074 2.000 15.523 2.000 15.523C2.000 15.654 1.948 15.780 1.855 15.874C1.762 15.967 1.635 16.019 1.504 16.019C1.504 16.019 0.497 16.019 0.497 16.019C0.432 16.019 0.368 16.006 0.307 15.981C0.247 15.956 0.192 15.919 0.146 15.873C0.100 15.827 0.064 15.772 0.039 15.712C0.014 15.652 0.001 15.587 0.001 15.522C0.001 15.522 0.003 14.019 0.003 14.019C0.003 14.019 0.000 14.019 0.000 14.019C0.000 14.019 0.000 10.074 0.000 10.074C-0.004 8.477 0.624 6.942 1.745 5.805C2.867 4.668 4.392 4.019 5.989 4.001C5.989 4.001 6.000 3.999 6.000 3.999C6.000 3.999 6.000 4.001 6.000 4.001C6.000 4.001 7.988 4.001 7.988 4.001C8.057 4.016 8.129 4.010 8.195 3.984C8.260 3.958 8.317 3.914 8.358 3.855C8.398 3.797 8.420 3.729 8.422 3.658C8.423 3.587 8.403 3.518 8.365 3.458C8.365 3.458 7.021 0.506 7.021 0.506C6.995 0.426 6.996 0.339 7.024 0.259C7.052 0.179 7.106 0.110 7.177 0.063C7.247 0.017 7.332 -0.005 7.416 0.001C7.501 0.007 7.581 0.041 7.645 0.097C7.645 0.097 13.992 5.019 13.992 5.019C13.992 5.019 7.645 9.904 7.645 9.904C7.581 9.960 7.501 9.994 7.416 10.000C7.332 10.006 7.247 9.984 7.177 9.938C7.106 9.891 7.052 9.823 7.024 9.743C6.996 9.663 6.995 9.576 7.021 9.495C7.021 9.495 8.365 6.543 8.365 6.543C8.403 6.483 8.423 6.414 8.422 6.343C8.420 6.272 8.398 6.204 8.358 6.146C8.317 6.088 8.260 6.043 8.195 6.017C8.129 5.991 8.057 5.985 7.988 6.001C7.988 6.001 5.989 6.001 5.989 6.001Z\" fill=\"currentColor\" transform=\"translate(4 1.981)\"/></svg>";
    readonly new_name_sharp_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M13.481 15.011C13.349 15.011 13.223 14.959 13.129 14.865C13.036 14.772 12.983 14.645 12.983 14.513C12.983 14.513 12.983 2.015 12.983 2.015C12.983 2.015 12.704 2.009 12.704 2.009C12.317 1.974 11.928 2.026 11.565 2.163C11.202 2.300 10.875 2.517 10.608 2.799C10.608 2.799 5.213 7.412 5.213 7.412C5.155 7.447 5.109 7.498 5.080 7.559C5.051 7.620 5.041 7.687 5.049 7.754C5.058 7.821 5.086 7.884 5.130 7.935C5.173 7.986 5.231 8.024 5.295 8.043C5.295 8.043 8.224 9.437 8.224 9.437C8.296 9.481 8.351 9.549 8.381 9.628C8.411 9.707 8.414 9.794 8.390 9.875C8.366 9.957 8.316 10.028 8.247 10.078C8.178 10.127 8.095 10.153 8.010 10.151C8.010 10.151 0.000 10.483 0.000 10.483C0.000 10.483 1.696 2.647 1.696 2.647C1.708 2.564 1.748 2.486 1.809 2.427C1.870 2.368 1.948 2.331 2.032 2.320C2.117 2.310 2.202 2.328 2.275 2.372C2.348 2.415 2.405 2.481 2.436 2.559C2.436 2.559 3.309 5.683 3.309 5.683C3.318 5.753 3.348 5.819 3.394 5.872C3.441 5.926 3.502 5.964 3.570 5.982C3.639 6.001 3.711 5.998 3.778 5.976C3.845 5.953 3.904 5.911 3.947 5.855C3.947 5.855 3.951 5.859 3.951 5.859C3.951 5.859 9.343 1.250 9.343 1.250C9.790 0.820 10.322 0.487 10.904 0.273C11.487 0.059 12.108 -0.031 12.728 0.009C12.728 0.009 12.992 0.011 12.992 0.011C13.257 0.002 13.521 0.048 13.768 0.146C14.015 0.244 14.239 0.392 14.426 0.580C14.792 0.977 14.992 1.500 14.983 2.040C14.983 2.040 14.983 14.513 14.983 14.513C14.983 14.579 14.971 14.643 14.945 14.704C14.920 14.764 14.884 14.819 14.838 14.865C14.791 14.912 14.736 14.948 14.676 14.973C14.616 14.998 14.551 15.011 14.486 15.011C14.486 15.011 13.481 15.011 13.481 15.011Z\" fill=\"currentColor\" transform=\"translate(2.017 2.989)\"/></svg>";
    readonly new_name_sharp_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M0.498 15.011C0.432 15.011 0.368 14.998 0.307 14.973C0.247 14.948 0.192 14.912 0.146 14.865C0.100 14.819 0.063 14.764 0.038 14.704C0.013 14.643 -0.000 14.579 0.000 14.513C0.000 14.513 0.000 2.040 0.000 2.040C-0.008 1.500 0.191 0.977 0.558 0.580C0.745 0.392 0.969 0.244 1.215 0.146C1.462 0.048 1.726 0.002 1.992 0.011C1.992 0.011 2.256 0.009 2.256 0.009C2.875 -0.031 3.496 0.059 4.079 0.273C4.662 0.487 5.194 0.820 5.641 1.250C5.641 1.250 11.033 5.859 11.033 5.859C11.033 5.859 11.036 5.855 11.036 5.855C11.080 5.911 11.138 5.953 11.205 5.976C11.272 5.998 11.345 6.001 11.413 5.982C11.481 5.964 11.543 5.926 11.589 5.872C11.636 5.819 11.665 5.753 11.674 5.683C11.674 5.683 12.547 2.559 12.547 2.559C12.579 2.481 12.636 2.415 12.709 2.372C12.782 2.328 12.867 2.310 12.951 2.320C13.035 2.331 13.114 2.368 13.175 2.427C13.235 2.486 13.275 2.564 13.288 2.647C13.288 2.647 14.983 10.483 14.983 10.483C14.983 10.483 6.973 10.151 6.973 10.151C6.888 10.153 6.805 10.127 6.736 10.078C6.668 10.028 6.618 9.957 6.593 9.875C6.569 9.794 6.572 9.707 6.602 9.628C6.632 9.549 6.687 9.481 6.759 9.437C6.759 9.437 9.688 8.043 9.688 8.043C9.753 8.024 9.810 7.986 9.854 7.935C9.897 7.884 9.925 7.821 9.934 7.754C9.943 7.687 9.932 7.620 9.903 7.559C9.874 7.498 9.828 7.447 9.771 7.412C9.771 7.412 4.375 2.799 4.375 2.799C4.109 2.517 3.781 2.300 3.418 2.163C3.055 2.026 2.666 1.974 2.280 2.009C2.280 2.009 2.000 2.015 2.000 2.015C2.000 2.015 2.000 14.513 2.000 14.513C2.000 14.645 1.948 14.772 1.854 14.865C1.761 14.959 1.634 15.011 1.502 15.011C1.502 15.011 0.498 15.011 0.498 15.011Z\" fill=\"currentColor\" transform=\"translate(3 2.989)\"/></svg>";
    readonly new_name_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.986 11.043C9.986 11.043 9.986 14.504 9.986 14.504C9.986 14.635 9.934 14.762 9.841 14.855C9.748 14.948 9.621 15.000 9.490 15.000C9.490 15.000 8.483 15.000 8.483 15.000C8.418 15.000 8.353 14.987 8.293 14.962C8.233 14.937 8.178 14.901 8.132 14.854C8.086 14.808 8.050 14.754 8.025 14.693C8.000 14.633 7.987 14.568 7.987 14.503C7.987 14.503 7.992 10.896 7.992 10.896C8.038 10.125 7.913 9.353 7.625 8.636C7.337 7.920 6.894 7.276 6.327 6.752C6.327 6.752 3.879 4.686 3.879 4.686C3.836 4.629 3.778 4.586 3.711 4.563C3.645 4.539 3.572 4.536 3.504 4.553C3.435 4.571 3.373 4.608 3.326 4.660C3.279 4.713 3.248 4.778 3.238 4.849C3.238 4.849 2.320 7.959 2.320 7.959C2.287 8.037 2.229 8.102 2.155 8.144C2.082 8.186 1.996 8.203 1.912 8.192C1.828 8.181 1.750 8.142 1.690 8.082C1.630 8.022 1.592 7.944 1.580 7.860C1.580 7.860 0.000 0.000 0.000 0.000C0.000 0.000 8.005 0.450 8.005 0.450C8.090 0.449 8.172 0.476 8.240 0.527C8.308 0.578 8.357 0.649 8.380 0.731C8.403 0.813 8.399 0.900 8.368 0.978C8.337 1.057 8.280 1.124 8.208 1.167C8.208 1.167 5.259 2.518 5.259 2.518C5.191 2.538 5.130 2.577 5.085 2.631C5.040 2.686 5.012 2.752 5.004 2.823C4.997 2.893 5.010 2.964 5.043 3.027C5.076 3.089 5.126 3.141 5.189 3.175C5.189 3.175 7.646 5.249 7.646 5.249C8.443 5.979 9.067 6.878 9.472 7.881C9.877 8.883 10.053 9.964 9.986 11.043Z\" fill=\"currentColor\" transform=\"translate(5 3)\"/></svg>";
    readonly new_name_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M2.354 5.249C2.354 5.249 4.811 3.175 4.811 3.175C4.873 3.141 4.924 3.089 4.957 3.027C4.990 2.964 5.003 2.893 4.996 2.823C4.988 2.752 4.960 2.686 4.915 2.631C4.869 2.577 4.809 2.538 4.741 2.518C4.741 2.518 1.792 1.167 1.792 1.167C1.719 1.124 1.663 1.057 1.632 0.978C1.601 0.900 1.596 0.813 1.619 0.731C1.642 0.649 1.692 0.578 1.760 0.527C1.827 0.476 1.910 0.449 1.995 0.450C1.995 0.450 10.000 0.000 10.000 0.000C10.000 0.000 8.419 7.860 8.419 7.860C8.408 7.944 8.369 8.022 8.309 8.082C8.249 8.142 8.171 8.181 8.087 8.192C8.003 8.203 7.918 8.186 7.844 8.144C7.771 8.102 7.713 8.037 7.680 7.959C7.680 7.959 6.762 4.849 6.762 4.849C6.752 4.778 6.721 4.713 6.674 4.660C6.626 4.608 6.564 4.571 6.496 4.553C6.427 4.536 6.355 4.539 6.288 4.563C6.222 4.586 6.163 4.629 6.121 4.686C6.121 4.686 3.673 6.751 3.673 6.751C3.106 7.276 2.663 7.920 2.375 8.636C2.087 9.353 1.962 10.125 2.008 10.895C2.008 10.895 2.013 14.503 2.013 14.503C2.013 14.568 2.000 14.633 1.975 14.693C1.950 14.754 1.914 14.808 1.868 14.854C1.821 14.901 1.767 14.937 1.707 14.962C1.646 14.987 1.582 15.000 1.516 15.000C1.516 15.000 0.510 15.000 0.510 15.000C0.378 15.000 0.252 14.948 0.159 14.855C0.066 14.762 0.014 14.635 0.014 14.504C0.014 14.504 0.014 11.043 0.014 11.043C-0.053 9.964 0.123 8.883 0.528 7.881C0.932 6.878 1.556 5.979 2.354 5.249Z\" fill=\"currentColor\" transform=\"translate(5 3)\"/></svg>";
    readonly new_name_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.495 6.966C9.495 6.966 6.543 5.623 6.543 5.623C6.483 5.584 6.414 5.565 6.343 5.566C6.272 5.567 6.204 5.590 6.146 5.630C6.088 5.670 6.043 5.727 6.017 5.793C5.991 5.859 5.985 5.931 6.001 6.000C6.001 6.000 6.001 15.497 6.001 15.497C6.001 15.563 5.988 15.628 5.962 15.689C5.937 15.750 5.900 15.806 5.853 15.853C5.806 15.899 5.751 15.936 5.690 15.962C5.629 15.987 5.563 16.000 5.497 16.000C5.497 16.000 4.504 16.000 4.504 16.000C4.438 16.000 4.372 15.987 4.311 15.962C4.250 15.936 4.195 15.899 4.148 15.853C4.101 15.806 4.064 15.750 4.039 15.689C4.014 15.628 4.001 15.563 4.001 15.497C4.001 15.497 4.001 6.000 4.001 6.000C4.016 5.931 4.010 5.859 3.984 5.793C3.958 5.727 3.914 5.670 3.856 5.630C3.797 5.590 3.729 5.567 3.658 5.566C3.587 5.565 3.518 5.584 3.458 5.623C3.458 5.623 0.506 6.966 0.506 6.966C0.426 6.993 0.339 6.992 0.259 6.964C0.179 6.935 0.110 6.882 0.063 6.811C0.017 6.740 -0.005 6.656 0.001 6.571C0.007 6.487 0.041 6.406 0.097 6.343C0.097 6.343 5.001 0.000 5.001 0.000C5.001 0.000 9.904 6.343 9.904 6.343C9.960 6.406 9.994 6.487 10.000 6.571C10.006 6.656 9.984 6.740 9.938 6.811C9.891 6.882 9.823 6.935 9.743 6.964C9.662 6.992 9.575 6.993 9.495 6.966Z\" fill=\"currentColor\" transform=\"translate(5.009 2)\"/></svg>";
    readonly notification_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M7.992 3.999C7.992 3.999 8.003 4.001 8.003 4.001C9.600 4.019 11.125 4.668 12.247 5.805C13.368 6.942 13.995 8.477 13.992 10.074C13.992 10.074 13.992 14.019 13.992 14.019C13.992 14.019 13.989 14.019 13.989 14.019C13.989 14.019 13.991 15.522 13.991 15.522C13.991 15.587 13.978 15.652 13.953 15.712C13.928 15.772 13.892 15.827 13.845 15.873C13.799 15.919 13.745 15.956 13.684 15.981C13.624 16.006 13.560 16.019 13.494 16.019C13.494 16.019 12.488 16.019 12.488 16.019C12.356 16.019 12.230 15.967 12.137 15.874C12.044 15.780 11.992 15.654 11.992 15.523C11.992 15.523 11.992 10.074 11.992 10.074C11.996 9.007 11.580 7.981 10.833 7.219C10.087 6.456 9.070 6.019 8.003 6.001C8.003 6.001 6.004 6.001 6.004 6.001C5.935 5.985 5.863 5.991 5.797 6.017C5.731 6.043 5.675 6.088 5.634 6.146C5.594 6.204 5.572 6.272 5.570 6.343C5.569 6.414 5.589 6.483 5.627 6.543C5.627 6.543 6.971 9.495 6.971 9.495C6.997 9.576 6.996 9.663 6.968 9.743C6.940 9.823 6.886 9.891 6.815 9.938C6.744 9.984 6.660 10.006 6.575 10.000C6.491 9.994 6.411 9.960 6.347 9.904C6.347 9.904 0.000 5.019 0.000 5.019C0.000 5.019 6.347 0.097 6.347 0.097C6.411 0.041 6.491 0.007 6.575 0.001C6.660 -0.005 6.744 0.017 6.815 0.063C6.886 0.110 6.940 0.179 6.968 0.259C6.996 0.339 6.997 0.426 6.971 0.506C6.971 0.506 5.627 3.458 5.627 3.458C5.589 3.518 5.569 3.587 5.570 3.658C5.572 3.729 5.594 3.797 5.634 3.855C5.675 3.914 5.731 3.958 5.797 3.984C5.863 4.010 5.935 4.016 6.004 4.001C6.004 4.001 7.992 4.001 7.992 4.001Z\" fill=\"currentColor\" transform=\"translate(2.008 1.981)\"/></svg>";
    readonly notification_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M5.989 6.001C4.922 6.019 3.905 6.456 3.159 7.219C2.412 7.981 1.996 9.007 2.000 10.074C2.000 10.074 2.000 15.523 2.000 15.523C2.000 15.654 1.948 15.780 1.855 15.874C1.762 15.967 1.635 16.019 1.504 16.019C1.504 16.019 0.497 16.019 0.497 16.019C0.432 16.019 0.368 16.006 0.307 15.981C0.247 15.956 0.192 15.919 0.146 15.873C0.100 15.827 0.064 15.772 0.039 15.712C0.014 15.652 0.001 15.587 0.001 15.522C0.001 15.522 0.003 14.019 0.003 14.019C0.003 14.019 0.000 14.019 0.000 14.019C0.000 14.019 0.000 10.074 0.000 10.074C-0.004 8.477 0.624 6.942 1.745 5.805C2.867 4.668 4.392 4.019 5.989 4.001C5.989 4.001 6.000 3.999 6.000 3.999C6.000 3.999 6.000 4.001 6.000 4.001C6.000 4.001 7.988 4.001 7.988 4.001C8.057 4.016 8.129 4.010 8.195 3.984C8.260 3.958 8.317 3.914 8.358 3.855C8.398 3.797 8.420 3.729 8.422 3.658C8.423 3.587 8.403 3.518 8.365 3.458C8.365 3.458 7.021 0.506 7.021 0.506C6.995 0.426 6.996 0.339 7.024 0.259C7.052 0.179 7.106 0.110 7.177 0.063C7.247 0.017 7.332 -0.005 7.416 0.001C7.501 0.007 7.581 0.041 7.645 0.097C7.645 0.097 13.992 5.019 13.992 5.019C13.992 5.019 7.645 9.904 7.645 9.904C7.581 9.960 7.501 9.994 7.416 10.000C7.332 10.006 7.247 9.984 7.177 9.938C7.106 9.891 7.052 9.823 7.024 9.743C6.996 9.663 6.995 9.576 7.021 9.495C7.021 9.495 8.365 6.543 8.365 6.543C8.403 6.483 8.423 6.414 8.422 6.343C8.420 6.272 8.398 6.204 8.358 6.146C8.317 6.088 8.260 6.043 8.195 6.017C8.129 5.991 8.057 5.985 7.988 6.001C7.988 6.001 5.989 6.001 5.989 6.001Z\" fill=\"currentColor\" transform=\"translate(4 1.981)\"/></svg>";
    readonly notification_sharp_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M13.481 15.011C13.349 15.011 13.223 14.959 13.129 14.865C13.036 14.772 12.983 14.645 12.983 14.513C12.983 14.513 12.983 2.015 12.983 2.015C12.983 2.015 12.704 2.009 12.704 2.009C12.317 1.973 11.928 2.026 11.565 2.163C11.202 2.300 10.875 2.517 10.608 2.799C10.608 2.799 5.213 7.411 5.213 7.411C5.155 7.447 5.109 7.498 5.080 7.559C5.051 7.619 5.041 7.687 5.049 7.754C5.058 7.821 5.086 7.884 5.130 7.935C5.173 7.986 5.231 8.024 5.295 8.043C5.295 8.043 8.224 9.437 8.224 9.437C8.296 9.481 8.351 9.549 8.381 9.628C8.411 9.707 8.414 9.794 8.390 9.875C8.366 9.957 8.316 10.028 8.247 10.078C8.178 10.127 8.095 10.153 8.010 10.151C8.010 10.151 0.000 10.483 0.000 10.483C0.000 10.483 1.696 2.647 1.696 2.647C1.708 2.564 1.748 2.486 1.809 2.427C1.870 2.368 1.948 2.330 2.032 2.320C2.117 2.310 2.202 2.328 2.275 2.371C2.348 2.415 2.405 2.481 2.436 2.559C2.436 2.559 3.309 5.683 3.309 5.683C3.318 5.753 3.348 5.819 3.394 5.872C3.441 5.925 3.502 5.964 3.570 5.982C3.639 6.001 3.711 5.998 3.778 5.976C3.845 5.953 3.904 5.911 3.947 5.855C3.947 5.855 3.951 5.859 3.951 5.859C3.951 5.859 9.343 1.250 9.343 1.250C9.790 0.820 10.322 0.487 10.904 0.273C11.487 0.059 12.108 -0.031 12.728 0.009C12.728 0.009 12.992 0.011 12.992 0.011C13.257 0.002 13.521 0.048 13.768 0.146C14.015 0.244 14.239 0.392 14.426 0.580C14.792 0.977 14.992 1.500 14.983 2.040C14.983 2.040 14.983 14.513 14.983 14.513C14.983 14.579 14.971 14.643 14.945 14.704C14.920 14.764 14.884 14.819 14.838 14.865C14.791 14.912 14.736 14.948 14.676 14.973C14.616 14.998 14.551 15.011 14.486 15.011C14.486 15.011 13.481 15.011 13.481 15.011Z\" fill=\"currentColor\" transform=\"translate(2.017 2.984)\"/></svg>";
    readonly notification_sharp_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M0.498 15.011C0.432 15.011 0.368 14.998 0.307 14.973C0.247 14.948 0.192 14.912 0.146 14.865C0.100 14.819 0.063 14.764 0.038 14.704C0.013 14.643 -0.000 14.579 0.000 14.513C0.000 14.513 0.000 2.040 0.000 2.040C-0.008 1.500 0.191 0.977 0.558 0.580C0.745 0.392 0.969 0.244 1.215 0.146C1.462 0.048 1.726 0.002 1.992 0.011C1.992 0.011 2.256 0.009 2.256 0.009C2.875 -0.031 3.496 0.059 4.079 0.273C4.662 0.487 5.194 0.820 5.641 1.250C5.641 1.250 11.033 5.859 11.033 5.859C11.033 5.859 11.036 5.855 11.036 5.855C11.080 5.911 11.138 5.953 11.205 5.976C11.272 5.998 11.345 6.001 11.413 5.982C11.481 5.964 11.543 5.926 11.589 5.872C11.636 5.819 11.665 5.753 11.674 5.683C11.674 5.683 12.547 2.559 12.547 2.559C12.579 2.481 12.636 2.415 12.709 2.372C12.782 2.328 12.867 2.310 12.951 2.320C13.035 2.331 13.114 2.368 13.175 2.427C13.235 2.486 13.275 2.564 13.288 2.647C13.288 2.647 14.983 10.483 14.983 10.483C14.983 10.483 6.973 10.151 6.973 10.151C6.888 10.153 6.805 10.127 6.736 10.078C6.668 10.028 6.618 9.957 6.593 9.875C6.569 9.794 6.572 9.707 6.602 9.628C6.632 9.549 6.687 9.481 6.759 9.437C6.759 9.437 9.688 8.043 9.688 8.043C9.753 8.024 9.810 7.986 9.854 7.935C9.897 7.884 9.925 7.821 9.934 7.754C9.943 7.687 9.932 7.620 9.903 7.559C9.874 7.498 9.828 7.447 9.771 7.412C9.771 7.412 4.375 2.799 4.375 2.799C4.109 2.517 3.781 2.300 3.418 2.163C3.055 2.026 2.666 1.974 2.280 2.009C2.280 2.009 2.000 2.015 2.000 2.015C2.000 2.015 2.000 14.513 2.000 14.513C2.000 14.645 1.948 14.772 1.854 14.865C1.761 14.959 1.634 15.011 1.502 15.011C1.502 15.011 0.498 15.011 0.498 15.011Z\" fill=\"currentColor\" transform=\"translate(3 2.984)\"/></svg>";
    readonly notification_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.986 11.043C9.986 11.043 9.986 14.504 9.986 14.504C9.986 14.635 9.934 14.762 9.841 14.855C9.748 14.948 9.621 15.000 9.490 15.000C9.490 15.000 8.483 15.000 8.483 15.000C8.418 15.000 8.353 14.987 8.293 14.962C8.233 14.937 8.178 14.901 8.132 14.854C8.086 14.808 8.050 14.754 8.025 14.693C8.000 14.633 7.987 14.568 7.987 14.503C7.987 14.503 7.992 10.896 7.992 10.896C8.038 10.125 7.913 9.353 7.625 8.636C7.337 7.920 6.894 7.276 6.327 6.752C6.327 6.752 3.879 4.686 3.879 4.686C3.836 4.629 3.778 4.586 3.711 4.563C3.645 4.539 3.572 4.536 3.504 4.553C3.435 4.571 3.373 4.608 3.326 4.660C3.279 4.713 3.248 4.778 3.238 4.849C3.238 4.849 2.320 7.959 2.320 7.959C2.287 8.037 2.229 8.102 2.155 8.144C2.082 8.186 1.996 8.203 1.912 8.192C1.828 8.181 1.750 8.142 1.690 8.082C1.630 8.022 1.592 7.944 1.580 7.860C1.580 7.860 0.000 0.000 0.000 0.000C0.000 0.000 8.005 0.450 8.005 0.450C8.090 0.449 8.172 0.476 8.240 0.527C8.308 0.578 8.357 0.649 8.380 0.731C8.403 0.813 8.399 0.900 8.368 0.978C8.337 1.057 8.280 1.124 8.208 1.167C8.208 1.167 5.259 2.518 5.259 2.518C5.191 2.538 5.130 2.577 5.085 2.631C5.040 2.686 5.012 2.752 5.004 2.823C4.997 2.893 5.010 2.964 5.043 3.027C5.076 3.089 5.126 3.141 5.189 3.175C5.189 3.175 7.646 5.249 7.646 5.249C8.443 5.979 9.067 6.878 9.472 7.881C9.877 8.883 10.053 9.964 9.986 11.043Z\" fill=\"currentColor\" transform=\"translate(5 3)\"/></svg>";
    readonly notification_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M2.354 5.249C2.354 5.249 4.811 3.175 4.811 3.175C4.873 3.141 4.924 3.089 4.957 3.027C4.990 2.964 5.003 2.893 4.996 2.823C4.988 2.752 4.960 2.686 4.915 2.631C4.869 2.577 4.809 2.538 4.741 2.518C4.741 2.518 1.792 1.167 1.792 1.167C1.719 1.124 1.663 1.057 1.632 0.978C1.601 0.900 1.596 0.813 1.619 0.731C1.642 0.649 1.692 0.578 1.760 0.527C1.827 0.476 1.910 0.449 1.995 0.450C1.995 0.450 10.000 0.000 10.000 0.000C10.000 0.000 8.419 7.860 8.419 7.860C8.408 7.944 8.369 8.022 8.309 8.082C8.249 8.142 8.171 8.181 8.087 8.192C8.003 8.203 7.918 8.186 7.844 8.144C7.771 8.102 7.713 8.037 7.680 7.959C7.680 7.959 6.762 4.849 6.762 4.849C6.752 4.778 6.721 4.713 6.674 4.660C6.626 4.608 6.564 4.571 6.496 4.553C6.427 4.536 6.355 4.539 6.288 4.563C6.222 4.586 6.163 4.629 6.121 4.686C6.121 4.686 3.673 6.751 3.673 6.751C3.106 7.276 2.663 7.920 2.375 8.636C2.087 9.353 1.962 10.125 2.008 10.895C2.008 10.895 2.013 14.503 2.013 14.503C2.013 14.568 2.000 14.633 1.975 14.693C1.950 14.754 1.914 14.808 1.868 14.854C1.821 14.901 1.767 14.937 1.707 14.962C1.646 14.987 1.582 15.000 1.516 15.000C1.516 15.000 0.510 15.000 0.510 15.000C0.378 15.000 0.252 14.948 0.159 14.855C0.066 14.762 0.014 14.635 0.014 14.504C0.014 14.504 0.014 11.043 0.014 11.043C-0.053 9.964 0.123 8.883 0.528 7.881C0.932 6.878 1.556 5.979 2.354 5.249Z\" fill=\"currentColor\" transform=\"translate(5 3)\"/></svg>";
    readonly notification_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.495 6.966C9.495 6.966 6.543 5.623 6.543 5.623C6.483 5.584 6.414 5.565 6.343 5.566C6.272 5.567 6.204 5.590 6.146 5.630C6.088 5.670 6.043 5.727 6.017 5.793C5.991 5.859 5.985 5.931 6.001 6.000C6.001 6.000 6.001 15.497 6.001 15.497C6.001 15.563 5.988 15.628 5.962 15.689C5.937 15.750 5.900 15.806 5.853 15.853C5.806 15.899 5.751 15.936 5.690 15.962C5.629 15.987 5.563 16.000 5.497 16.000C5.497 16.000 4.504 16.000 4.504 16.000C4.438 16.000 4.372 15.987 4.311 15.962C4.250 15.936 4.195 15.899 4.148 15.853C4.101 15.806 4.064 15.750 4.039 15.689C4.014 15.628 4.001 15.563 4.001 15.497C4.001 15.497 4.001 6.000 4.001 6.000C4.016 5.931 4.010 5.859 3.984 5.793C3.958 5.727 3.914 5.670 3.856 5.630C3.797 5.590 3.729 5.567 3.658 5.566C3.587 5.565 3.518 5.584 3.458 5.623C3.458 5.623 0.506 6.966 0.506 6.966C0.426 6.993 0.339 6.992 0.259 6.964C0.179 6.935 0.110 6.882 0.063 6.811C0.017 6.740 -0.005 6.656 0.001 6.571C0.007 6.487 0.041 6.406 0.097 6.343C0.097 6.343 5.001 0.000 5.001 0.000C5.001 0.000 9.904 6.343 9.904 6.343C9.960 6.406 9.994 6.487 10.000 6.571C10.006 6.656 9.984 6.740 9.938 6.811C9.891 6.882 9.823 6.935 9.743 6.964C9.662 6.992 9.575 6.993 9.495 6.966Z\" fill=\"currentColor\" transform=\"translate(5.009 2)\"/></svg>";
    readonly off_ramp_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M13.494 0.019C13.494 0.019 12.488 0.019 12.488 0.019C12.423 0.019 12.358 0.032 12.298 0.057C12.237 0.082 12.183 0.118 12.137 0.164C12.090 0.211 12.054 0.265 12.029 0.326C12.004 0.386 11.991 0.451 11.991 0.516C11.991 0.516 11.991 15.522 11.991 15.522C11.991 15.587 12.004 15.652 12.029 15.712C12.054 15.772 12.090 15.827 12.137 15.873C12.183 15.919 12.237 15.956 12.298 15.981C12.358 16.006 12.423 16.019 12.488 16.019C12.488 16.019 13.494 16.019 13.494 16.019C13.559 16.019 13.624 16.006 13.684 15.981C13.744 15.956 13.799 15.919 13.845 15.873C13.891 15.827 13.928 15.772 13.953 15.712C13.978 15.652 13.991 15.587 13.991 15.522C13.991 15.522 13.991 0.516 13.991 0.516C13.991 0.451 13.978 0.386 13.953 0.326C13.928 0.265 13.891 0.211 13.845 0.164C13.799 0.118 13.744 0.082 13.684 0.057C13.624 0.032 13.559 0.019 13.494 0.019Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(1.009 1.981)\"/><path d=\"M7.992 4.001C7.992 4.001 6.004 4.001 6.004 4.001C5.935 4.016 5.863 4.010 5.797 3.984C5.731 3.958 5.675 3.914 5.634 3.855C5.594 3.797 5.572 3.729 5.570 3.658C5.569 3.587 5.589 3.518 5.627 3.458C5.627 3.458 6.971 0.506 6.971 0.506C6.997 0.426 6.996 0.339 6.968 0.259C6.940 0.179 6.886 0.110 6.815 0.063C6.744 0.017 6.660 -0.005 6.575 0.001C6.491 0.007 6.411 0.041 6.347 0.097C6.347 0.097 0.000 5.019 0.000 5.019C0.000 5.019 6.347 9.904 6.347 9.904C6.411 9.960 6.491 9.994 6.575 10.000C6.660 10.006 6.744 9.984 6.815 9.938C6.886 9.891 6.940 9.823 6.968 9.743C6.996 9.663 6.997 9.576 6.971 9.495C6.971 9.495 5.627 6.543 5.627 6.543C5.589 6.483 5.569 6.414 5.570 6.343C5.572 6.273 5.594 6.204 5.634 6.146C5.675 6.088 5.731 6.043 5.797 6.017C5.863 5.991 5.935 5.985 6.004 6.001C6.004 6.001 8.003 6.001 8.003 6.001C9.070 6.019 10.087 6.456 10.833 7.219C11.580 7.981 11.996 9.007 11.992 10.074C11.992 10.074 11.992 15.523 11.992 15.523C11.992 15.588 12.004 15.652 12.029 15.712C12.054 15.772 12.090 15.827 12.137 15.873C12.183 15.919 12.237 15.956 12.298 15.981C12.358 16.006 12.423 16.019 12.488 16.019C12.488 16.019 13.494 16.019 13.494 16.019C13.559 16.019 13.624 16.006 13.684 15.981C13.744 15.956 13.799 15.919 13.845 15.873C13.891 15.827 13.928 15.772 13.953 15.712C13.978 15.652 13.991 15.587 13.991 15.522C13.991 15.522 13.989 14.019 13.989 14.019C13.989 14.019 13.992 14.019 13.992 14.019C13.992 14.019 13.992 10.074 13.992 10.074C13.995 8.477 13.368 6.942 12.247 5.805C11.125 4.668 9.600 4.019 8.003 4.001C8.003 4.001 7.992 3.999 7.992 3.999Z\" fill=\"currentColor\" transform=\"translate(1.009 1.981)\"/></svg>";
    readonly off_ramp_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M1.503 0.019C1.503 0.019 0.497 0.019 0.497 0.019C0.432 0.019 0.367 0.032 0.307 0.057C0.247 0.082 0.192 0.118 0.146 0.164C0.099 0.211 0.063 0.265 0.038 0.326C0.013 0.386 -0.000 0.451 0.000 0.516C0.000 0.516 0.000 15.522 0.000 15.522C-0.000 15.587 0.013 15.652 0.038 15.712C0.063 15.772 0.099 15.827 0.146 15.873C0.192 15.919 0.247 15.956 0.307 15.981C0.367 16.006 0.432 16.019 0.497 16.019C0.497 16.019 1.503 16.019 1.503 16.019C1.568 16.019 1.633 16.006 1.693 15.981C1.753 15.956 1.808 15.919 1.854 15.873C1.901 15.827 1.937 15.772 1.962 15.712C1.987 15.652 2.000 15.587 2.000 15.522C2.000 15.522 2.000 0.516 2.000 0.516C2.000 0.451 1.987 0.386 1.962 0.326C1.937 0.265 1.901 0.211 1.854 0.164C1.808 0.118 1.753 0.082 1.693 0.057C1.633 0.032 1.568 0.019 1.503 0.019Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(5 1.981)\"/><path d=\"M6.008 6.001C6.008 6.001 7.996 6.001 7.996 6.001C8.065 5.985 8.137 5.991 8.203 6.017C8.269 6.043 8.325 6.088 8.366 6.146C8.406 6.204 8.428 6.272 8.430 6.343C8.431 6.414 8.411 6.483 8.373 6.543C8.373 6.543 7.029 9.495 7.029 9.495C7.003 9.576 7.004 9.663 7.032 9.743C7.060 9.823 7.114 9.891 7.185 9.938C7.256 9.984 7.340 10.006 7.425 10.000C7.509 9.994 7.589 9.960 7.653 9.904C7.653 9.904 14.000 5.019 14.000 5.019C14.000 5.019 7.653 0.097 7.653 0.097C7.589 0.041 7.509 0.007 7.425 0.001C7.340 -0.005 7.256 0.017 7.185 0.063C7.114 0.110 7.060 0.179 7.032 0.259C7.004 0.339 7.003 0.426 7.029 0.506C7.029 0.506 8.373 3.458 8.373 3.458C8.411 3.518 8.431 3.587 8.430 3.658C8.428 3.729 8.406 3.797 8.366 3.855C8.325 3.914 8.269 3.958 8.203 3.984C8.137 4.010 8.065 4.016 7.996 4.001C7.996 4.001 6.008 4.001 6.008 4.001C6.008 4.001 6.008 3.999 6.008 3.999C6.008 3.999 5.997 4.001 5.997 4.001C4.400 4.019 2.875 4.668 1.753 5.805C0.632 6.942 0.005 8.477 0.008 10.074C0.008 10.074 0.008 14.019 0.008 14.019C0.008 14.019 0.011 14.019 0.011 14.019C0.011 14.019 0.009 15.522 0.009 15.522C0.009 15.587 0.022 15.652 0.047 15.712C0.072 15.772 0.108 15.827 0.155 15.873C0.201 15.919 0.255 15.956 0.316 15.981C0.376 16.006 0.440 16.019 0.506 16.019C0.506 16.019 1.512 16.019 1.512 16.019C1.644 16.019 1.770 15.967 1.863 15.874C1.956 15.780 2.008 15.654 2.008 15.523C2.008 15.523 2.008 10.074 2.008 10.074C2.004 9.007 2.420 7.981 3.167 7.219C3.913 6.456 4.930 6.019 5.997 6.001C5.997 6.001 6.008 6.001 6.008 6.001Z\" fill=\"currentColor\" transform=\"translate(5 1.981)\"/></svg>";
    readonly off_ramp_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M9.503 0.000C9.503 0.000 8.497 0.000 8.497 0.000C8.432 0.000 8.367 0.013 8.307 0.038C8.247 0.063 8.192 0.099 8.146 0.146C8.099 0.192 8.063 0.247 8.038 0.307C8.013 0.367 8.000 0.432 8.000 0.497C8.000 0.497 8.000 15.503 8.000 15.503C8.000 15.568 8.013 15.633 8.038 15.693C8.063 15.753 8.099 15.808 8.146 15.854C8.192 15.901 8.247 15.937 8.307 15.962C8.367 15.987 8.432 16.000 8.497 16.000C8.497 16.000 9.503 16.000 9.503 16.000C9.568 16.000 9.633 15.987 9.693 15.962C9.753 15.937 9.808 15.901 9.854 15.854C9.901 15.808 9.937 15.753 9.962 15.693C9.987 15.633 10.000 15.568 10.000 15.503C10.000 15.503 10.000 0.497 10.000 0.497C10.000 0.432 9.987 0.367 9.962 0.307C9.937 0.247 9.901 0.192 9.854 0.146C9.808 0.099 9.753 0.063 9.693 0.038C9.633 0.013 9.568 0.000 9.503 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(5 2)\"/><path d=\"M7.646 6.249C7.646 6.249 5.189 4.175 5.189 4.175C5.126 4.141 5.076 4.089 5.043 4.027C5.010 3.964 4.997 3.893 5.004 3.823C5.012 3.752 5.040 3.686 5.085 3.631C5.130 3.577 5.191 3.538 5.259 3.518C5.259 3.518 8.208 2.167 8.208 2.167C8.280 2.124 8.337 2.057 8.368 1.978C8.399 1.900 8.403 1.813 8.380 1.731C8.357 1.649 8.308 1.578 8.240 1.527C8.172 1.476 8.090 1.449 8.005 1.450C8.005 1.450 0.000 1.000 0.000 1.000C0.000 1.000 1.580 8.860 1.580 8.860C1.592 8.944 1.630 9.022 1.690 9.082C1.750 9.142 1.828 9.181 1.912 9.192C1.996 9.203 2.082 9.186 2.155 9.144C2.229 9.102 2.287 9.037 2.320 8.959C2.320 8.959 3.238 5.849 3.238 5.849C3.248 5.778 3.279 5.713 3.326 5.660C3.373 5.608 3.435 5.571 3.504 5.553C3.572 5.536 3.645 5.539 3.711 5.563C3.778 5.586 3.836 5.629 3.878 5.686C3.878 5.686 6.327 7.751 6.327 7.751C6.894 8.276 7.337 8.920 7.625 9.636C7.913 10.353 8.038 11.125 7.992 11.895C7.992 11.895 7.987 15.503 7.987 15.503C7.987 15.568 8.000 15.633 8.025 15.693C8.049 15.754 8.086 15.808 8.132 15.854C8.178 15.901 8.233 15.937 8.293 15.962C8.353 15.987 8.418 16.000 8.483 16.000C8.483 16.000 9.490 16.000 9.490 16.000C9.621 16.000 9.748 15.948 9.841 15.855C9.934 15.762 9.986 15.635 9.986 15.504C9.986 15.504 9.986 12.043 9.986 12.043C10.053 10.964 9.877 9.883 9.472 8.881C9.067 7.878 8.443 6.979 7.646 6.249Z\" fill=\"currentColor\" transform=\"translate(5 2)\"/></svg>";
    readonly off_ramp_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M1.503 0.000C1.503 0.000 0.497 0.000 0.497 0.000C0.432 0.000 0.367 0.013 0.307 0.038C0.247 0.063 0.192 0.099 0.146 0.146C0.099 0.192 0.063 0.247 0.038 0.307C0.013 0.367 -0.000 0.432 0.000 0.497C0.000 0.497 0.000 15.503 0.000 15.503C-0.000 15.568 0.013 15.633 0.038 15.693C0.063 15.753 0.099 15.808 0.146 15.854C0.192 15.901 0.247 15.937 0.307 15.962C0.367 15.987 0.432 16.000 0.497 16.000C0.497 16.000 1.503 16.000 1.503 16.000C1.568 16.000 1.633 15.987 1.693 15.962C1.753 15.937 1.808 15.901 1.854 15.854C1.901 15.808 1.937 15.753 1.962 15.693C1.987 15.633 2.000 15.568 2.000 15.503C2.000 15.503 2.000 0.497 2.000 0.497C2.000 0.432 1.987 0.367 1.962 0.307C1.937 0.247 1.901 0.192 1.854 0.146C1.808 0.099 1.753 0.063 1.693 0.038C1.633 0.013 1.568 0.000 1.503 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" transform=\"translate(7 2)\"/><path d=\"M0.014 12.043C0.014 12.043 0.014 15.504 0.014 15.504C0.014 15.635 0.066 15.762 0.159 15.855C0.252 15.948 0.379 16.000 0.510 16.000C0.510 16.000 1.517 16.000 1.517 16.000C1.582 16.000 1.647 15.987 1.707 15.962C1.767 15.937 1.822 15.901 1.868 15.854C1.914 15.808 1.950 15.754 1.975 15.693C2.000 15.633 2.013 15.568 2.013 15.503C2.013 15.503 2.008 11.896 2.008 11.896C1.962 11.125 2.087 10.353 2.375 9.636C2.663 8.920 3.106 8.276 3.673 7.752C3.673 7.752 6.121 5.686 6.121 5.686C6.164 5.629 6.222 5.586 6.289 5.563C6.355 5.539 6.427 5.536 6.496 5.553C6.565 5.571 6.626 5.608 6.674 5.661C6.721 5.713 6.752 5.779 6.762 5.849C6.762 5.849 7.680 8.959 7.680 8.959C7.713 9.037 7.771 9.102 7.845 9.145C7.918 9.187 8.004 9.203 8.088 9.192C8.172 9.181 8.250 9.142 8.310 9.082C8.370 9.022 8.408 8.944 8.420 8.860C8.420 8.860 10.000 1.000 10.000 1.000C10.000 1.000 1.995 1.450 1.995 1.450C1.910 1.449 1.828 1.476 1.760 1.527C1.692 1.578 1.643 1.649 1.620 1.731C1.597 1.813 1.601 1.900 1.632 1.978C1.663 2.057 1.720 2.124 1.792 2.167C1.792 2.167 4.741 3.518 4.741 3.518C4.809 3.538 4.870 3.577 4.915 3.631C4.960 3.686 4.988 3.752 4.996 3.823C5.003 3.893 4.990 3.964 4.957 4.027C4.924 4.089 4.874 4.141 4.811 4.175C4.811 4.175 2.354 6.249 2.354 6.249C1.557 6.979 0.933 7.878 0.528 8.881C0.123 9.883 -0.053 10.964 0.014 12.043Z\" fill=\"currentColor\" transform=\"translate(7 2)\"/></svg>";
    readonly on_ramp_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M7.992 3.999C7.992 3.999 8.003 4.001 8.003 4.001C9.600 4.019 11.125 4.668 12.247 5.805C13.368 6.942 13.995 8.477 13.992 10.074C13.992 10.074 13.992 14.019 13.992 14.019C13.992 14.019 13.989 14.019 13.989 14.019C13.989 14.019 13.991 15.522 13.991 15.522C13.991 15.587 13.978 15.652 13.953 15.712C13.928 15.772 13.892 15.827 13.845 15.873C13.799 15.919 13.745 15.956 13.684 15.981C13.624 16.006 13.560 16.019 13.494 16.019C13.494 16.019 12.488 16.019 12.488 16.019C12.356 16.019 12.230 15.967 12.137 15.874C12.044 15.780 11.992 15.654 11.992 15.523C11.992 15.523 11.992 10.074 11.992 10.074C11.996 9.007 11.580 7.981 10.833 7.219C10.087 6.456 9.070 6.019 8.003 6.001C8.003 6.001 6.004 6.001 6.004 6.001C5.935 5.985 5.863 5.991 5.797 6.017C5.731 6.043 5.675 6.088 5.634 6.146C5.594 6.204 5.572 6.272 5.570 6.343C5.569 6.414 5.589 6.483 5.627 6.543C5.627 6.543 6.971 9.495 6.971 9.495C6.997 9.576 6.996 9.663 6.968 9.743C6.940 9.823 6.886 9.891 6.815 9.938C6.744 9.984 6.660 10.006 6.575 10.000C6.491 9.994 6.411 9.960 6.347 9.904C6.347 9.904 0.000 5.019 0.000 5.019C0.000 5.019 6.347 0.097 6.347 0.097C6.411 0.041 6.491 0.007 6.575 0.001C6.660 -0.005 6.744 0.017 6.815 0.063C6.886 0.110 6.940 0.179 6.968 0.259C6.996 0.339 6.997 0.426 6.971 0.506C6.971 0.506 5.627 3.458 5.627 3.458C5.589 3.518 5.569 3.587 5.570 3.658C5.572 3.729 5.594 3.797 5.634 3.855C5.675 3.914 5.731 3.958 5.797 3.984C5.863 4.010 5.935 4.016 6.004 4.001C6.004 4.001 7.992 4.001 7.992 4.001Z\" fill=\"currentColor\" transform=\"translate(1.009 1.981)\"/></svg>";
    readonly on_ramp_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M5.989 6.001C4.922 6.019 3.905 6.456 3.159 7.219C2.412 7.981 1.996 9.007 2.000 10.074C2.000 10.074 2.000 15.523 2.000 15.523C2.000 15.654 1.948 15.780 1.855 15.873C1.762 15.967 1.635 16.019 1.504 16.019C1.504 16.019 0.497 16.019 0.497 16.019C0.432 16.019 0.368 16.006 0.307 15.981C0.247 15.956 0.192 15.919 0.146 15.873C0.100 15.827 0.064 15.772 0.039 15.712C0.014 15.652 0.001 15.587 0.001 15.522C0.001 15.522 0.003 14.019 0.003 14.019C0.003 14.019 0.000 14.019 0.000 14.019C0.000 14.019 0.000 10.074 0.000 10.074C-0.004 8.477 0.624 6.942 1.745 5.805C2.867 4.668 4.392 4.019 5.989 4.001C5.989 4.001 6.000 3.999 6.000 3.999C6.000 3.999 6.000 4.001 6.000 4.001C6.000 4.001 7.988 4.001 7.988 4.001C8.057 4.016 8.129 4.010 8.195 3.984C8.260 3.958 8.317 3.914 8.358 3.855C8.398 3.797 8.420 3.729 8.422 3.658C8.423 3.587 8.403 3.518 8.365 3.458C8.365 3.458 7.021 0.506 7.021 0.506C6.995 0.426 6.996 0.339 7.024 0.259C7.052 0.179 7.106 0.110 7.177 0.063C7.247 0.017 7.332 -0.005 7.416 0.001C7.501 0.007 7.581 0.041 7.645 0.097C7.645 0.097 13.992 5.019 13.992 5.019C13.992 5.019 7.645 9.904 7.645 9.904C7.581 9.960 7.501 9.994 7.416 10.000C7.332 10.006 7.247 9.984 7.177 9.938C7.106 9.891 7.052 9.823 7.024 9.743C6.996 9.663 6.995 9.575 7.021 9.495C7.021 9.495 8.365 6.543 8.365 6.543C8.403 6.483 8.423 6.414 8.422 6.343C8.420 6.272 8.398 6.204 8.358 6.146C8.317 6.088 8.260 6.043 8.195 6.017C8.129 5.991 8.057 5.985 7.988 6.001C7.988 6.001 5.989 6.001 5.989 6.001Z\" fill=\"currentColor\" transform=\"translate(5.008 1.981)\"/></svg>";
    readonly on_ramp_sharp_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M13.481 15.011C13.349 15.011 13.223 14.959 13.129 14.865C13.036 14.772 12.983 14.645 12.983 14.513C12.983 14.513 12.983 2.015 12.983 2.015C12.983 2.015 12.704 2.009 12.704 2.009C12.317 1.974 11.928 2.026 11.565 2.163C11.202 2.300 10.875 2.517 10.608 2.799C10.608 2.799 5.213 7.412 5.213 7.412C5.155 7.447 5.109 7.498 5.080 7.559C5.051 7.620 5.041 7.687 5.049 7.754C5.058 7.821 5.086 7.884 5.130 7.935C5.173 7.986 5.231 8.024 5.295 8.043C5.295 8.043 8.224 9.437 8.224 9.437C8.296 9.481 8.351 9.549 8.381 9.628C8.411 9.707 8.414 9.794 8.390 9.875C8.366 9.957 8.316 10.028 8.247 10.078C8.178 10.127 8.095 10.153 8.010 10.151C8.010 10.151 0.000 10.483 0.000 10.483C0.000 10.483 1.696 2.647 1.696 2.647C1.708 2.564 1.748 2.486 1.809 2.427C1.870 2.368 1.948 2.331 2.032 2.320C2.117 2.310 2.202 2.328 2.275 2.372C2.348 2.415 2.405 2.481 2.436 2.559C2.436 2.559 3.309 5.683 3.309 5.683C3.318 5.753 3.348 5.819 3.394 5.872C3.441 5.926 3.502 5.964 3.570 5.982C3.639 6.001 3.711 5.998 3.778 5.976C3.845 5.953 3.904 5.911 3.947 5.855C3.947 5.855 3.951 5.859 3.951 5.859C3.951 5.859 9.343 1.250 9.343 1.250C9.790 0.820 10.322 0.487 10.904 0.273C11.487 0.059 12.108 -0.031 12.728 0.009C12.728 0.009 12.992 0.011 12.992 0.011C13.257 0.002 13.521 0.048 13.768 0.146C14.015 0.244 14.239 0.392 14.426 0.580C14.792 0.977 14.992 1.500 14.983 2.040C14.983 2.040 14.983 14.513 14.983 14.513C14.983 14.579 14.971 14.643 14.945 14.704C14.920 14.764 14.884 14.819 14.838 14.865C14.791 14.912 14.736 14.948 14.676 14.973C14.616 14.998 14.551 15.011 14.486 15.011C14.486 15.011 13.481 15.011 13.481 15.011Z\" fill=\"currentColor\" transform=\"translate(2.017 2.989)\"/></svg>";
    readonly on_ramp_sharp_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M0.498 15.011C0.432 15.011 0.368 14.998 0.307 14.973C0.247 14.948 0.192 14.912 0.146 14.865C0.100 14.819 0.063 14.764 0.038 14.704C0.013 14.643 -0.000 14.579 0.000 14.513C0.000 14.513 0.000 2.040 0.000 2.040C-0.008 1.500 0.191 0.977 0.558 0.580C0.745 0.392 0.969 0.244 1.215 0.146C1.462 0.048 1.726 0.002 1.992 0.011C1.992 0.011 2.256 0.009 2.256 0.009C2.875 -0.031 3.496 0.059 4.079 0.273C4.662 0.487 5.194 0.820 5.641 1.250C5.641 1.250 11.033 5.859 11.033 5.859C11.033 5.859 11.036 5.855 11.036 5.855C11.080 5.911 11.138 5.953 11.205 5.976C11.272 5.998 11.345 6.001 11.413 5.982C11.481 5.964 11.543 5.926 11.589 5.872C11.636 5.819 11.665 5.753 11.674 5.683C11.674 5.683 12.547 2.559 12.547 2.559C12.579 2.481 12.636 2.415 12.709 2.372C12.782 2.328 12.867 2.310 12.951 2.320C13.035 2.331 13.114 2.368 13.175 2.427C13.235 2.486 13.275 2.564 13.288 2.647C13.288 2.647 14.983 10.483 14.983 10.483C14.983 10.483 6.973 10.151 6.973 10.151C6.888 10.153 6.805 10.127 6.736 10.078C6.668 10.028 6.618 9.957 6.593 9.875C6.569 9.794 6.572 9.707 6.602 9.628C6.632 9.549 6.687 9.481 6.759 9.437C6.759 9.437 9.688 8.043 9.688 8.043C9.753 8.024 9.810 7.986 9.854 7.935C9.897 7.884 9.925 7.821 9.934 7.754C9.943 7.687 9.932 7.620 9.903 7.559C9.874 7.498 9.828 7.447 9.771 7.412C9.771 7.412 4.375 2.799 4.375 2.799C4.109 2.517 3.781 2.300 3.418 2.163C3.055 2.026 2.666 1.974 2.280 2.009C2.280 2.009 2.000 2.015 2.000 2.015C2.000 2.015 2.000 14.513 2.000 14.513C2.000 14.645 1.948 14.772 1.854 14.865C1.761 14.959 1.634 15.011 1.502 15.011C1.502 15.011 0.498 15.011 0.498 15.011Z\" fill=\"currentColor\" transform=\"translate(3 2.984)\"/></svg>";
    readonly on_ramp_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.986 11.043C9.986 11.043 9.986 14.504 9.986 14.504C9.986 14.635 9.934 14.762 9.841 14.855C9.748 14.948 9.621 15.000 9.490 15.000C9.490 15.000 8.483 15.000 8.483 15.000C8.418 15.000 8.353 14.987 8.293 14.962C8.233 14.937 8.178 14.901 8.132 14.854C8.086 14.808 8.050 14.754 8.025 14.693C8.000 14.633 7.987 14.568 7.987 14.503C7.987 14.503 7.992 10.896 7.992 10.896C8.038 10.125 7.913 9.353 7.625 8.636C7.337 7.920 6.894 7.276 6.327 6.752C6.327 6.752 3.879 4.686 3.879 4.686C3.836 4.629 3.778 4.586 3.711 4.563C3.645 4.539 3.572 4.536 3.504 4.553C3.435 4.571 3.373 4.608 3.326 4.660C3.279 4.713 3.248 4.778 3.238 4.849C3.238 4.849 2.320 7.959 2.320 7.959C2.287 8.037 2.229 8.102 2.155 8.144C2.082 8.186 1.996 8.203 1.912 8.192C1.828 8.181 1.750 8.142 1.690 8.082C1.630 8.022 1.592 7.944 1.580 7.860C1.580 7.860 0.000 0.000 0.000 0.000C0.000 0.000 8.005 0.450 8.005 0.450C8.090 0.449 8.172 0.476 8.240 0.527C8.308 0.578 8.357 0.649 8.380 0.731C8.403 0.813 8.399 0.900 8.368 0.978C8.337 1.057 8.280 1.124 8.208 1.167C8.208 1.167 5.259 2.518 5.259 2.518C5.191 2.538 5.130 2.577 5.085 2.631C5.040 2.686 5.012 2.752 5.004 2.823C4.997 2.893 5.010 2.964 5.043 3.027C5.076 3.089 5.126 3.141 5.189 3.175C5.189 3.175 7.646 5.249 7.646 5.249C8.443 5.979 9.067 6.878 9.472 7.881C9.877 8.883 10.053 9.964 9.986 11.043Z\" fill=\"currentColor\" transform=\"translate(3 3)\"/></svg>";
    readonly on_ramp_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M2.354 5.249C2.354 5.249 4.811 3.175 4.811 3.175C4.873 3.141 4.924 3.089 4.957 3.027C4.990 2.964 5.003 2.893 4.996 2.823C4.988 2.752 4.960 2.686 4.915 2.631C4.869 2.577 4.809 2.538 4.741 2.518C4.741 2.518 1.792 1.167 1.792 1.167C1.719 1.124 1.663 1.057 1.632 0.978C1.601 0.900 1.596 0.813 1.619 0.731C1.642 0.649 1.692 0.578 1.760 0.527C1.827 0.476 1.910 0.449 1.995 0.450C1.995 0.450 10.000 0.000 10.000 0.000C10.000 0.000 8.419 7.860 8.419 7.860C8.408 7.944 8.369 8.022 8.309 8.082C8.249 8.142 8.171 8.181 8.087 8.192C8.003 8.203 7.918 8.186 7.844 8.144C7.771 8.102 7.713 8.037 7.680 7.959C7.680 7.959 6.762 4.849 6.762 4.849C6.752 4.778 6.721 4.713 6.674 4.660C6.626 4.608 6.564 4.571 6.496 4.553C6.427 4.536 6.355 4.539 6.288 4.563C6.222 4.586 6.163 4.629 6.121 4.686C6.121 4.686 3.673 6.751 3.673 6.751C3.106 7.276 2.663 7.920 2.375 8.636C2.087 9.353 1.962 10.125 2.008 10.895C2.008 10.895 2.013 14.503 2.013 14.503C2.013 14.568 2.000 14.633 1.975 14.693C1.950 14.754 1.914 14.808 1.868 14.854C1.822 14.901 1.767 14.937 1.707 14.962C1.646 14.987 1.582 15.000 1.516 15.000C1.516 15.000 0.510 15.000 0.510 15.000C0.378 15.000 0.252 14.948 0.159 14.855C0.066 14.762 0.014 14.635 0.014 14.504C0.014 14.504 0.014 11.043 0.014 11.043C-0.053 9.964 0.123 8.883 0.528 7.881C0.932 6.878 1.556 5.979 2.354 5.249Z\" fill=\"currentColor\" transform=\"translate(7 3)\"/></svg>";
    readonly on_ramp_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.495 6.966C9.495 6.966 6.543 5.623 6.543 5.623C6.483 5.584 6.414 5.565 6.343 5.566C6.272 5.567 6.204 5.590 6.146 5.630C6.088 5.670 6.043 5.727 6.017 5.793C5.991 5.859 5.985 5.931 6.001 6.000C6.001 6.000 6.001 15.497 6.001 15.497C6.001 15.563 5.988 15.628 5.962 15.689C5.937 15.750 5.900 15.806 5.853 15.853C5.806 15.899 5.751 15.936 5.690 15.962C5.629 15.987 5.563 16.000 5.497 16.000C5.497 16.000 4.504 16.000 4.504 16.000C4.438 16.000 4.372 15.987 4.311 15.962C4.250 15.936 4.195 15.899 4.148 15.853C4.101 15.806 4.064 15.750 4.039 15.689C4.014 15.628 4.001 15.563 4.001 15.497C4.001 15.497 4.001 6.000 4.001 6.000C4.016 5.931 4.010 5.859 3.984 5.793C3.958 5.727 3.914 5.670 3.856 5.630C3.797 5.590 3.729 5.567 3.658 5.566C3.587 5.565 3.518 5.584 3.458 5.623C3.458 5.623 0.506 6.966 0.506 6.966C0.426 6.993 0.339 6.992 0.259 6.964C0.179 6.935 0.110 6.882 0.063 6.811C0.017 6.740 -0.005 6.656 0.001 6.571C0.007 6.487 0.041 6.406 0.097 6.343C0.097 6.343 5.001 0.000 5.001 0.000C5.001 0.000 9.904 6.343 9.904 6.343C9.960 6.406 9.994 6.487 10.000 6.571C10.006 6.656 9.984 6.740 9.938 6.811C9.891 6.882 9.823 6.935 9.743 6.964C9.662 6.992 9.575 6.993 9.495 6.966Z\" fill=\"currentColor\" transform=\"translate(5.009 2)\"/></svg>";
    readonly rotary: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(8.500 9.250)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(8.500 9.250)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 4.782 -1.462L2.869 -0.877A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(8.500 9.250)\"/><path d=\"M7.536 -1.219C7.536 -1.219 4.977 -1.646 4.977 -1.646C4.923 -1.664 4.866 -1.664 4.811 -1.649C4.756 -1.633 4.708 -1.601 4.672 -1.558C4.635 -1.515 4.612 -1.462 4.606 -1.406C4.600 -1.349 4.610 -1.292 4.636 -1.242L3.091 -0.828C3.088 -0.885 3.069 -0.939 3.035 -0.985C3.001 -1.030 2.955 -1.065 2.902 -1.084C2.848 -1.103 2.791 -1.106 2.736 -1.093C2.681 -1.079 2.632 -1.050 2.593 -1.007C2.593 -1.007 0.590 0.642 0.590 0.642C0.534 0.679 0.467 0.697 0.399 0.692C0.331 0.686 0.267 0.659 0.216 0.614C0.166 0.569 0.131 0.508 0.118 0.441C0.105 0.375 0.115 0.305 0.145 0.245L2.621 -5.672L7.723 -1.785C7.780 -1.748 7.823 -1.693 7.845 -1.629C7.867 -1.565 7.867 -1.495 7.847 -1.431C7.825 -1.366 7.783 -1.311 7.728 -1.272C7.671 -1.234 7.604 -1.215 7.536 -1.219Z\" fill=\"currentColor\" transform=\"translate(8.500 9.250)\"/></svg>";
    readonly rotary_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(14.000 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -5.000 0.000L-3.000 0.000A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/><path d=\"M-4.000 -1.000L-7.750 -1.000L-7.750 1.000L-4.000 1.000Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/><path d=\"M-5.784 -4.494C-5.784 -4.494 -7.127 -1.542 -7.127 -1.542C-7.166 -1.482 -7.185 -1.413 -7.184 -1.342C-7.183 -1.271 -7.160 -1.203 -7.120 -1.145C-7.080 -1.087 -7.023 -1.042 -6.957 -1.016C-6.891 -0.990 -6.819 -0.984 -6.750 -1.000L-6.750 1.000C-6.819 0.985 -6.891 0.991 -6.957 1.017C-7.023 1.043 -7.080 1.087 -7.120 1.145C-7.160 1.204 -7.183 1.272 -7.184 1.343C-7.185 1.414 -7.166 1.483 -7.127 1.543C-7.127 1.543 -5.784 4.495 -5.784 4.495C-5.757 4.575 -5.758 4.662 -5.786 4.742C-5.815 4.822 -5.868 4.891 -5.939 4.938C-6.010 4.984 -6.094 5.006 -6.179 5.000C-6.263 4.994 -6.344 4.960 -6.407 4.904L-12.750 0.000L-6.407 -4.903C-6.344 -4.959 -6.263 -4.993 -6.179 -4.999C-6.094 -5.005 -6.010 -4.983 -5.939 -4.937C-5.868 -4.890 -5.815 -4.822 -5.786 -4.742C-5.758 -4.661 -5.757 -4.574 -5.784 -4.494Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/></svg>";
    readonly rotary_lht: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 11.500 9.250)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 11.500 9.250)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 4.782 -1.462L2.869 -0.877A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 11.500 9.250)\"/><path d=\"M7.536 -1.219C7.536 -1.219 4.977 -1.646 4.977 -1.646C4.923 -1.664 4.866 -1.664 4.811 -1.649C4.756 -1.633 4.708 -1.601 4.672 -1.558C4.635 -1.515 4.612 -1.462 4.606 -1.406C4.600 -1.349 4.610 -1.292 4.636 -1.242L3.091 -0.828C3.088 -0.885 3.069 -0.939 3.035 -0.985C3.001 -1.030 2.955 -1.065 2.902 -1.084C2.848 -1.103 2.791 -1.106 2.736 -1.093C2.681 -1.079 2.632 -1.050 2.593 -1.007C2.593 -1.007 0.590 0.642 0.590 0.642C0.534 0.679 0.467 0.697 0.399 0.692C0.331 0.686 0.267 0.659 0.216 0.614C0.166 0.569 0.131 0.508 0.118 0.441C0.105 0.375 0.115 0.305 0.145 0.245L2.621 -5.672L7.723 -1.785C7.780 -1.748 7.823 -1.693 7.845 -1.629C7.867 -1.565 7.867 -1.495 7.847 -1.431C7.825 -1.366 7.783 -1.311 7.728 -1.272C7.671 -1.234 7.604 -1.215 7.536 -1.219Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 11.500 9.250)\"/></svg>";
    readonly rotary_lht_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 13.750 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 5.000 0.000L3.000 0.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.000)\"/><path d=\"M4.000 1.000L7.750 1.000L7.750 -1.000L4.000 -1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.000)\"/><path d=\"M5.784 4.494C5.784 4.494 7.127 1.542 7.127 1.542C7.166 1.482 7.185 1.413 7.184 1.342C7.183 1.271 7.160 1.203 7.120 1.145C7.080 1.087 7.023 1.042 6.957 1.016C6.891 0.990 6.819 0.984 6.750 1.000L6.750 -1.000C6.819 -0.985 6.891 -0.991 6.957 -1.017C7.023 -1.043 7.080 -1.087 7.120 -1.145C7.160 -1.204 7.183 -1.272 7.184 -1.343C7.185 -1.414 7.166 -1.483 7.127 -1.543C7.127 -1.543 5.784 -4.495 5.784 -4.495C5.757 -4.575 5.758 -4.662 5.786 -4.742C5.815 -4.822 5.868 -4.891 5.939 -4.938C6.010 -4.984 6.094 -5.006 6.179 -5.000C6.263 -4.994 6.344 -4.960 6.407 -4.904L12.750 0.000L6.407 4.903C6.344 4.959 6.263 4.993 6.179 4.999C6.094 5.005 6.010 4.983 5.939 4.937C5.868 4.890 5.815 4.822 5.786 4.742C5.758 4.661 5.757 4.574 5.784 4.494Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.000)\"/></svg>";
    readonly rotary_lht_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -5.000 0.000L-3.000 0.000A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M-4.000 -1.000L-7.750 -1.000L-7.750 1.000L-4.000 1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M-5.784 -4.494C-5.784 -4.494 -7.127 -1.542 -7.127 -1.542C-7.166 -1.482 -7.185 -1.413 -7.184 -1.342C-7.183 -1.271 -7.160 -1.203 -7.120 -1.145C-7.080 -1.087 -7.023 -1.042 -6.957 -1.016C-6.891 -0.990 -6.819 -0.984 -6.750 -1.000L-6.750 1.000C-6.819 0.985 -6.891 0.991 -6.957 1.017C-7.023 1.043 -7.080 1.087 -7.120 1.145C-7.160 1.204 -7.183 1.272 -7.184 1.343C-7.185 1.414 -7.166 1.483 -7.127 1.543C-7.127 1.543 -5.784 4.495 -5.784 4.495C-5.757 4.575 -5.758 4.662 -5.786 4.742C-5.815 4.822 -5.868 4.891 -5.939 4.938C-6.010 4.984 -6.094 5.006 -6.179 5.000C-6.263 4.994 -6.344 4.960 -6.407 4.904L-12.750 0.000L-6.407 -4.903C-6.344 -4.959 -6.263 -4.993 -6.179 -4.999C-6.094 -5.005 -6.010 -4.983 -5.939 -4.937C-5.868 -4.890 -5.815 -4.822 -5.786 -4.742C-5.758 -4.661 -5.757 -4.574 -5.784 -4.494Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/></svg>";
    readonly rotary_lht_sharp_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 12.750 8.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 12.750 8.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 4.636 1.873L2.782 1.124A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 12.750 8.500)\"/><path d=\"M3.002 2.206L6.184 5.388L7.598 3.973L4.416 0.791Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 12.750 8.500)\"/><path d=\"M2.323 6.468C2.323 6.468 5.360 5.330 5.360 5.330C5.430 5.315 5.492 5.280 5.542 5.229C5.591 5.178 5.623 5.114 5.636 5.045C5.648 4.975 5.640 4.903 5.612 4.838C5.583 4.773 5.537 4.718 5.477 4.680L6.891 3.266C6.929 3.326 6.984 3.372 7.049 3.401C7.114 3.429 7.186 3.438 7.255 3.425C7.325 3.412 7.389 3.380 7.440 3.331C7.491 3.281 7.526 3.219 7.541 3.149C7.541 3.149 8.679 0.112 8.679 0.112C8.716 0.036 8.779 -0.025 8.855 -0.061C8.932 -0.098 9.018 -0.109 9.102 -0.092C9.185 -0.074 9.260 -0.030 9.315 0.034C9.371 0.098 9.404 0.179 9.409 0.263L10.426 8.216L2.474 7.198C2.390 7.193 2.309 7.160 2.245 7.104C2.181 7.049 2.137 6.974 2.119 6.891C2.102 6.807 2.113 6.722 2.149 6.645C2.186 6.568 2.247 6.505 2.323 6.468Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 12.750 8.500)\"/></svg>";
    readonly rotary_lht_sharp_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 7.250 8.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 7.250 8.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -4.636 1.873L-2.782 1.124A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 7.250 8.500)\"/><path d=\"M-4.416 0.791L-7.598 3.973L-6.184 5.388L-3.002 2.206Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 7.250 8.500)\"/><path d=\"M-8.678 0.112C-8.678 0.112 -7.541 3.150 -7.541 3.150C-7.526 3.220 -7.490 3.282 -7.439 3.331C-7.389 3.381 -7.324 3.413 -7.255 3.425C-7.186 3.438 -7.113 3.430 -7.048 3.401C-6.983 3.373 -6.928 3.326 -6.891 3.266L-5.477 4.680C-5.536 4.719 -5.583 4.774 -5.611 4.839C-5.639 4.904 -5.648 4.975 -5.636 5.045C-5.622 5.115 -5.590 5.179 -5.541 5.230C-5.491 5.281 -5.429 5.316 -5.359 5.331C-5.359 5.331 -2.322 6.469 -2.322 6.469C-2.246 6.506 -2.186 6.568 -2.149 6.645C-2.113 6.722 -2.101 6.808 -2.118 6.892C-2.136 6.974 -2.180 7.049 -2.244 7.105C-2.308 7.160 -2.389 7.193 -2.473 7.198L-10.426 8.216L-9.408 0.264C-9.403 0.180 -9.370 0.098 -9.315 0.035C-9.259 -0.030 -9.184 -0.073 -9.101 -0.091C-9.018 -0.108 -8.932 -0.098 -8.855 -0.061C-8.778 -0.024 -8.716 0.037 -8.678 0.112Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 7.250 8.500)\"/></svg>";
    readonly rotary_lht_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 5.000 0.000L3.000 0.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M3.300 1.000L5.550 1.000L5.550 -1.000L3.300 -1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M5.500 1.000A4.000 4.000 0 0 0 8.328 -0.172L6.914 -1.586A2.000 2.000 0 0 1 5.500 -1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M8.293 -0.136L9.919 -1.763L8.505 -3.177L6.879 -1.550Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M11.000 2.098C11.000 2.098 9.862 -0.939 9.862 -0.939C9.847 -1.009 9.812 -1.071 9.761 -1.121C9.710 -1.170 9.646 -1.202 9.576 -1.215C9.507 -1.227 9.435 -1.219 9.370 -1.191C9.305 -1.162 9.250 -1.116 9.212 -1.055L7.798 -2.470C7.857 -2.508 7.904 -2.563 7.932 -2.628C7.961 -2.693 7.970 -2.765 7.957 -2.834C7.944 -2.904 7.912 -2.968 7.862 -3.019C7.813 -3.070 7.751 -3.105 7.681 -3.120C7.681 -3.120 4.644 -4.258 4.644 -4.258C4.568 -4.295 4.507 -4.358 4.470 -4.434C4.434 -4.511 4.423 -4.597 4.440 -4.681C4.458 -4.764 4.502 -4.838 4.566 -4.894C4.630 -4.949 4.711 -4.983 4.795 -4.988L12.748 -6.005L11.730 1.947C11.725 2.031 11.691 2.112 11.636 2.176C11.580 2.240 11.505 2.284 11.423 2.302C11.339 2.319 11.254 2.308 11.177 2.272C11.100 2.235 11.037 2.174 11.000 2.098Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/></svg>";
    readonly rotary_lht_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -5.000 0.000L-3.000 0.000A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M-3.300 -1.000L-5.550 -1.000L-5.550 1.000L-3.300 1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M-5.500 1.000A4.000 4.000 0 0 1 -8.328 -0.172L-6.914 -1.586A2.000 2.000 0 0 0 -5.500 -1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M-6.879 -1.550L-8.505 -3.177L-9.919 -1.763L-8.293 -0.136Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M-4.644 -4.257C-4.644 -4.257 -7.681 -3.120 -7.681 -3.120C-7.751 -3.105 -7.814 -3.069 -7.863 -3.018C-7.913 -2.967 -7.944 -2.903 -7.957 -2.834C-7.970 -2.765 -7.961 -2.692 -7.933 -2.627C-7.905 -2.562 -7.858 -2.507 -7.798 -2.470L-9.212 -1.055C-9.250 -1.115 -9.306 -1.162 -9.371 -1.190C-9.436 -1.218 -9.507 -1.227 -9.576 -1.215C-9.646 -1.201 -9.711 -1.169 -9.762 -1.120C-9.813 -1.070 -9.848 -1.008 -9.863 -0.938C-9.863 -0.938 -11.001 2.099 -11.001 2.099C-11.038 2.175 -11.100 2.235 -11.177 2.272C-11.254 2.308 -11.340 2.320 -11.423 2.303C-11.506 2.285 -11.581 2.241 -11.637 2.177C-11.692 2.113 -11.725 2.032 -11.730 1.948L-12.748 -6.005L-4.796 -4.987C-4.712 -4.982 -4.630 -4.949 -4.567 -4.894C-4.502 -4.838 -4.458 -4.763 -4.441 -4.680C-4.424 -4.597 -4.434 -4.511 -4.470 -4.434C-4.508 -4.357 -4.569 -4.295 -4.644 -4.257Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/></svg>";
    readonly rotary_lht_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M-1.000 2.828L-1.000 6.000Q-1.000 6.500 -0.500 6.500L0.500 6.500Q1.000 6.500 1.000 6.000L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 0.000 -5.000L0.000 -3.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M1.000 -4.000L1.000 -7.000L-1.000 -7.000L-1.000 -4.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M4.494 -5.034C4.494 -5.034 1.542 -6.377 1.542 -6.377C1.482 -6.416 1.413 -6.435 1.342 -6.434C1.271 -6.433 1.203 -6.410 1.145 -6.370C1.087 -6.330 1.042 -6.273 1.016 -6.207C0.990 -6.141 0.984 -6.069 1.000 -6.000L-1.000 -6.000C-0.985 -6.069 -0.991 -6.141 -1.017 -6.207C-1.043 -6.273 -1.087 -6.330 -1.145 -6.370C-1.204 -6.410 -1.272 -6.433 -1.343 -6.434C-1.414 -6.435 -1.483 -6.416 -1.543 -6.377C-1.543 -6.377 -4.495 -5.034 -4.495 -5.034C-4.575 -5.007 -4.662 -5.008 -4.742 -5.036C-4.822 -5.065 -4.891 -5.118 -4.938 -5.189C-4.984 -5.260 -5.006 -5.344 -5.000 -5.429C-4.994 -5.513 -4.960 -5.594 -4.904 -5.657L0.000 -12.000L4.903 -5.657C4.959 -5.594 4.993 -5.513 4.999 -5.429C5.005 -5.344 4.983 -5.260 4.937 -5.189C4.890 -5.118 4.822 -5.065 4.742 -5.036C4.661 -5.008 4.574 -5.007 4.494 -5.034Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/></svg>";
    readonly rotary_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(6.250 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(6.250 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 5.000 0.000L3.000 0.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(6.250 9.000)\"/><path d=\"M4.000 1.000L7.750 1.000L7.750 -1.000L4.000 -1.000Z\" fill=\"currentColor\" transform=\"translate(6.250 9.000)\"/><path d=\"M5.784 4.494C5.784 4.494 7.127 1.542 7.127 1.542C7.166 1.482 7.185 1.413 7.184 1.342C7.183 1.271 7.160 1.203 7.120 1.145C7.080 1.087 7.023 1.042 6.957 1.016C6.891 0.990 6.819 0.984 6.750 1.000L6.750 -1.000C6.819 -0.985 6.891 -0.991 6.957 -1.017C7.023 -1.043 7.080 -1.087 7.120 -1.145C7.160 -1.204 7.183 -1.272 7.184 -1.343C7.185 -1.414 7.166 -1.483 7.127 -1.543C7.127 -1.543 5.784 -4.495 5.784 -4.495C5.757 -4.575 5.758 -4.662 5.786 -4.742C5.815 -4.822 5.868 -4.891 5.939 -4.938C6.010 -4.984 6.094 -5.006 6.179 -5.000C6.263 -4.994 6.344 -4.960 6.407 -4.904L12.750 0.000L6.407 4.903C6.344 4.959 6.263 4.993 6.179 4.999C6.094 5.005 6.010 4.983 5.939 4.937C5.868 4.890 5.815 4.822 5.786 4.742C5.758 4.661 5.757 4.574 5.784 4.494Z\" fill=\"currentColor\" transform=\"translate(6.250 9.000)\"/></svg>";
    readonly rotary_sharp_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(12.750 8.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(12.750 8.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -4.636 1.873L-2.782 1.124A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(12.750 8.500)\"/><path d=\"M-4.416 0.791L-7.598 3.973L-6.184 5.388L-3.002 2.206Z\" fill=\"currentColor\" transform=\"translate(12.750 8.500)\"/><path d=\"M-8.678 0.112C-8.678 0.112 -7.541 3.150 -7.541 3.150C-7.526 3.220 -7.490 3.282 -7.439 3.331C-7.389 3.381 -7.324 3.413 -7.255 3.425C-7.186 3.438 -7.113 3.430 -7.048 3.401C-6.983 3.373 -6.928 3.326 -6.891 3.266L-5.477 4.680C-5.536 4.719 -5.583 4.774 -5.611 4.839C-5.639 4.904 -5.648 4.975 -5.636 5.045C-5.622 5.115 -5.590 5.179 -5.541 5.230C-5.491 5.281 -5.429 5.316 -5.359 5.331C-5.359 5.331 -2.322 6.469 -2.322 6.469C-2.246 6.506 -2.186 6.568 -2.149 6.645C-2.113 6.722 -2.101 6.808 -2.118 6.892C-2.136 6.974 -2.180 7.049 -2.244 7.105C-2.308 7.160 -2.389 7.193 -2.473 7.198L-10.426 8.216L-9.408 0.264C-9.403 0.180 -9.370 0.098 -9.315 0.035C-9.259 -0.030 -9.184 -0.073 -9.101 -0.091C-9.018 -0.108 -8.932 -0.098 -8.855 -0.061C-8.778 -0.024 -8.716 0.037 -8.678 0.112Z\" fill=\"currentColor\" transform=\"translate(12.750 8.500)\"/></svg>";
    readonly rotary_sharp_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(7.250 8.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(7.250 8.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 4.636 1.873L2.782 1.124A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(7.250 8.500)\"/><path d=\"M3.002 2.206L6.184 5.388L7.598 3.973L4.416 0.791Z\" fill=\"currentColor\" transform=\"translate(7.250 8.500)\"/><path d=\"M2.323 6.468C2.323 6.468 5.360 5.330 5.360 5.330C5.430 5.315 5.492 5.280 5.542 5.229C5.591 5.178 5.623 5.114 5.636 5.045C5.648 4.975 5.640 4.903 5.612 4.838C5.583 4.773 5.537 4.718 5.477 4.680L6.891 3.266C6.929 3.326 6.984 3.372 7.049 3.401C7.114 3.429 7.186 3.438 7.255 3.425C7.325 3.412 7.389 3.380 7.440 3.331C7.491 3.281 7.526 3.219 7.541 3.149C7.541 3.149 8.679 0.112 8.679 0.112C8.716 0.036 8.779 -0.025 8.855 -0.061C8.932 -0.098 9.018 -0.109 9.102 -0.092C9.185 -0.074 9.260 -0.030 9.315 0.034C9.371 0.098 9.404 0.179 9.409 0.263L10.426 8.216L2.474 7.198C2.390 7.193 2.309 7.160 2.245 7.104C2.181 7.049 2.137 6.974 2.119 6.891C2.102 6.807 2.113 6.722 2.149 6.645C2.186 6.568 2.247 6.505 2.323 6.468Z\" fill=\"currentColor\" transform=\"translate(7.250 8.500)\"/></svg>";
    readonly rotary_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(13.750 9.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -5.000 0.000L-3.000 0.000A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/><path d=\"M-3.300 -1.000L-5.550 -1.000L-5.550 1.000L-3.300 1.000Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/><path d=\"M-5.500 1.000A4.000 4.000 0 0 1 -8.328 -0.172L-6.914 -1.586A2.000 2.000 0 0 0 -5.500 -1.000Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/><path d=\"M-6.879 -1.550L-8.505 -3.177L-9.919 -1.763L-8.293 -0.136Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/><path d=\"M-4.644 -4.257C-4.644 -4.257 -7.681 -3.120 -7.681 -3.120C-7.751 -3.105 -7.814 -3.069 -7.863 -3.018C-7.913 -2.967 -7.944 -2.903 -7.957 -2.834C-7.970 -2.765 -7.961 -2.692 -7.933 -2.627C-7.905 -2.562 -7.858 -2.507 -7.798 -2.470L-9.212 -1.055C-9.250 -1.115 -9.306 -1.162 -9.371 -1.190C-9.436 -1.218 -9.507 -1.227 -9.576 -1.215C-9.646 -1.201 -9.711 -1.169 -9.762 -1.120C-9.813 -1.070 -9.848 -1.008 -9.863 -0.938C-9.863 -0.938 -11.001 2.099 -11.001 2.099C-11.038 2.175 -11.100 2.235 -11.177 2.272C-11.254 2.308 -11.340 2.320 -11.423 2.303C-11.506 2.285 -11.581 2.241 -11.637 2.177C-11.692 2.113 -11.725 2.032 -11.730 1.948L-12.748 -6.005L-4.796 -4.987C-4.712 -4.982 -4.630 -4.949 -4.567 -4.894C-4.502 -4.838 -4.458 -4.763 -4.441 -4.680C-4.424 -4.597 -4.434 -4.511 -4.470 -4.434C-4.508 -4.357 -4.569 -4.295 -4.644 -4.257Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/></svg>";
    readonly rotary_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(6.250 9.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 5.000 0.000L3.000 0.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/><path d=\"M3.300 1.000L5.550 1.000L5.550 -1.000L3.300 -1.000Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/><path d=\"M5.500 1.000A4.000 4.000 0 0 0 8.328 -0.172L6.914 -1.586A2.000 2.000 0 0 1 5.500 -1.000Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/><path d=\"M8.293 -0.136L9.919 -1.763L8.505 -3.177L6.879 -1.550Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/><path d=\"M11.000 2.098C11.000 2.098 9.862 -0.939 9.862 -0.939C9.847 -1.009 9.812 -1.071 9.761 -1.121C9.710 -1.170 9.646 -1.202 9.576 -1.215C9.507 -1.227 9.435 -1.219 9.370 -1.191C9.305 -1.162 9.250 -1.116 9.212 -1.055L7.798 -2.470C7.857 -2.508 7.904 -2.563 7.932 -2.628C7.961 -2.693 7.970 -2.765 7.957 -2.834C7.944 -2.904 7.912 -2.968 7.862 -3.019C7.813 -3.070 7.751 -3.105 7.681 -3.120C7.681 -3.120 4.644 -4.258 4.644 -4.258C4.568 -4.295 4.507 -4.358 4.470 -4.434C4.434 -4.511 4.423 -4.597 4.440 -4.681C4.458 -4.764 4.502 -4.838 4.566 -4.894C4.630 -4.949 4.711 -4.983 4.795 -4.988L12.748 -6.005L11.730 1.947C11.725 2.031 11.691 2.112 11.636 2.176C11.580 2.240 11.505 2.284 11.423 2.302C11.339 2.319 11.254 2.308 11.177 2.272C11.100 2.235 11.037 2.174 11.000 2.098Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/></svg>";
    readonly rotary_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(10.000 12.750)\"/><path d=\"M-1.000 2.828L-1.000 6.000Q-1.000 6.500 -0.500 6.500L0.500 6.500Q1.000 6.500 1.000 6.000L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 0.000 -5.000L0.000 -3.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/><path d=\"M1.000 -4.000L1.000 -7.000L-1.000 -7.000L-1.000 -4.000Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/><path d=\"M4.494 -5.034C4.494 -5.034 1.542 -6.377 1.542 -6.377C1.482 -6.416 1.413 -6.435 1.342 -6.434C1.271 -6.433 1.203 -6.410 1.145 -6.370C1.087 -6.330 1.042 -6.273 1.016 -6.207C0.990 -6.141 0.984 -6.069 1.000 -6.000L-1.000 -6.000C-0.985 -6.069 -0.991 -6.141 -1.017 -6.207C-1.043 -6.273 -1.087 -6.330 -1.145 -6.370C-1.204 -6.410 -1.272 -6.433 -1.343 -6.434C-1.414 -6.435 -1.483 -6.416 -1.543 -6.377C-1.543 -6.377 -4.495 -5.034 -4.495 -5.034C-4.575 -5.007 -4.662 -5.008 -4.742 -5.036C-4.822 -5.065 -4.891 -5.118 -4.938 -5.189C-4.984 -5.260 -5.006 -5.344 -5.000 -5.429C-4.994 -5.513 -4.960 -5.594 -4.904 -5.657L0.000 -12.000L4.903 -5.657C4.959 -5.594 4.993 -5.513 4.999 -5.429C5.005 -5.344 4.983 -5.260 4.937 -5.189C4.890 -5.118 4.822 -5.065 4.742 -5.036C4.661 -5.008 4.574 -5.007 4.494 -5.034Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/></svg>";
    readonly roundabout: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(8.500 9.250)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(8.500 9.250)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 4.782 -1.462L2.869 -0.877A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(8.500 9.250)\"/><path d=\"M7.536 -1.219C7.536 -1.219 4.977 -1.646 4.977 -1.646C4.923 -1.664 4.866 -1.664 4.811 -1.649C4.756 -1.633 4.708 -1.601 4.672 -1.558C4.635 -1.515 4.612 -1.462 4.606 -1.406C4.600 -1.349 4.610 -1.292 4.636 -1.242L3.091 -0.828C3.088 -0.885 3.069 -0.939 3.035 -0.985C3.001 -1.030 2.955 -1.065 2.902 -1.084C2.848 -1.103 2.791 -1.106 2.736 -1.093C2.681 -1.079 2.632 -1.050 2.593 -1.007C2.593 -1.007 0.590 0.642 0.590 0.642C0.534 0.679 0.467 0.697 0.399 0.692C0.331 0.686 0.267 0.659 0.216 0.614C0.166 0.569 0.131 0.508 0.118 0.441C0.105 0.375 0.115 0.305 0.145 0.245L2.621 -5.672L7.723 -1.785C7.780 -1.748 7.823 -1.693 7.845 -1.629C7.867 -1.565 7.867 -1.495 7.847 -1.431C7.825 -1.366 7.783 -1.311 7.728 -1.272C7.671 -1.234 7.604 -1.215 7.536 -1.219Z\" fill=\"currentColor\" transform=\"translate(8.500 9.250)\"/></svg>";
    readonly roundabout_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(14.000 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -5.000 0.000L-3.000 0.000A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/><path d=\"M-4.000 -1.000L-7.750 -1.000L-7.750 1.000L-4.000 1.000Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/><path d=\"M-5.784 -4.494C-5.784 -4.494 -7.127 -1.542 -7.127 -1.542C-7.166 -1.482 -7.185 -1.413 -7.184 -1.342C-7.183 -1.271 -7.160 -1.203 -7.120 -1.145C-7.080 -1.087 -7.023 -1.042 -6.957 -1.016C-6.891 -0.990 -6.819 -0.984 -6.750 -1.000L-6.750 1.000C-6.819 0.985 -6.891 0.991 -6.957 1.017C-7.023 1.043 -7.080 1.087 -7.120 1.145C-7.160 1.204 -7.183 1.272 -7.184 1.343C-7.185 1.414 -7.166 1.483 -7.127 1.543C-7.127 1.543 -5.784 4.495 -5.784 4.495C-5.757 4.575 -5.758 4.662 -5.786 4.742C-5.815 4.822 -5.868 4.891 -5.939 4.938C-6.010 4.984 -6.094 5.006 -6.179 5.000C-6.263 4.994 -6.344 4.960 -6.407 4.904L-12.750 0.000L-6.407 -4.903C-6.344 -4.959 -6.263 -4.993 -6.179 -4.999C-6.094 -5.005 -6.010 -4.983 -5.939 -4.937C-5.868 -4.890 -5.815 -4.822 -5.786 -4.742C-5.758 -4.661 -5.757 -4.574 -5.784 -4.494Z\" fill=\"currentColor\" transform=\"translate(14.000 9.000)\"/></svg>";
    readonly roundabout_lht: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 11.500 9.250)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 11.500 9.250)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 4.782 -1.462L2.869 -0.877A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 11.500 9.250)\"/><path d=\"M7.536 -1.219C7.536 -1.219 4.977 -1.646 4.977 -1.646C4.923 -1.664 4.866 -1.664 4.811 -1.649C4.756 -1.633 4.708 -1.601 4.672 -1.558C4.635 -1.515 4.612 -1.462 4.606 -1.406C4.600 -1.349 4.610 -1.292 4.636 -1.242L3.091 -0.828C3.088 -0.885 3.069 -0.939 3.035 -0.985C3.001 -1.030 2.955 -1.065 2.902 -1.084C2.848 -1.103 2.791 -1.106 2.736 -1.093C2.681 -1.079 2.632 -1.050 2.593 -1.007C2.593 -1.007 0.590 0.642 0.590 0.642C0.534 0.679 0.467 0.697 0.399 0.692C0.331 0.686 0.267 0.659 0.216 0.614C0.166 0.569 0.131 0.508 0.118 0.441C0.105 0.375 0.115 0.305 0.145 0.245L2.621 -5.672L7.723 -1.785C7.780 -1.748 7.823 -1.693 7.845 -1.629C7.867 -1.565 7.867 -1.495 7.847 -1.431C7.825 -1.366 7.783 -1.311 7.728 -1.272C7.671 -1.234 7.604 -1.215 7.536 -1.219Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 11.500 9.250)\"/></svg>";
    readonly roundabout_lht_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 13.750 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 5.000 0.000L3.000 0.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.000)\"/><path d=\"M4.000 1.000L7.750 1.000L7.750 -1.000L4.000 -1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.000)\"/><path d=\"M5.784 4.494C5.784 4.494 7.127 1.542 7.127 1.542C7.166 1.482 7.185 1.413 7.184 1.342C7.183 1.271 7.160 1.203 7.120 1.145C7.080 1.087 7.023 1.042 6.957 1.016C6.891 0.990 6.819 0.984 6.750 1.000L6.750 -1.000C6.819 -0.985 6.891 -0.991 6.957 -1.017C7.023 -1.043 7.080 -1.087 7.120 -1.145C7.160 -1.204 7.183 -1.272 7.184 -1.343C7.185 -1.414 7.166 -1.483 7.127 -1.543C7.127 -1.543 5.784 -4.495 5.784 -4.495C5.757 -4.575 5.758 -4.662 5.786 -4.742C5.815 -4.822 5.868 -4.891 5.939 -4.938C6.010 -4.984 6.094 -5.006 6.179 -5.000C6.263 -4.994 6.344 -4.960 6.407 -4.904L12.750 0.000L6.407 4.903C6.344 4.959 6.263 4.993 6.179 4.999C6.094 5.005 6.010 4.983 5.939 4.937C5.868 4.890 5.815 4.822 5.786 4.742C5.758 4.661 5.757 4.574 5.784 4.494Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.000)\"/></svg>";
    readonly roundabout_lht_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -5.000 0.000L-3.000 0.000A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M-4.000 -1.000L-7.750 -1.000L-7.750 1.000L-4.000 1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/><path d=\"M-5.784 -4.494C-5.784 -4.494 -7.127 -1.542 -7.127 -1.542C-7.166 -1.482 -7.185 -1.413 -7.184 -1.342C-7.183 -1.271 -7.160 -1.203 -7.120 -1.145C-7.080 -1.087 -7.023 -1.042 -6.957 -1.016C-6.891 -0.990 -6.819 -0.984 -6.750 -1.000L-6.750 1.000C-6.819 0.985 -6.891 0.991 -6.957 1.017C-7.023 1.043 -7.080 1.087 -7.120 1.145C-7.160 1.204 -7.183 1.272 -7.184 1.343C-7.185 1.414 -7.166 1.483 -7.127 1.543C-7.127 1.543 -5.784 4.495 -5.784 4.495C-5.757 4.575 -5.758 4.662 -5.786 4.742C-5.815 4.822 -5.868 4.891 -5.939 4.938C-6.010 4.984 -6.094 5.006 -6.179 5.000C-6.263 4.994 -6.344 4.960 -6.407 4.904L-12.750 0.000L-6.407 -4.903C-6.344 -4.959 -6.263 -4.993 -6.179 -4.999C-6.094 -5.005 -6.010 -4.983 -5.939 -4.937C-5.868 -4.890 -5.815 -4.822 -5.786 -4.742C-5.758 -4.661 -5.757 -4.574 -5.784 -4.494Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.000 9.000)\"/></svg>";
    readonly roundabout_lht_sharp_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 12.750 8.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 12.750 8.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 4.636 1.873L2.782 1.124A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 12.750 8.500)\"/><path d=\"M3.002 2.206L6.184 5.388L7.598 3.973L4.416 0.791Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 12.750 8.500)\"/><path d=\"M2.323 6.468C2.323 6.468 5.360 5.330 5.360 5.330C5.430 5.315 5.492 5.280 5.542 5.229C5.591 5.178 5.623 5.114 5.636 5.045C5.648 4.975 5.640 4.903 5.612 4.838C5.583 4.773 5.537 4.718 5.477 4.680L6.891 3.266C6.929 3.326 6.984 3.372 7.049 3.401C7.114 3.429 7.186 3.438 7.255 3.425C7.325 3.412 7.389 3.380 7.440 3.331C7.491 3.281 7.526 3.219 7.541 3.149C7.541 3.149 8.679 0.112 8.679 0.112C8.716 0.036 8.779 -0.025 8.855 -0.061C8.932 -0.098 9.018 -0.109 9.102 -0.092C9.185 -0.074 9.260 -0.030 9.315 0.034C9.371 0.098 9.404 0.179 9.409 0.263L10.426 8.216L2.474 7.198C2.390 7.193 2.309 7.160 2.245 7.104C2.181 7.049 2.137 6.974 2.119 6.891C2.102 6.807 2.113 6.722 2.149 6.645C2.186 6.568 2.247 6.505 2.323 6.468Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 12.750 8.500)\"/></svg>";
    readonly roundabout_lht_sharp_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 7.250 8.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 7.250 8.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -4.636 1.873L-2.782 1.124A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 7.250 8.500)\"/><path d=\"M-4.416 0.791L-7.598 3.973L-6.184 5.388L-3.002 2.206Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 7.250 8.500)\"/><path d=\"M-8.678 0.112C-8.678 0.112 -7.541 3.150 -7.541 3.150C-7.526 3.220 -7.490 3.282 -7.439 3.331C-7.389 3.381 -7.324 3.413 -7.255 3.425C-7.186 3.438 -7.113 3.430 -7.048 3.401C-6.983 3.373 -6.928 3.326 -6.891 3.266L-5.477 4.680C-5.536 4.719 -5.583 4.774 -5.611 4.839C-5.639 4.904 -5.648 4.975 -5.636 5.045C-5.622 5.115 -5.590 5.179 -5.541 5.230C-5.491 5.281 -5.429 5.316 -5.359 5.331C-5.359 5.331 -2.322 6.469 -2.322 6.469C-2.246 6.506 -2.186 6.568 -2.149 6.645C-2.113 6.722 -2.101 6.808 -2.118 6.892C-2.136 6.974 -2.180 7.049 -2.244 7.105C-2.308 7.160 -2.389 7.193 -2.473 7.198L-10.426 8.216L-9.408 0.264C-9.403 0.180 -9.370 0.098 -9.315 0.035C-9.259 -0.030 -9.184 -0.073 -9.101 -0.091C-9.018 -0.108 -8.932 -0.098 -8.855 -0.061C-8.778 -0.024 -8.716 0.037 -8.678 0.112Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 7.250 8.500)\"/></svg>";
    readonly roundabout_lht_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 5.000 0.000L3.000 0.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M3.300 1.000L5.550 1.000L5.550 -1.000L3.300 -1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M5.500 1.000A4.000 4.000 0 0 0 8.328 -0.172L6.914 -1.586A2.000 2.000 0 0 1 5.500 -1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M8.293 -0.136L9.919 -1.763L8.505 -3.177L6.879 -1.550Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/><path d=\"M11.000 2.098C11.000 2.098 9.862 -0.939 9.862 -0.939C9.847 -1.009 9.812 -1.071 9.761 -1.121C9.710 -1.170 9.646 -1.202 9.576 -1.215C9.507 -1.227 9.435 -1.219 9.370 -1.191C9.305 -1.162 9.250 -1.116 9.212 -1.055L7.798 -2.470C7.857 -2.508 7.904 -2.563 7.932 -2.628C7.961 -2.693 7.970 -2.765 7.957 -2.834C7.944 -2.904 7.912 -2.968 7.862 -3.019C7.813 -3.070 7.751 -3.105 7.681 -3.120C7.681 -3.120 4.644 -4.258 4.644 -4.258C4.568 -4.295 4.507 -4.358 4.470 -4.434C4.434 -4.511 4.423 -4.597 4.440 -4.681C4.458 -4.764 4.502 -4.838 4.566 -4.894C4.630 -4.949 4.711 -4.983 4.795 -4.988L12.748 -6.005L11.730 1.947C11.725 2.031 11.691 2.112 11.636 2.176C11.580 2.240 11.505 2.284 11.423 2.302C11.339 2.319 11.254 2.308 11.177 2.272C11.100 2.235 11.037 2.174 11.000 2.098Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 13.750 9.500)\"/></svg>";
    readonly roundabout_lht_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -5.000 0.000L-3.000 0.000A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M-3.300 -1.000L-5.550 -1.000L-5.550 1.000L-3.300 1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M-5.500 1.000A4.000 4.000 0 0 1 -8.328 -0.172L-6.914 -1.586A2.000 2.000 0 0 0 -5.500 -1.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M-6.879 -1.550L-8.505 -3.177L-9.919 -1.763L-8.293 -0.136Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/><path d=\"M-4.644 -4.257C-4.644 -4.257 -7.681 -3.120 -7.681 -3.120C-7.751 -3.105 -7.814 -3.069 -7.863 -3.018C-7.913 -2.967 -7.944 -2.903 -7.957 -2.834C-7.970 -2.765 -7.961 -2.692 -7.933 -2.627C-7.905 -2.562 -7.858 -2.507 -7.798 -2.470L-9.212 -1.055C-9.250 -1.115 -9.306 -1.162 -9.371 -1.190C-9.436 -1.218 -9.507 -1.227 -9.576 -1.215C-9.646 -1.201 -9.711 -1.169 -9.762 -1.120C-9.813 -1.070 -9.848 -1.008 -9.863 -0.938C-9.863 -0.938 -11.001 2.099 -11.001 2.099C-11.038 2.175 -11.100 2.235 -11.177 2.272C-11.254 2.308 -11.340 2.320 -11.423 2.303C-11.506 2.285 -11.581 2.241 -11.637 2.177C-11.692 2.113 -11.725 2.032 -11.730 1.948L-12.748 -6.005L-4.796 -4.987C-4.712 -4.982 -4.630 -4.949 -4.567 -4.894C-4.502 -4.838 -4.458 -4.763 -4.441 -4.680C-4.424 -4.597 -4.434 -4.511 -4.470 -4.434C-4.508 -4.357 -4.569 -4.295 -4.644 -4.257Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 6.250 9.500)\"/></svg>";
    readonly roundabout_lht_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M-1.000 2.828L-1.000 6.000Q-1.000 6.500 -0.500 6.500L0.500 6.500Q1.000 6.500 1.000 6.000L1.000 2.828Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 0.000 -5.000L0.000 -3.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M1.000 -4.000L1.000 -7.000L-1.000 -7.000L-1.000 -4.000Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/><path d=\"M4.494 -5.034C4.494 -5.034 1.542 -6.377 1.542 -6.377C1.482 -6.416 1.413 -6.435 1.342 -6.434C1.271 -6.433 1.203 -6.410 1.145 -6.370C1.087 -6.330 1.042 -6.273 1.016 -6.207C0.990 -6.141 0.984 -6.069 1.000 -6.000L-1.000 -6.000C-0.985 -6.069 -0.991 -6.141 -1.017 -6.207C-1.043 -6.273 -1.087 -6.330 -1.145 -6.370C-1.204 -6.410 -1.272 -6.433 -1.343 -6.434C-1.414 -6.435 -1.483 -6.416 -1.543 -6.377C-1.543 -6.377 -4.495 -5.034 -4.495 -5.034C-4.575 -5.007 -4.662 -5.008 -4.742 -5.036C-4.822 -5.065 -4.891 -5.118 -4.938 -5.189C-4.984 -5.260 -5.006 -5.344 -5.000 -5.429C-4.994 -5.513 -4.960 -5.594 -4.904 -5.657L0.000 -12.000L4.903 -5.657C4.959 -5.594 4.993 -5.513 4.999 -5.429C5.005 -5.344 4.983 -5.260 4.937 -5.189C4.890 -5.118 4.822 -5.065 4.742 -5.036C4.661 -5.008 4.574 -5.007 4.494 -5.034Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 10.000 12.750)\"/></svg>";
    readonly roundabout_lht_uturn: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"matrix(-1 0 0 1 8.000 6.000)\"/><path d=\"M2.750 1.199L2.750 12.300Q2.750 12.800 3.250 12.800L4.250 12.800Q4.750 12.800 4.750 12.300L4.750 1.199Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 8.000 6.000)\"/><path d=\"M4.672 1.782A5.000 5.000 0 1 0 -4.672 1.782L-2.803 1.069A3.000 3.000 0 1 1 2.803 1.069Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 8.000 6.000)\"/><path d=\"M-4.750 1.199L-4.750 7.800L-2.750 7.800L-2.750 1.199Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 8.000 6.000)\"/><path d=\"M-8.244 5.834C-8.244 5.834 -5.292 7.177 -5.292 7.177C-5.232 7.216 -5.163 7.235 -5.092 7.234C-5.021 7.233 -4.953 7.210 -4.895 7.170C-4.837 7.130 -4.792 7.073 -4.766 7.007C-4.740 6.941 -4.734 6.869 -4.750 6.800L-2.750 6.800C-2.765 6.869 -2.759 6.941 -2.733 7.007C-2.707 7.073 -2.663 7.130 -2.605 7.170C-2.546 7.210 -2.478 7.233 -2.407 7.234C-2.336 7.235 -2.267 7.216 -2.207 7.177C-2.207 7.177 0.745 5.834 0.745 5.834C0.825 5.807 0.912 5.808 0.992 5.836C1.072 5.865 1.141 5.918 1.188 5.989C1.234 6.060 1.256 6.144 1.250 6.229C1.244 6.313 1.210 6.394 1.154 6.457L-3.750 12.800L-8.653 6.457C-8.709 6.394 -8.743 6.313 -8.749 6.229C-8.755 6.144 -8.733 6.060 -8.687 5.989C-8.640 5.918 -8.572 5.865 -8.492 5.836C-8.411 5.808 -8.324 5.807 -8.244 5.834Z\" fill=\"currentColor\" transform=\"matrix(-1 0 0 1 8.000 6.000)\"/></svg>";
    readonly roundabout_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(6.250 9.000)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(6.250 9.000)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 5.000 0.000L3.000 0.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(6.250 9.000)\"/><path d=\"M4.000 1.000L7.750 1.000L7.750 -1.000L4.000 -1.000Z\" fill=\"currentColor\" transform=\"translate(6.250 9.000)\"/><path d=\"M5.784 4.494C5.784 4.494 7.127 1.542 7.127 1.542C7.166 1.482 7.185 1.413 7.184 1.342C7.183 1.271 7.160 1.203 7.120 1.145C7.080 1.087 7.023 1.042 6.957 1.016C6.891 0.990 6.819 0.984 6.750 1.000L6.750 -1.000C6.819 -0.985 6.891 -0.991 6.957 -1.017C7.023 -1.043 7.080 -1.087 7.120 -1.145C7.160 -1.204 7.183 -1.272 7.184 -1.343C7.185 -1.414 7.166 -1.483 7.127 -1.543C7.127 -1.543 5.784 -4.495 5.784 -4.495C5.757 -4.575 5.758 -4.662 5.786 -4.742C5.815 -4.822 5.868 -4.891 5.939 -4.938C6.010 -4.984 6.094 -5.006 6.179 -5.000C6.263 -4.994 6.344 -4.960 6.407 -4.904L12.750 0.000L6.407 4.903C6.344 4.959 6.263 4.993 6.179 4.999C6.094 5.005 6.010 4.983 5.939 4.937C5.868 4.890 5.815 4.822 5.786 4.742C5.758 4.661 5.757 4.574 5.784 4.494Z\" fill=\"currentColor\" transform=\"translate(6.250 9.000)\"/></svg>";
    readonly roundabout_sharp_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(12.750 8.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(12.750 8.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -4.636 1.873L-2.782 1.124A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(12.750 8.500)\"/><path d=\"M-4.416 0.791L-7.598 3.973L-6.184 5.388L-3.002 2.206Z\" fill=\"currentColor\" transform=\"translate(12.750 8.500)\"/><path d=\"M-8.678 0.112C-8.678 0.112 -7.541 3.150 -7.541 3.150C-7.526 3.220 -7.490 3.282 -7.439 3.331C-7.389 3.381 -7.324 3.413 -7.255 3.425C-7.186 3.438 -7.113 3.430 -7.048 3.401C-6.983 3.373 -6.928 3.326 -6.891 3.266L-5.477 4.680C-5.536 4.719 -5.583 4.774 -5.611 4.839C-5.639 4.904 -5.648 4.975 -5.636 5.045C-5.622 5.115 -5.590 5.179 -5.541 5.230C-5.491 5.281 -5.429 5.316 -5.359 5.331C-5.359 5.331 -2.322 6.469 -2.322 6.469C-2.246 6.506 -2.186 6.568 -2.149 6.645C-2.113 6.722 -2.101 6.808 -2.118 6.892C-2.136 6.974 -2.180 7.049 -2.244 7.105C-2.308 7.160 -2.389 7.193 -2.473 7.198L-10.426 8.216L-9.408 0.264C-9.403 0.180 -9.370 0.098 -9.315 0.035C-9.259 -0.030 -9.184 -0.073 -9.101 -0.091C-9.018 -0.108 -8.932 -0.098 -8.855 -0.061C-8.778 -0.024 -8.716 0.037 -8.678 0.112Z\" fill=\"currentColor\" transform=\"translate(12.750 8.500)\"/></svg>";
    readonly roundabout_sharp_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(7.250 8.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(7.250 8.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 4.636 1.873L2.782 1.124A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(7.250 8.500)\"/><path d=\"M3.002 2.206L6.184 5.388L7.598 3.973L4.416 0.791Z\" fill=\"currentColor\" transform=\"translate(7.250 8.500)\"/><path d=\"M2.323 6.468C2.323 6.468 5.360 5.330 5.360 5.330C5.430 5.315 5.492 5.280 5.542 5.229C5.591 5.178 5.623 5.114 5.636 5.045C5.648 4.975 5.640 4.903 5.612 4.838C5.583 4.773 5.537 4.718 5.477 4.680L6.891 3.266C6.929 3.326 6.984 3.372 7.049 3.401C7.114 3.429 7.186 3.438 7.255 3.425C7.325 3.412 7.389 3.380 7.440 3.331C7.491 3.281 7.526 3.219 7.541 3.149C7.541 3.149 8.679 0.112 8.679 0.112C8.716 0.036 8.779 -0.025 8.855 -0.061C8.932 -0.098 9.018 -0.109 9.102 -0.092C9.185 -0.074 9.260 -0.030 9.315 0.034C9.371 0.098 9.404 0.179 9.409 0.263L10.426 8.216L2.474 7.198C2.390 7.193 2.309 7.160 2.245 7.104C2.181 7.049 2.137 6.974 2.119 6.891C2.102 6.807 2.113 6.722 2.149 6.645C2.186 6.568 2.247 6.505 2.323 6.468Z\" fill=\"currentColor\" transform=\"translate(7.250 8.500)\"/></svg>";
    readonly roundabout_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(13.750 9.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 1 0 -5.000 0.000L-3.000 0.000A3.000 3.000 0 1 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/><path d=\"M-3.300 -1.000L-5.550 -1.000L-5.550 1.000L-3.300 1.000Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/><path d=\"M-5.500 1.000A4.000 4.000 0 0 1 -8.328 -0.172L-6.914 -1.586A2.000 2.000 0 0 0 -5.500 -1.000Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/><path d=\"M-6.879 -1.550L-8.505 -3.177L-9.919 -1.763L-8.293 -0.136Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/><path d=\"M-4.644 -4.257C-4.644 -4.257 -7.681 -3.120 -7.681 -3.120C-7.751 -3.105 -7.814 -3.069 -7.863 -3.018C-7.913 -2.967 -7.944 -2.903 -7.957 -2.834C-7.970 -2.765 -7.961 -2.692 -7.933 -2.627C-7.905 -2.562 -7.858 -2.507 -7.798 -2.470L-9.212 -1.055C-9.250 -1.115 -9.306 -1.162 -9.371 -1.190C-9.436 -1.218 -9.507 -1.227 -9.576 -1.215C-9.646 -1.201 -9.711 -1.169 -9.762 -1.120C-9.813 -1.070 -9.848 -1.008 -9.863 -0.938C-9.863 -0.938 -11.001 2.099 -11.001 2.099C-11.038 2.175 -11.100 2.235 -11.177 2.272C-11.254 2.308 -11.340 2.320 -11.423 2.303C-11.506 2.285 -11.581 2.241 -11.637 2.177C-11.692 2.113 -11.725 2.032 -11.730 1.948L-12.748 -6.005L-4.796 -4.987C-4.712 -4.982 -4.630 -4.949 -4.567 -4.894C-4.502 -4.838 -4.458 -4.763 -4.441 -4.680C-4.424 -4.597 -4.434 -4.511 -4.470 -4.434C-4.508 -4.357 -4.569 -4.295 -4.644 -4.257Z\" fill=\"currentColor\" transform=\"translate(13.750 9.500)\"/></svg>";
    readonly roundabout_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(6.250 9.500)\"/><path d=\"M-1.000 2.828L-1.000 6.500Q-1.000 7.000 -0.500 7.000L0.500 7.000Q1.000 7.000 1.000 6.500L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 5.000 0.000L3.000 0.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/><path d=\"M3.300 1.000L5.550 1.000L5.550 -1.000L3.300 -1.000Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/><path d=\"M5.500 1.000A4.000 4.000 0 0 0 8.328 -0.172L6.914 -1.586A2.000 2.000 0 0 1 5.500 -1.000Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/><path d=\"M8.293 -0.136L9.919 -1.763L8.505 -3.177L6.879 -1.550Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/><path d=\"M11.000 2.098C11.000 2.098 9.862 -0.939 9.862 -0.939C9.847 -1.009 9.812 -1.071 9.761 -1.121C9.710 -1.170 9.646 -1.202 9.576 -1.215C9.507 -1.227 9.435 -1.219 9.370 -1.191C9.305 -1.162 9.250 -1.116 9.212 -1.055L7.798 -2.470C7.857 -2.508 7.904 -2.563 7.932 -2.628C7.961 -2.693 7.970 -2.765 7.957 -2.834C7.944 -2.904 7.912 -2.968 7.862 -3.019C7.813 -3.070 7.751 -3.105 7.681 -3.120C7.681 -3.120 4.644 -4.258 4.644 -4.258C4.568 -4.295 4.507 -4.358 4.470 -4.434C4.434 -4.511 4.423 -4.597 4.440 -4.681C4.458 -4.764 4.502 -4.838 4.566 -4.894C4.630 -4.949 4.711 -4.983 4.795 -4.988L12.748 -6.005L11.730 1.947C11.725 2.031 11.691 2.112 11.636 2.176C11.580 2.240 11.505 2.284 11.423 2.302C11.339 2.319 11.254 2.308 11.177 2.272C11.100 2.235 11.037 2.174 11.000 2.098Z\" fill=\"currentColor\" transform=\"translate(6.250 9.500)\"/></svg>";
    readonly roundabout_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(10.000 12.750)\"/><path d=\"M-1.000 2.828L-1.000 6.000Q-1.000 6.500 -0.500 6.500L0.500 6.500Q1.000 6.500 1.000 6.000L1.000 2.828Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/><path d=\"M0.000 5.000A5.000 5.000 0 0 0 0.000 -5.000L0.000 -3.000A3.000 3.000 0 0 1 0.000 3.000Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/><path d=\"M1.000 -4.000L1.000 -7.000L-1.000 -7.000L-1.000 -4.000Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/><path d=\"M4.494 -5.034C4.494 -5.034 1.542 -6.377 1.542 -6.377C1.482 -6.416 1.413 -6.435 1.342 -6.434C1.271 -6.433 1.203 -6.410 1.145 -6.370C1.087 -6.330 1.042 -6.273 1.016 -6.207C0.990 -6.141 0.984 -6.069 1.000 -6.000L-1.000 -6.000C-0.985 -6.069 -0.991 -6.141 -1.017 -6.207C-1.043 -6.273 -1.087 -6.330 -1.145 -6.370C-1.204 -6.410 -1.272 -6.433 -1.343 -6.434C-1.414 -6.435 -1.483 -6.416 -1.543 -6.377C-1.543 -6.377 -4.495 -5.034 -4.495 -5.034C-4.575 -5.007 -4.662 -5.008 -4.742 -5.036C-4.822 -5.065 -4.891 -5.118 -4.938 -5.189C-4.984 -5.260 -5.006 -5.344 -5.000 -5.429C-4.994 -5.513 -4.960 -5.594 -4.904 -5.657L0.000 -12.000L4.903 -5.657C4.959 -5.594 4.993 -5.513 4.999 -5.429C5.005 -5.344 4.983 -5.260 4.937 -5.189C4.890 -5.118 4.822 -5.065 4.742 -5.036C4.661 -5.008 4.574 -5.007 4.494 -5.034Z\" fill=\"currentColor\" transform=\"translate(10.000 12.750)\"/></svg>";
    readonly roundabout_uturn: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path class=\"mm2\" d=\"M-5.000 0.000A5.000 5.000 0 1 0 5.000 0.000A5.000 5.000 0 1 0 -5.000 0.000ZM-3.000 0.000A3.000 3.000 0 1 0 3.000 0.000A3.000 3.000 0 1 0 -3.000 0.000Z\" fill=\"currentColor\" fill-opacity=\"0.35\" fill-rule=\"evenodd\" transform=\"translate(12.000 6.000)\"/><path d=\"M2.750 1.199L2.750 12.300Q2.750 12.800 3.250 12.800L4.250 12.800Q4.750 12.800 4.750 12.300L4.750 1.199Z\" fill=\"currentColor\" transform=\"translate(12.000 6.000)\"/><path d=\"M4.672 1.782A5.000 5.000 0 1 0 -4.672 1.782L-2.803 1.069A3.000 3.000 0 1 1 2.803 1.069Z\" fill=\"currentColor\" transform=\"translate(12.000 6.000)\"/><path d=\"M-4.750 1.199L-4.750 7.800L-2.750 7.800L-2.750 1.199Z\" fill=\"currentColor\" transform=\"translate(12.000 6.000)\"/><path d=\"M-8.244 5.834C-8.244 5.834 -5.292 7.177 -5.292 7.177C-5.232 7.216 -5.163 7.235 -5.092 7.234C-5.021 7.233 -4.953 7.210 -4.895 7.170C-4.837 7.130 -4.792 7.073 -4.766 7.007C-4.740 6.941 -4.734 6.869 -4.750 6.800L-2.750 6.800C-2.765 6.869 -2.759 6.941 -2.733 7.007C-2.707 7.073 -2.663 7.130 -2.605 7.170C-2.546 7.210 -2.478 7.233 -2.407 7.234C-2.336 7.235 -2.267 7.216 -2.207 7.177C-2.207 7.177 0.745 5.834 0.745 5.834C0.825 5.807 0.912 5.808 0.992 5.836C1.072 5.865 1.141 5.918 1.188 5.989C1.234 6.060 1.256 6.144 1.250 6.229C1.244 6.313 1.210 6.394 1.154 6.457L-3.750 12.800L-8.653 6.457C-8.709 6.394 -8.743 6.313 -8.749 6.229C-8.755 6.144 -8.733 6.060 -8.687 5.989C-8.640 5.918 -8.572 5.865 -8.492 5.836C-8.411 5.808 -8.324 5.807 -8.244 5.834Z\" fill=\"currentColor\" transform=\"translate(12.000 6.000)\"/></svg>";
    readonly stairs: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M2.9 17 V13.9 H7 V10.3 H11.1 V6.7 H15.2 V3.1 H17.1 V17 Z\" fill=\"currentColor\" stroke=\"currentColor\" stroke-width=\"1\" stroke-linejoin=\"round\"/></svg>";
    readonly turn_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M7.992 3.999C7.992 3.999 8.003 4.001 8.003 4.001C9.600 4.019 11.125 4.668 12.247 5.805C13.368 6.942 13.995 8.477 13.992 10.074C13.992 10.074 13.992 14.019 13.992 14.019C13.992 14.019 13.989 14.019 13.989 14.019C13.989 14.019 13.991 15.522 13.991 15.522C13.991 15.587 13.978 15.652 13.953 15.712C13.928 15.772 13.892 15.827 13.845 15.873C13.799 15.919 13.745 15.956 13.684 15.981C13.624 16.006 13.560 16.019 13.494 16.019C13.494 16.019 12.488 16.019 12.488 16.019C12.356 16.019 12.230 15.967 12.137 15.874C12.044 15.780 11.992 15.654 11.992 15.523C11.992 15.523 11.992 10.074 11.992 10.074C11.996 9.007 11.580 7.981 10.833 7.219C10.087 6.456 9.070 6.019 8.003 6.001C8.003 6.001 6.004 6.001 6.004 6.001C5.935 5.985 5.863 5.991 5.797 6.017C5.731 6.043 5.675 6.088 5.634 6.146C5.594 6.204 5.572 6.272 5.570 6.343C5.569 6.414 5.589 6.483 5.627 6.543C5.627 6.543 6.971 9.495 6.971 9.495C6.997 9.576 6.996 9.663 6.968 9.743C6.940 9.823 6.886 9.891 6.815 9.938C6.744 9.984 6.660 10.006 6.575 10.000C6.491 9.994 6.411 9.960 6.347 9.904C6.347 9.904 0.000 5.019 0.000 5.019C0.000 5.019 6.347 0.097 6.347 0.097C6.411 0.041 6.491 0.007 6.575 0.001C6.660 -0.005 6.744 0.017 6.815 0.063C6.886 0.110 6.940 0.179 6.968 0.259C6.996 0.339 6.997 0.426 6.971 0.506C6.971 0.506 5.627 3.458 5.627 3.458C5.589 3.518 5.569 3.587 5.570 3.658C5.572 3.729 5.594 3.797 5.634 3.855C5.675 3.914 5.731 3.958 5.797 3.984C5.863 4.010 5.935 4.016 6.004 4.001C6.004 4.001 7.992 4.001 7.992 4.001Z\" fill=\"currentColor\" transform=\"translate(2.008 1.981)\"/></svg>";
    readonly turn_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M5.989 6.001C4.922 6.019 3.905 6.456 3.159 7.219C2.412 7.981 1.996 9.007 2.000 10.074C2.000 10.074 2.000 15.523 2.000 15.523C2.000 15.654 1.948 15.780 1.855 15.874C1.762 15.967 1.635 16.019 1.504 16.019C1.504 16.019 0.497 16.019 0.497 16.019C0.432 16.019 0.368 16.006 0.307 15.981C0.247 15.956 0.192 15.919 0.146 15.873C0.100 15.827 0.064 15.772 0.039 15.712C0.014 15.652 0.001 15.587 0.001 15.522C0.001 15.522 0.003 14.019 0.003 14.019C0.003 14.019 0.000 14.019 0.000 14.019C0.000 14.019 0.000 10.074 0.000 10.074C-0.004 8.477 0.624 6.942 1.745 5.805C2.867 4.668 4.392 4.019 5.989 4.001C5.989 4.001 6.000 3.999 6.000 3.999C6.000 3.999 6.000 4.001 6.000 4.001C6.000 4.001 7.988 4.001 7.988 4.001C8.057 4.016 8.129 4.010 8.195 3.984C8.260 3.958 8.317 3.914 8.358 3.855C8.398 3.797 8.420 3.729 8.422 3.658C8.423 3.587 8.403 3.518 8.365 3.458C8.365 3.458 7.021 0.506 7.021 0.506C6.995 0.426 6.996 0.339 7.024 0.259C7.052 0.179 7.106 0.110 7.177 0.063C7.247 0.017 7.332 -0.005 7.416 0.001C7.501 0.007 7.581 0.041 7.645 0.097C7.645 0.097 13.992 5.019 13.992 5.019C13.992 5.019 7.645 9.904 7.645 9.904C7.581 9.960 7.501 9.994 7.416 10.000C7.332 10.006 7.247 9.984 7.177 9.938C7.106 9.891 7.052 9.823 7.024 9.743C6.996 9.663 6.995 9.576 7.021 9.495C7.021 9.495 8.365 6.543 8.365 6.543C8.403 6.483 8.423 6.414 8.422 6.343C8.420 6.272 8.398 6.204 8.358 6.146C8.317 6.088 8.260 6.043 8.195 6.017C8.129 5.991 8.057 5.985 7.988 6.001C7.988 6.001 5.989 6.001 5.989 6.001Z\" fill=\"currentColor\" transform=\"translate(4 1.981)\"/></svg>";
    readonly turn_sharp_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M13.481 15.011C13.349 15.011 13.223 14.959 13.129 14.865C13.036 14.772 12.983 14.645 12.983 14.513C12.983 14.513 12.983 2.015 12.983 2.015C12.983 2.015 12.704 2.009 12.704 2.009C12.317 1.973 11.928 2.026 11.565 2.163C11.202 2.300 10.875 2.517 10.608 2.799C10.608 2.799 5.213 7.411 5.213 7.411C5.155 7.447 5.109 7.498 5.080 7.559C5.051 7.619 5.041 7.687 5.049 7.754C5.058 7.821 5.086 7.884 5.130 7.935C5.173 7.986 5.231 8.024 5.295 8.043C5.295 8.043 8.224 9.437 8.224 9.437C8.296 9.481 8.351 9.549 8.381 9.628C8.411 9.707 8.414 9.794 8.390 9.875C8.366 9.957 8.316 10.028 8.247 10.078C8.178 10.127 8.095 10.153 8.010 10.151C8.010 10.151 0.000 10.483 0.000 10.483C0.000 10.483 1.696 2.647 1.696 2.647C1.708 2.564 1.748 2.486 1.809 2.427C1.870 2.368 1.948 2.330 2.032 2.320C2.117 2.310 2.202 2.328 2.275 2.371C2.348 2.415 2.405 2.481 2.436 2.559C2.436 2.559 3.309 5.683 3.309 5.683C3.318 5.753 3.348 5.819 3.394 5.872C3.441 5.925 3.502 5.964 3.570 5.982C3.639 6.001 3.711 5.998 3.778 5.976C3.845 5.953 3.904 5.911 3.947 5.855C3.947 5.855 3.951 5.859 3.951 5.859C3.951 5.859 9.343 1.250 9.343 1.250C9.790 0.820 10.322 0.487 10.904 0.273C11.487 0.059 12.108 -0.031 12.728 0.009C12.728 0.009 12.992 0.011 12.992 0.011C13.257 0.002 13.521 0.048 13.768 0.146C14.015 0.244 14.239 0.392 14.426 0.580C14.792 0.977 14.992 1.500 14.983 2.040C14.983 2.040 14.983 14.513 14.983 14.513C14.983 14.579 14.971 14.643 14.945 14.704C14.920 14.764 14.884 14.819 14.838 14.865C14.791 14.912 14.736 14.948 14.676 14.973C14.616 14.998 14.551 15.011 14.486 15.011C14.486 15.011 13.481 15.011 13.481 15.011Z\" fill=\"currentColor\" transform=\"translate(2.017 2.984)\"/></svg>";
    readonly turn_sharp_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M0.498 15.011C0.432 15.011 0.368 14.998 0.307 14.973C0.247 14.948 0.192 14.912 0.146 14.865C0.100 14.819 0.063 14.764 0.038 14.704C0.013 14.643 -0.000 14.579 0.000 14.513C0.000 14.513 0.000 2.040 0.000 2.040C-0.008 1.500 0.191 0.977 0.558 0.580C0.745 0.392 0.969 0.244 1.215 0.146C1.462 0.048 1.726 0.002 1.992 0.011C1.992 0.011 2.256 0.009 2.256 0.009C2.875 -0.031 3.496 0.059 4.079 0.273C4.662 0.487 5.194 0.820 5.641 1.250C5.641 1.250 11.033 5.859 11.033 5.859C11.033 5.859 11.036 5.855 11.036 5.855C11.080 5.911 11.138 5.953 11.205 5.976C11.272 5.998 11.345 6.001 11.413 5.982C11.481 5.964 11.543 5.926 11.589 5.872C11.636 5.819 11.665 5.753 11.674 5.683C11.674 5.683 12.547 2.559 12.547 2.559C12.579 2.481 12.636 2.415 12.709 2.372C12.782 2.328 12.867 2.310 12.951 2.320C13.035 2.331 13.114 2.368 13.175 2.427C13.235 2.486 13.275 2.564 13.288 2.647C13.288 2.647 14.983 10.483 14.983 10.483C14.983 10.483 6.973 10.151 6.973 10.151C6.888 10.153 6.805 10.127 6.736 10.078C6.668 10.028 6.618 9.957 6.593 9.875C6.569 9.794 6.572 9.707 6.602 9.628C6.632 9.549 6.687 9.481 6.759 9.437C6.759 9.437 9.688 8.043 9.688 8.043C9.753 8.024 9.810 7.986 9.854 7.935C9.897 7.884 9.925 7.821 9.934 7.754C9.943 7.687 9.932 7.620 9.903 7.559C9.874 7.498 9.828 7.447 9.771 7.412C9.771 7.412 4.375 2.799 4.375 2.799C4.109 2.517 3.781 2.300 3.418 2.163C3.055 2.026 2.666 1.974 2.280 2.009C2.280 2.009 2.000 2.015 2.000 2.015C2.000 2.015 2.000 14.513 2.000 14.513C2.000 14.645 1.948 14.772 1.854 14.865C1.761 14.959 1.634 15.011 1.502 15.011C1.502 15.011 0.498 15.011 0.498 15.011Z\" fill=\"currentColor\" transform=\"translate(3 2.984)\"/></svg>";
    readonly turn_slight_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.986 11.043C9.986 11.043 9.986 14.504 9.986 14.504C9.986 14.635 9.934 14.762 9.841 14.855C9.748 14.948 9.621 15.000 9.490 15.000C9.490 15.000 8.483 15.000 8.483 15.000C8.418 15.000 8.353 14.987 8.293 14.962C8.233 14.937 8.178 14.901 8.132 14.854C8.086 14.808 8.050 14.754 8.025 14.693C8.000 14.633 7.987 14.568 7.987 14.503C7.987 14.503 7.992 10.896 7.992 10.896C8.038 10.125 7.913 9.353 7.625 8.636C7.337 7.920 6.894 7.276 6.327 6.752C6.327 6.752 3.879 4.686 3.879 4.686C3.836 4.629 3.778 4.586 3.711 4.563C3.645 4.539 3.572 4.536 3.504 4.553C3.435 4.571 3.373 4.608 3.326 4.660C3.279 4.713 3.248 4.778 3.238 4.849C3.238 4.849 2.320 7.959 2.320 7.959C2.287 8.037 2.229 8.102 2.155 8.144C2.082 8.186 1.996 8.203 1.912 8.192C1.828 8.181 1.750 8.142 1.690 8.082C1.630 8.022 1.592 7.944 1.580 7.860C1.580 7.860 0.000 0.000 0.000 0.000C0.000 0.000 8.005 0.450 8.005 0.450C8.090 0.449 8.172 0.476 8.240 0.527C8.308 0.578 8.357 0.649 8.380 0.731C8.403 0.813 8.399 0.900 8.368 0.978C8.337 1.057 8.280 1.124 8.208 1.167C8.208 1.167 5.259 2.518 5.259 2.518C5.191 2.538 5.130 2.577 5.085 2.631C5.040 2.686 5.012 2.752 5.004 2.823C4.997 2.893 5.010 2.964 5.043 3.027C5.076 3.089 5.126 3.141 5.189 3.175C5.189 3.175 7.646 5.249 7.646 5.249C8.443 5.979 9.067 6.878 9.472 7.881C9.877 8.883 10.053 9.964 9.986 11.043Z\" fill=\"currentColor\" transform=\"translate(5 3)\"/></svg>";
    readonly turn_slight_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M2.354 5.249C2.354 5.249 4.811 3.175 4.811 3.175C4.873 3.141 4.924 3.089 4.957 3.027C4.990 2.964 5.003 2.893 4.996 2.823C4.988 2.752 4.960 2.686 4.915 2.631C4.869 2.577 4.809 2.538 4.741 2.518C4.741 2.518 1.792 1.167 1.792 1.167C1.719 1.124 1.663 1.057 1.632 0.978C1.601 0.900 1.596 0.813 1.619 0.731C1.642 0.649 1.692 0.578 1.760 0.527C1.827 0.476 1.910 0.449 1.995 0.450C1.995 0.450 10.000 0.000 10.000 0.000C10.000 0.000 8.419 7.860 8.419 7.860C8.408 7.944 8.369 8.022 8.309 8.082C8.249 8.142 8.171 8.181 8.087 8.192C8.003 8.203 7.918 8.186 7.844 8.144C7.771 8.102 7.713 8.037 7.680 7.959C7.680 7.959 6.762 4.849 6.762 4.849C6.752 4.778 6.721 4.713 6.674 4.660C6.626 4.608 6.564 4.571 6.496 4.553C6.427 4.536 6.355 4.539 6.288 4.563C6.222 4.586 6.163 4.629 6.121 4.686C6.121 4.686 3.673 6.751 3.673 6.751C3.106 7.276 2.663 7.920 2.375 8.636C2.087 9.353 1.962 10.125 2.008 10.895C2.008 10.895 2.013 14.503 2.013 14.503C2.013 14.568 2.000 14.633 1.975 14.693C1.950 14.754 1.914 14.808 1.868 14.854C1.821 14.901 1.767 14.937 1.707 14.962C1.646 14.987 1.582 15.000 1.516 15.000C1.516 15.000 0.510 15.000 0.510 15.000C0.378 15.000 0.252 14.948 0.159 14.855C0.066 14.762 0.014 14.635 0.014 14.504C0.014 14.504 0.014 11.043 0.014 11.043C-0.053 9.964 0.123 8.883 0.528 7.881C0.932 6.878 1.556 5.979 2.354 5.249Z\" fill=\"currentColor\" transform=\"translate(5 3)\"/></svg>";
    readonly turn_straight: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.495 6.966C9.495 6.966 6.543 5.623 6.543 5.623C6.483 5.584 6.414 5.565 6.343 5.566C6.272 5.567 6.204 5.590 6.146 5.630C6.088 5.670 6.043 5.727 6.017 5.793C5.991 5.859 5.985 5.931 6.001 6.000C6.001 6.000 6.001 15.497 6.001 15.497C6.001 15.563 5.988 15.628 5.962 15.689C5.937 15.750 5.900 15.806 5.853 15.853C5.806 15.899 5.751 15.936 5.690 15.962C5.629 15.987 5.563 16.000 5.497 16.000C5.497 16.000 4.504 16.000 4.504 16.000C4.438 16.000 4.372 15.987 4.311 15.962C4.250 15.936 4.195 15.899 4.148 15.853C4.101 15.806 4.064 15.750 4.039 15.689C4.014 15.628 4.001 15.563 4.001 15.497C4.001 15.497 4.001 6.000 4.001 6.000C4.016 5.931 4.010 5.859 3.984 5.793C3.958 5.727 3.914 5.670 3.856 5.630C3.797 5.590 3.729 5.567 3.658 5.566C3.587 5.565 3.518 5.584 3.458 5.623C3.458 5.623 0.506 6.966 0.506 6.966C0.426 6.993 0.339 6.992 0.259 6.964C0.179 6.935 0.110 6.882 0.063 6.811C0.017 6.740 -0.005 6.656 0.001 6.571C0.007 6.487 0.041 6.406 0.097 6.343C0.097 6.343 5.001 0.000 5.001 0.000C5.001 0.000 9.904 6.343 9.904 6.343C9.960 6.406 9.994 6.487 10.000 6.571C10.006 6.656 9.984 6.740 9.938 6.811C9.891 6.882 9.823 6.935 9.743 6.964C9.662 6.992 9.575 6.993 9.495 6.966Z\" fill=\"currentColor\" transform=\"translate(5.009 2)\"/></svg>";
    readonly updown: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M9.904 11.649C9.904 11.649 5.001 17.992 5.001 17.992C5.001 17.992 0.097 11.649 0.097 11.649C0.041 11.585 0.007 11.505 0.001 11.420C-0.005 11.336 0.017 11.252 0.063 11.181C0.110 11.110 0.179 11.056 0.259 11.028C0.339 11.000 0.426 10.999 0.506 11.025C0.506 11.025 3.458 12.369 3.458 12.369C3.518 12.407 3.587 12.427 3.658 12.426C3.729 12.424 3.797 12.402 3.855 12.362C3.914 12.321 3.958 12.265 3.984 12.199C4.010 12.133 4.016 12.061 4.001 11.992C4.001 11.992 4.001 6.000 4.001 6.000C4.016 5.931 4.010 5.859 3.984 5.793C3.958 5.727 3.914 5.670 3.855 5.630C3.797 5.590 3.729 5.567 3.658 5.566C3.587 5.565 3.518 5.584 3.458 5.623C3.458 5.623 0.506 6.966 0.506 6.966C0.426 6.993 0.339 6.992 0.259 6.964C0.179 6.935 0.110 6.882 0.063 6.811C0.017 6.740 -0.005 6.656 0.001 6.571C0.007 6.487 0.041 6.406 0.097 6.343C0.097 6.343 5.001 0.000 5.001 0.000C5.001 0.000 9.904 6.343 9.904 6.343C9.960 6.406 9.994 6.487 10.000 6.571C10.006 6.656 9.984 6.740 9.938 6.811C9.891 6.882 9.823 6.935 9.743 6.964C9.662 6.992 9.575 6.993 9.495 6.966C9.495 6.966 6.543 5.623 6.543 5.623C6.483 5.584 6.414 5.565 6.343 5.566C6.272 5.567 6.204 5.590 6.146 5.630C6.088 5.670 6.043 5.727 6.017 5.793C5.991 5.859 5.985 5.931 6.001 6.000C6.001 6.000 6.001 11.992 6.001 11.992C5.985 12.061 5.991 12.133 6.017 12.199C6.043 12.265 6.088 12.321 6.146 12.362C6.204 12.402 6.272 12.424 6.343 12.426C6.414 12.427 6.483 12.407 6.543 12.369C6.543 12.369 9.495 11.025 9.495 11.025C9.575 10.999 9.662 11.000 9.742 11.028C9.823 11.056 9.891 11.110 9.938 11.181C9.984 11.252 10.006 11.336 10.000 11.420C9.994 11.505 9.960 11.585 9.904 11.649Z\" fill=\"currentColor\" transform=\"translate(5.009 1.008)\"/></svg>";
    readonly uturn_left: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M15.010 5.500C15.010 5.500 15.010 14.997 15.010 14.997C15.010 15.063 14.997 15.128 14.971 15.189C14.946 15.250 14.909 15.306 14.862 15.353C14.815 15.399 14.760 15.436 14.699 15.462C14.638 15.487 14.572 15.500 14.506 15.500C14.506 15.500 13.513 15.500 13.513 15.500C13.447 15.500 13.382 15.487 13.321 15.462C13.259 15.436 13.204 15.399 13.157 15.353C13.110 15.306 13.073 15.250 13.048 15.189C13.023 15.128 13.010 15.063 13.010 14.997C13.010 14.997 13.010 5.500 13.010 5.500C13.010 4.572 12.641 3.682 11.985 3.025C11.328 2.369 10.438 2.000 9.510 2.000C8.581 2.000 7.691 2.369 7.035 3.025C6.378 3.682 6.010 4.572 6.010 5.500C6.010 5.500 6.010 9.500 6.010 9.500C6.010 9.500 6.001 9.500 6.001 9.500C5.985 9.569 5.991 9.641 6.017 9.707C6.043 9.773 6.088 9.830 6.146 9.870C6.204 9.910 6.272 9.933 6.343 9.934C6.414 9.935 6.483 9.916 6.543 9.877C6.543 9.877 9.495 8.534 9.495 8.534C9.575 8.507 9.663 8.508 9.743 8.536C9.823 8.565 9.891 8.618 9.938 8.689C9.984 8.760 10.006 8.844 10.000 8.929C9.994 9.013 9.960 9.094 9.904 9.157C9.904 9.157 5.001 15.500 5.001 15.500C5.001 15.500 0.097 9.157 0.097 9.157C0.041 9.094 0.007 9.013 0.001 8.929C-0.005 8.844 0.017 8.760 0.063 8.689C0.110 8.618 0.179 8.565 0.259 8.536C0.339 8.508 0.426 8.507 0.506 8.534C0.506 8.534 3.458 9.877 3.458 9.877C3.518 9.916 3.587 9.935 3.658 9.934C3.729 9.933 3.797 9.910 3.855 9.870C3.914 9.830 3.958 9.773 3.984 9.707C4.010 9.641 4.016 9.569 4.001 9.500C4.001 9.500 4.010 9.500 4.010 9.500C4.010 9.500 4.010 5.500 4.010 5.500C4.010 4.041 4.589 2.642 5.621 1.611C6.652 0.579 8.051 0.000 9.510 0.000C10.968 0.000 12.367 0.579 13.399 1.611C14.430 2.642 15.010 4.041 15.010 5.500Z\" fill=\"currentColor\" transform=\"translate(1.999 2.5)\"/></svg>";
    readonly uturn_right: "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" width=\"20\" height=\"20\"><path d=\"M15.010 5.500C15.010 5.500 15.010 14.997 15.010 14.997C15.010 15.063 14.997 15.128 14.971 15.189C14.946 15.250 14.909 15.306 14.862 15.353C14.815 15.399 14.760 15.436 14.699 15.462C14.638 15.487 14.572 15.500 14.506 15.500C14.506 15.500 13.513 15.500 13.513 15.500C13.447 15.500 13.382 15.487 13.321 15.462C13.259 15.436 13.204 15.399 13.157 15.353C13.110 15.306 13.073 15.250 13.048 15.189C13.023 15.128 13.010 15.063 13.010 14.997C13.010 14.997 13.010 5.500 13.010 5.500C13.010 4.572 12.641 3.682 11.985 3.025C11.328 2.369 10.438 2.000 9.510 2.000C8.581 2.000 7.691 2.369 7.035 3.025C6.378 3.682 6.010 4.572 6.010 5.500C6.010 5.500 6.010 9.500 6.010 9.500C6.010 9.500 6.001 9.500 6.001 9.500C5.985 9.569 5.991 9.641 6.017 9.707C6.043 9.773 6.088 9.830 6.146 9.870C6.204 9.910 6.272 9.933 6.343 9.934C6.414 9.935 6.483 9.916 6.543 9.877C6.543 9.877 9.495 8.534 9.495 8.534C9.575 8.507 9.663 8.508 9.743 8.536C9.823 8.565 9.891 8.618 9.938 8.689C9.984 8.760 10.006 8.844 10.000 8.929C9.994 9.013 9.960 9.094 9.904 9.157C9.904 9.157 5.001 15.500 5.001 15.500C5.001 15.500 0.097 9.157 0.097 9.157C0.041 9.094 0.007 9.013 0.001 8.929C-0.005 8.844 0.017 8.760 0.063 8.689C0.110 8.618 0.179 8.565 0.259 8.536C0.339 8.508 0.426 8.507 0.506 8.534C0.506 8.534 3.458 9.877 3.458 9.877C3.518 9.916 3.587 9.935 3.658 9.934C3.729 9.933 3.797 9.910 3.855 9.870C3.914 9.830 3.958 9.773 3.984 9.707C4.010 9.641 4.016 9.569 4.001 9.500C4.001 9.500 4.010 9.500 4.010 9.500C4.010 9.500 4.010 5.500 4.010 5.500C4.010 4.041 4.589 2.642 5.621 1.611C6.652 0.579 8.051 0.000 9.510 0.000C10.968 0.000 12.367 0.579 13.399 1.611C14.430 2.642 15.010 4.041 15.010 5.500Z\" fill=\"currentColor\" transform=\"translate(20 0) scale(-1 1) translate(1.999 2.5)\"/></svg>";
};

Inline SVG markup for every direction icon, keyed by icon name.

EFFECTS_METADATA_KEY

Constant

ts
const EFFECTS_METADATA_KEY = "mapmap:effects";

The metadata key a compiled style carries its effects block under. Shared with sn-style (compile.rs) and read back by MapMapMap to auto-enable the route effect for styles that request one.

FEATURESETS

Constant

ts
const FEATURESETS: Readonly<Record<FeaturesetId, readonly string[]>>;

The basemap layer ids each featureset covers. A layer the live style does not carry is skipped (building-3d exists only with 3D buildings on).

FLOW_DEFAULTS

Constant

ts
const FLOW_DEFAULTS: {
    readonly color: "#3a86ff";
    readonly width: 10;
    readonly speed: 0.6;
};

Default flow parameters (exported so docs/tests state one truth).

FULL_ATTRIBUTION

Constant

ts
const FULL_ATTRIBUTION = "\u00A9 OpenStreetMap contributors \u00A9 OpenMapTiles";

Combined attribution stamped on every compiled style's tile source. Legally required (ODbL + CC-BY) - enforced, not themable: no theme field can remove it.

GLOBE_BLEND_GLSL

Constant

ts
const GLOBE_BLEND_GLSL = "uniform mat4 uGlobeMatrix;\nuniform float uGlobeness;\nvec4 mapmapProject(vec4 localPos) {\n  vec4 mercatorPos = projectionMatrix * localPos;\n  if (uGlobeness <= 0.0) return mercatorPos;\n  vec4 globePos = uGlobeMatrix * localPos;\n  if (uGlobeness > 0.999) return globePos;\n  return mix(mercatorPos, globePos, uGlobeness);\n}\n";

The vertex-shader tail every tier-2 layer uses: declare it once, then write gl_Position = mapmapProject(vec4(localPos, 1.0)); where projectionMatrix is ClipMatrices.mercator, uGlobeMatrix is ClipMatrices.globe and uGlobeness is ClipMatrices.transition. The mercator branch is the same expression the layers evaluated before, so mercator output does not move by a bit; the blend is a branch, never a mix on that path. (Variable names avoid flat, a GLSL ES 3.00 keyword.)

GLOBE_RADIUS_M

Constant

ts
const GLOBE_RADIUS_M = 6371008.8;

The prelude's GLOBE_RADIUS: MapLibre's mean Earth radius, metres.

IDENTITY_LUT

Constant

ts
const IDENTITY_LUT: LutBytes;

The identity LUT: lattice point i holds i * 17 (i * 255 / 15 exactly), so lutApply(IDENTITY_LUT, c) returns c for every colour.

KEYED_TILES_TERRITORY

Constant

ts
const KEYED_TILES_TERRITORY = "planet";

The gateway territory a keyed default basemap reads. The gateway serves it from the same planet.pmtiles build as DEFAULT_TERRITORY_TILES_URL, so feature ids, zoom range and the OpenMapTiles schema are identical.

LOGO_SVG

Constant · deprecated

ts
const LOGO_SVG: string;

The Day mark as an SVG string (v2/MapBrand, 79.7 x 16.6 px art box).

Deprecated. Kept so existing imports compile; it is now the v2 Day mark, not the old outline lockup. Use mapBrandSvg("day" | "night").

LUT_BYTES

Constant

ts
const LUT_BYTES: number;

Bytes in a LUT: 16 * 16 * 16 RGB triplets.

LUT_SIZE

Constant

ts
const LUT_SIZE = 16;

Lattice points per axis. Fixed at 16 (Mapbox's size too).

MAPMAP_BASES

Constant

ts
const MAPMAP_BASES: readonly MapMapBase[];

The catalogue, in display order.

MARKER_DEFAULT_COLOUR

Constant

ts
const MARKER_DEFAULT_COLOUR = "#1a6bff";

Default marker colour (MapMap marker blue).

MARKER_GLYPH_IDS

Constant

ts
const MARKER_GLYPH_IDS: readonly ["pin", "dot", "star", "heart", "flag", "home", "work", "food", "cafe", "bar", "shop", "hotel", "parking", "fuel", "charging", "transit", "bike", "camera", "music", "warning", "info"];

The 21 marker glyph ids of the extra.markers v1 contract, in order.

MARKER_GLYPH_VIEWBOX

Constant

ts
const MARKER_GLYPH_VIEWBOX = 24;

The glyph and pin-body coordinate space (a 24x24 viewBox).

MARKER_LABEL_TEXT_SIZES

Constant

ts
const MARKER_LABEL_TEXT_SIZES: Record<MarkerSize, number>;

Label text size in px for each marker size preset.

MARKER_PIN_BODY_PATH

Constant

ts
const MARKER_PIN_BODY_PATH = "M12 24C7 17.2 3 13.2 3 9.4a9 9 0 0 1 18 0C21 13.2 17 17.2 12 24Z";

The coloured pin-body teardrop, 24x24 viewBox: head centre (12, 9.4), radius 9, tip at (12, 24). Every glyph except dot is drawn in white on top of this body, centred on the head.

MARKER_SIZES

Constant

ts
const MARKER_SIZES: readonly ["s", "m", "l"];

The marker size presets, smallest first.

MARKER_SIZES_PX

Constant

ts
const MARKER_SIZES_PX: Record<MarkerSize, number>;

CSS pixel size of each marker preset (the rasterised square canvas).

markerGlyphPaths

Constant

ts
const markerGlyphPaths: Record<MarkerGlyphId, string>;

24x24 viewBox SVG path data for every marker glyph, keyed by id.

MARKERS_ID

Constant

ts
const MARKERS_ID = "mm-user-markers";

The shared GeoJSON source id AND symbol layer id (contract).

MAX_MARKER_ID_LENGTH

Constant

ts
const MAX_MARKER_ID_LENGTH = 64;

Maximum marker id length (contract).

MAX_MARKER_IMAGE_BYTES

Constant

ts
const MAX_MARKER_IMAGE_BYTES: number;

Maximum accepted data: marker-image payload (matches the puck's cap).

MAX_MARKER_ITEMS

Constant

ts
const MAX_MARKER_ITEMS = 200;

Maximum markers per theme (extra.markers v1 contract).

MAX_MARKER_LABEL_LENGTH

Constant

ts
const MAX_MARKER_LABEL_LENGTH = 120;

Maximum marker label length (contract).

MAX_MARKER_TEXT_LENGTH

Constant

ts
const MAX_MARKER_TEXT_LENGTH = 3;

Maximum characters drawn INSIDE a pin head by the short-text mode of renderMarkerImage (numbered waypoints 1, 2, 3; lettered stops A, B). Anything longer belongs in a label below the pin.

MAX_PUCK_IMAGE_BYTES

Constant

ts
const MAX_PUCK_IMAGE_BYTES: number;

Maximum accepted data: puck-image payload (matches Studio's upload cap).

MAX_THEME_GEOJSON_SOURCES

Constant

ts
const MAX_THEME_GEOJSON_SOURCES = 8;

At most this many GeoJSON sources per theme.

MAX_THEME_SOURCES

Constant

ts
const MAX_THEME_SOURCES = 15;

At most this many sources per theme. Mirrors sn_style::MAX_THEME_SOURCES.

NAPTAN_SHORT_CREDIT

Constant

ts
const NAPTAN_SHORT_CREDIT = "Bus stops: NaPTAN, DfT, OGL v3.0";

The short NaPTAN credit the stops source adds to the map's credit line. The full OGL wording is in the tiles index and THIRD-PARTY-NOTICES.md.

Constant

ts
const NAV_ALERT_AUDIO_MODES: readonly ["off", "earcon", "earcon_and_speech"];

Audio channel for a kind: silent, a non-verbal earcon, or an earcon followed by speech naming the kind. Kind is carried in the ICON and in SPEECH, never in the earcon's identity - urgency lives in timbre, so the escalated state is the same motif made more insistent, not a new sound.

Constant

ts
const NAV_ALERT_CHIP_POSITIONS: readonly ["aboveSpeed", "topLeading", "topTrailing"];

Where the chip sits. Constrained slots, never free x/y: the chip must not occlude the current speed or the limit. Covering exactly the two numbers the alert is telling the driver to act on has been the single most-complained-about defect in the category since 2023, and a free position would let a customer reintroduce it.

Constant

ts
const NAV_ALERT_ICON_SETS: readonly ["european", "us", "minimal", "brand"];

Curated icon sets a design can pick for the alert chip and map pins.

Constant

ts
const NAV_ALERT_LEAD_DISTANCE_M: Record<NavAlertLeadDistance, number>;

Metres before the camera at which the alert may first appear, per preset. These are FLOORS, not targets: a host may announce earlier (a motorway closing speed eats 400 m in nine seconds) but never later. Exposed as an enum rather than a numeric field precisely so no design can set a lead below the safety floor.

Constant

ts
const NAV_ALERT_LEAD_DISTANCES: readonly ["short", "standard", "long"];

Lead-distance presets. Not a free number: see NAV_ALERT_LEAD_DISTANCE_M.

Constant

ts
const NAV_ALERT_MODES: readonly ["always", "whenSpeeding", "never"];

When a kind alerts AUDIBLY while driving.

The visual chip is governed by alertWhileDriving and is deliberately unconditional and calm; audio is the escalation channel (the shipping model: the pop-up always appears, the sound only when the driver is over the limit). UI labels must describe the behaviour - "Always alert", "Warn if speeding", "Never alert" - and must never say "Auto", which Organic Maps relabelled after users could not tell what it did.

Constant

ts
const NAV_ALERT_SOUND_BASE_URL = "https://mapmap.ai/earcons/";

Where the built-in earcons are hosted. Public, unmetered and immutable (the files are content-stable; a new sound gets a new name). Pass your own base to navAlertSoundUrl to self-host them - the SDK bundles no audio, exactly like VoiceGuidance's earcon URLs.

Constant

ts
const NAV_ALERT_SOUND_FILES: Record<NavAlertSound, string>;

File name of each built-in earcon, relative to NAV_ALERT_SOUND_BASE_URL. Mono, ~0.5-0.9 s, mixed dry with no reverb tail so they stay crisp over road noise and never trail into the spoken instruction that follows.

Constant

ts
const NAV_ALERT_SOUNDS: readonly ["cameraCalm", "cameraUrgent", "overspeedSoft", "zoneEnter", "zoneClear"];

The built-in earcon library, as a curated enum rather than a free URL.

A design picks ONE sound for the calm alert and ONE for its escalated variant - never one per camera kind. Kind is carried by the icon and by speech; urgency is carried by timbre, so the escalated state is the same motif made more insistent. Per-kind sounds would ask a driver to learn five timbres at 70 mph, which no shipping product does.

zoneEnter / zoneClear are the average-speed corridor pair a host plays at the entry and exit of a corridor. They are offered here too so a design can borrow their timbre, but the corridor itself always uses the pair - it is a boundary crossing, not a point alert.

Constant

ts
const NAV_CAMERA_DEFAULTS: {
    readonly pitch: 60;
    readonly zoom: 17.5;
    readonly speedMps: 12;
};

Defaults for the optional camera block. LOCKSTEP: mirrors NAV_CAMERA_DEFAULTS in website/lib/studio-nav.ts.

Constant

ts
const NAV_CAMERA_KINDS: readonly ["fixed", "average", "red_light", "mobile_site", "unknown"];

Safety-camera kinds a design can style, matching the kind the data model already carries per camera. LOCKSTEP: mirrors NAV_CAMERA_KINDS in website/lib/studio-nav.ts.

WIRE NOTE: the gateway serialises sn_safety::CameraKind lowercase (fixed / average / redlight / unknown); mobile_site is a product-level kind a host may classify itself (the sidecar deliberately leaves an OSM speed_camera=mobile node as unknown rather than overclaiming a fixed installation). Normalise a wire value with navCameraKind before indexing a design.

NO_ROADS_NEAR_ORIGIN

Constant

ts
const NO_ROADS_NEAR_ORIGIN = "urn:sn-gateway:problem:no-roads-near-origin";

The gateway's problem type for an origin with no road near it.

OPENMAPTILES_ATTRIBUTION

Constant

ts
const OPENMAPTILES_ATTRIBUTION = "\u00A9 OpenMapTiles";

The OpenMapTiles schema attribution (CC-BY 4.0).

OSM_ATTRIBUTION

Constant

ts
const OSM_ATTRIBUTION = "\u00A9 OpenStreetMap contributors";

The OSM attribution string. Legally required (ODbL) - never removed.

PALETTE_SLOTS

Constant

ts
const PALETTE_SLOTS: readonly (readonly [string, string, string])[];

The 32 named palette slots as [slot, lightDefault, darkDefault], mirroring sn_style::palette_slots() (and PALETTE_SLOTS in the Studio compiler, website/lib/studio-style.ts). Order is stable and documentation-worthy: it is the order a Studio UI should present them in.

LOCKSTEP: this list, its defaults and the inherit rule in resolvePalette must match the crate and the Studio compiler exactly, or a theme authored in Studio fails to compile in the SDK. A guard test parses crates/sn-style/src/theme.rs and fails on drift.

POI_CATEGORY_COLORS

Constant

ts
const POI_CATEGORY_COLORS: readonly (readonly [string, string])[];

The valid category ids with their built-in dot colours, in presentation order. LOCKSTEP: mirrors POI_CATEGORIES in website/lib/poi-icons.ts.

POI_CATEGORY_IDS

Constant

ts
const POI_CATEGORY_IDS: readonly string[];

The valid category ids, in presentation order.

POI_CLASS_CATEGORIES

Constant

ts
const POI_CLASS_CATEGORIES: Record<string, string[]>;

OpenMapTiles poi layer class values grouped into the categories above; every class not listed falls through to services. LOCKSTEP: mirrors POI_CLASS_CATEGORIES in website/lib/poi-icons.ts.

PROJECTION_UNIFORMS

Constant

ts
const PROJECTION_UNIFORMS: readonly ["u_projection_matrix", "u_projection_tile_mercator_coords", "u_projection_clipping_plane", "u_projection_transition", "u_projection_fallback_matrix"];

The five uniforms MapLibre's projection prelude declares and reads.

RIBBON_FLOATS_PER_VERTEX

Constant

ts
const RIBBON_FLOATS_PER_VERTEX = 5;

Floats per ribbon vertex: x, y (mercator), nx, ny (unit normal), progress.

ROUTE_EFFECTS

Constant

ts
const ROUTE_EFFECTS: Record<RouteEffectName, (geometry: RouteGeometry, options?: RouteFlowOptions) => RouteEffectLayer>;

The effect registry: name -> layer factory. New effects (ambient life, seasonal snow, fog-of-exploration) add an entry here and a name to RouteEffectName.

SIGNAL_BLUE

Constant

ts
const SIGNAL_BLUE = "#3a86ff";

MapMap brand signal blue (see website --signal).

SLOT_ANCHORS

Constant

ts
const SLOT_ANCHORS: Readonly<Record<Slot, {
    before: string;
    fallback: string[];
}>>;

Where each slot resolves: insert before the layer before; when the live style has no such layer, try each fallback entry in turn; when nothing matches, append (top of the stack).

A fallback entry matches a layer when:

  • it ends with - and the layer id starts with it ("road-"), or
  • it is a style-spec layer type and the layer has that type ("symbol"), or
  • it equals the layer id ("city-labels").

The first matching layer in style order wins.

SLOTS

Constant

ts
const SLOTS: readonly Slot[];

Every slot, bottom of the stack first.

SOURCE_LAYERS

Constant

ts
const SOURCE_LAYERS: readonly string[];

Every source-layer the Planetiler (OpenMapTiles-schema) tiles emit. The style skeleton covers all of them; extra layers referencing anything else are rejected. Mirrors sn_style::SOURCE_LAYERS.

TRANSIT_LINE_FALLBACK_COLOUR

Constant

ts
const TRANSIT_LINE_FALLBACK_COLOUR = "#4c72b0";

Line colour where the timetable gives none (the first entry of the MapMap points SDK's colour-blind-aware class palette).

TRANSIT_TILES_INDEX_URL

Constant

ts
const TRANSIT_TILES_INDEX_URL = "https://tiles.mapmap.ai/index.json";

The tiles index the layer reads its archive URLs from.

@mapmap/maps/direction-icons

ts
import { /* … */ } from "@mapmap/maps/direction-icons";

Every export of this entry point is documented above, under @mapmap/maps: 7 names, that is all of them except addBusMarkerImages, AdrCheck, AdrCheckOptions, AdrCheckRequest, AdrCheckResult, AdrDimensions, AdrTunnelCategory, ALERT_CONTRAST_MIN, alertChipContent, AlertChipContent, AlertContrastIssue, alertContrastIssues, alertIconSvg, alertIconUrl, alertPresentation, AlertPresentation, alertSoundUrl, alertSpeedReadoutColor, applyColourTheme, applyGeoJSONDiff, applyPoiDesign, applyTerrain, AttributionPosition, BAKED_MARKERS_GLYPH_ID, BannerComponent, BannerContent, BannerInstruction, bannerLanes, BASE_ID_ALIASES, baseTheme, bearingBetween, bindFlythroughToScroll, BODS_SHORT_CREDIT, buildAdrCheckBody, buildGeocodeUrl, buildLut, buildProbeUrl, buildRetrieveUrl, buildReverseGeocodeUrl, buildRouteQuery, buildRouteUrl, buildStyle, BuildStyleOptions, buildSuggestUrl, buildVertexSource, builtInPoiColor, BUS_DEFAULT_VEHICLE_TYPE, BUS_IMAGES, BUS_INK, BUS_RING_IMAGES, BUS_SPRITE_IMAGES, BUS_STALE_AFTER_S, BUS_VEHICLE_TYPES, busMarkerLayers, busPuckImage, busPuckImageOptions, busSilhouetteSdf, busSpriteBody, busTickImage, busVehicleType, BusVehicleType, CameraAlert, CameraAlertChip, CameraFix, cameraKindLabel, cameraKindsShownOnMap, cameraShownOnMap, cameraSpriteName, cameraSymbolLayer, capTransitBbox, checkSourceUrl, CLIP_DEFAULT_MINZOOM, CLIP_MAX_VERTICES, CLIP_TARGETS, clipFilter, ClipMatrices, ClipOptions, ClipType, ColorThemeSpec, COLOUR_THEME_LAYER_ID, COLOUR_THEME_METADATA_KEY, ColourTheme, ColourThemeLayer, ColourThemeLayerOptions, colourThemeMetadata, contrastRatio, createMap, createRouteEffect, CreditControl, CreditInnerControl, CreditOptions, creditTier, CreditTier, DataLayer, DataLayerCategories, DataLayerClusterOptions, dataLayerColor, DataLayerEvent, DataLayerExtrusionOptions, DataLayerGraduated, DataLayerMode, DataLayerOptions, DataLayerSimpleStyle, DataLayerStyle, DEFAULT_DEBOUNCE_MS, DEFAULT_GATEWAY_URL, DEFAULT_GLYPHS_URL, DEFAULT_MAX_MERCATOR_SEGMENT, DEFAULT_TERRAIN_ATTRIBUTION, DEFAULT_TERRAIN_URL, DEFAULT_TERRITORY_TILES_URL, defaultNavAlertsDesign, defaultNavDesign, defaultPoiDesign, DiagnosticIssue, directionArrow, EFFECTS_METADATA_KEY, effectsFromStyleMetadata, EndpointMarker, EndpointsDesign, extractGuidance, FeaturesetId, featuresetLayerIds, FEATURESETS, FixSet, fixSetFromCollection, FLOW_DEFAULTS, FlowRouteEffectLayer, flythrough, FlythroughController, FlythroughOptions, flythroughPose, FlythroughPose, formatCoord, formatCoords, FULL_ATTRIBUTION, GeocodeHit, GeocodeKind, GeocodeOptions, Geocoder, GeocoderOptions, GLOBE_BLEND_GLSL, GLOBE_RADIUS_M, globeModelMatrix, gradeColourString, gradeStyleColours, GradeStyleOptions, GroundReadableMap, GuidanceBanner, GuidanceSeverity, GuidanceSpokenPrompt, hasBakedMarkers, haversineDistanceM, holdLayersOnTop, IDENTITY_LUT, Interaction, InteractionEvent, InteractionRegistry, InteractionTarget, InteractionType, interpolateFixes, isMarkerGlyphId, isNameTextField, IsochroneError, IsochroneFeatureCollection, IsochroneLayer, IsochroneLayerOptions, isSlot, KEYED_TILES_TERRITORY, keyedStyleUrl, keyedTilesUrl, laneArrowDirection, LaneIndication, languageTextField, LayerOverride, layersOnTopMoves, liveTargetLayerIds, LngLatLike, lngLatToMercator, locateProjectionUniforms, LOGO_SVG, LogoControl, LogoOptions, LogoPosition, LUT_BYTES, LUT_SIZE, lutApply, LutBytes, lutDigest, lutFromBase64, lutFromImageData, lutFromPngData, LutImageData, lutToBase64, lutToImageData, mapBrandSvg, MapBrandTheme, MapDiagnosticsInput, MapDisplayMode, mapGroundTheme, MAPMAP_BASES, MapMapBase, MapMapBaseGroup, MapMapBaseId, MapMapMap, MapMapOptions, MapMapTheme, MARKER_DEFAULT_COLOUR, MARKER_GLYPH_IDS, MARKER_GLYPH_VIEWBOX, MARKER_LABEL_TEXT_SIZES, MARKER_PIN_BODY_PATH, MARKER_SIZES, MARKER_SIZES_PX, MarkerGlyphId, markerGlyphPaths, markerImage, markerImageDataKey, markerImageKey, MarkerItem, MARKERS_ID, MarkersBlock, markersFromTheme, markersFromThemeUrl, MarkerSize, MarkersLayer, MarkersLayerIds, MarkersLayerOptions, markerText, markerTextImageKey, MAX_MARKER_ID_LENGTH, MAX_MARKER_IMAGE_BYTES, MAX_MARKER_ITEMS, MAX_MARKER_LABEL_LENGTH, MAX_MARKER_TEXT_LENGTH, MAX_PUCK_IMAGE_BYTES, MAX_THEME_GEOJSON_SOURCES, MAX_THEME_SOURCES, mercatorModelMatrix, modelClipMatrices, multiplyMat4, namedBase, NAPTAN_SHORT_CREDIT, NAV_ALERT_AUDIO_MODES, NAV_ALERT_CHIP_POSITIONS, NAV_ALERT_ICON_SETS, NAV_ALERT_LEAD_DISTANCE_M, NAV_ALERT_LEAD_DISTANCES, NAV_ALERT_MODES, NAV_ALERT_SOUND_BASE_URL, NAV_ALERT_SOUND_FILES, NAV_ALERT_SOUNDS, NAV_CAMERA_DEFAULTS, NAV_CAMERA_KINDS, NavAlertAudioMode, NavAlertChipPosition, NavAlertIconSet, NavAlertKindDesign, NavAlertLeadDistance, navAlertLeadDistanceM, NavAlertMode, NavAlertsDesign, NavAlertSound, navAlertSoundUrl, NavBannerDesign, NavCameraDesign, navCameraKind, NavCameraKind, NavDesign, navDesignFromTheme, navDesignFromThemeUrl, NavigationCamera, NavigationCameraMode, NavigationCameraOptions, NavPuckDesign, NavRouteDesign, NearestByDriveTimeOptions, NO_ROADS_NEAR_ORIGIN, OPENMAPTILES_ATTRIBUTION, OSM_ATTRIBUTION, osmAndMoreCredit, PALETTE_SLOTS, parseCssColour, ParsedRoute, parseGeocodeResponse, parseHexColor, parseMarkers, parseNavAlertsDesign, parseNavDesign, parseOsrmRoute, parsePoiDesign, parseSuggestResponse, PersistentIds, PersistentLayerOptions, Place, PlacePointFeature, PlacesFeatureCollection, placesFromGeoJSON, PlacesIcon, PlacesInput, PlacesLabelOptions, PlacesLayer, PlacesLayerIds, PlacesLayerOptions, PlacesSelectOptions, PlaceWithDistance, PlaceWithDriveTime, POI_CATEGORY_COLORS, POI_CATEGORY_IDS, POI_CLASS_CATEGORIES, PoiCategoryDesign, PoiDesign, poiDesignFromTheme, poiDesignFromThemeUrl, poiDesignIsDefault, poiTextColorExpression, PositionPuck, PositionPuckOptions, prefersReducedMotion, ProbeUploadOutcome, ProgramCache, PROJECTION_UNIFORMS, ProjectionArgs, ProjectionUniform, projectionVariant, ProjectionVariant, ProtocolHost, ReachabilityMode, readProjection, registerPmtilesProtocol, relativeLuminance, removeTerrain, renderClockMs, Rendered, RenderedMarkerImage, renderMarkerImage, RenderMarkerImageOptions, resetDiagnostics, resolveBaseId, resolveSlot, resolveTerrain, resolveTheme, ReverseGeocodeOptions, RIBBON_FLOATS_PER_VERTEX, RibbonMesh, ROUTE_EFFECTS, RouteEffectLayer, RouteEffectName, RouteFlowOptions, RouteGeometry, RouteLayer, RouteLayerIds, RouteLayerOptions, RouteLineStyle, RouteOptions, RouteProfile, runMapDiagnostics, SearchBox, SearchBoxBias, SearchBoxMap, SearchBoxOptions, SearchBoxSelectEvent, SearchBoxSelectListener, SearchSuggestion, setMapLanguage, setProjectionUniforms, SetRouteEffectOptions, severityProsody, SeverityProsody, shortCredit, shortestArcDeg, shortestArcDelta, ShowReachabilityOptions, SIGNAL_BLUE, Slot, SLOT_ANCHORS, SLOTS, SnappedOrigin, SOURCE_LAYERS, speak, SpeakOptions, sphereFrame, sphereSurface, ssmlToText, StepGuidance, styleFromBase, styleGroundTheme, subdivideMercator, SuggestUrlOptions, sunTimes, SunTimes, supportsTerrainDraping, TerrainOptions, territoryTilesSourceUrl, tessellateRouteRibbon, Theme, ThemeEffects, ThemeScheduler, ThemeSchedulerOptions, ThemeSource, tidyPlaceName, toLngLat, toPmtilesUrl, TRANSIT_LINE_FALLBACK_COLOUR, TRANSIT_TILES_INDEX_URL, transitArchiveUrl, TransitDrawnVehicle, TransitFeedAnswer, TransitFeedReport, TransitFeedStatus, TransitFix, transitFreshnessLabel, TransitSlot, TransitStopFeature, transitStopFromProperties, TransitStopsLayer, TransitStopsLayerOptions, transitTileJsonUrl, transitUrlsFromIndex, TransitVehicle, TransitVehiclesLayer, TransitVehiclesLayerOptions, TruckParams, truncateChars, uploadProbeBatch, UploadProbeOptions, UseTheme, validateColourTheme, validateUseTheme, Vec3, VoiceGuidance, VoiceGuidanceOptions, VoiceGuidanceUpdate, VoiceInstruction.

@mapmap/maps/avatars

ts
import { /* … */ } from "@mapmap/maps/avatars";

Classes (@mapmap/maps/avatars)

AvatarPuck

AvatarPuck

Class

ts
class AvatarPuck { … }

The user's vehicle drawn as a MapMap car. A drop-in for PositionPuck:

ts
import { AvatarPuck } from "@mapmap/maps/avatars";
const car = new AvatarPuck(map, { car: "city", paint: "signal-blue", size: "m" });
car.setLocation({ lat, lon }, headingDeg);

The artwork for the current pitch bucket (about 0.4 MB) is fetched when the puck is created; other buckets load when the camera tilts into them, while the previous one stays on screen. The layer is re-installed after setStyle. If the artwork cannot be loaded or decoded, a PositionPuck is drawn instead and onFallback fires; the API keeps working either way.

PropertyTypeDefaultDescription
readonly sourceIdstringThe GeoJSON source id this puck owns.
readonly layerIdstringThe symbol layer id this puck owns.
readonly carAvatarCarThe current car.
readonly paintAvatarPaintThe current paint.
readonly fallbackAvatarFallbackEvent | undefinedThe fallback reason, if this puck is drawing the Arrow puck instead of the artwork.

Constructor and methods

  • constructor(map: MapMapMap | Map, options?: AvatarPuckOptions)
  • whenReady(): Promise<void>: Resolves once the first pitch bucket's artwork is on the map, or once the puck has fallen back to the Arrow puck (check onFallback). Never rejects.
  • setLocation(location: { lat: number; lon: number; }, headingDeg?: number): void: Moves the vehicle (adding it to the map on the first call). headingDeg is the course, clockwise from north; omit it to keep the previous one. Same glide as PositionPuck.
  • setAvatar(avatar: { car?: AvatarCar; paint?: AvatarPaint; }): void: Swaps the car and/or paint, keeping position and heading. The new artwork loads before it replaces the old, so there is no blank frame. A puck that had fallen back tries the artwork again.
  • remove(): void: Removes the vehicle from the map (cancelling any glide). setLocation adds it again.

Example

ts
import { map } from "./map.ts";
import { AvatarPuck } from "@mapmap/maps/avatars";

const car = new AvatarPuck(map, { car: "city", paint: "signal-blue", size: "m" });
await car.whenReady();
car.setLocation({ lat: 51.5072, lon: -0.1276 }, 45);

Functions (@mapmap/maps/avatars)

avatarAlignment, avatarCellRect, avatarFeatureProperties, avatarIconOffset, avatarIconSize, avatarImageId, avatarModelUrl, avatarPixelRatio, avatarSizePx, avatarSpriteUrl, avatarSymbolLayer, headingBucket, pitchBucket

avatarAlignment

Function

ts
function avatarAlignment(pitch: AvatarPitch): {
    "icon-rotation-alignment": "map" | "viewport";
    "icon-pitch-alignment": "map" | "viewport";
};

The layout properties that differ between the top-down bucket and the pitched ones (not data-driven in MapLibre, so they are set on the layer).

ParameterTypeDefaultDescription
pitchAvatarPitchrequired

Options and types: AvatarPitch.

avatarCellRect

Function

ts
function avatarCellRect(index: number, pixelRatio?: 1 | 2): {
    x: number;
    y: number;
    width: number;
    height: number;
};

The rectangle of heading cell index in a bucket's atlas, in atlas pixels.

ParameterTypeDefaultDescription
indexnumberrequired
pixelRatio?1 | 2not stated

avatarFeatureProperties

Function

ts
function avatarFeatureProperties(car: AvatarCar, paint: AvatarPaint, pitch: AvatarPitch, courseDeg: number, bearingDeg: number, size?: AvatarSize | number): {
    image: string;
    rotate: number;
    size: number;
    offset: [number, number];
};

The feature properties that draw one vehicle: the cell image, its rotation (the course when top-down, 0 when pitched), size and offset. Pair with avatarSymbolLayer; a fleet layer can hold many such features in one GeoJSON source (all in the same pitch bucket).

ParameterTypeDefaultDescription
carAvatarCarrequired
paintAvatarPaintrequired
pitchAvatarPitchrequired
courseDegnumberrequired
bearingDegnumberrequired
size?AvatarSize | numbernot stated

Options and types: AvatarCar, AvatarPaint, AvatarPitch, AvatarSize.

avatarIconOffset

Function

ts
function avatarIconOffset(car: AvatarCar, pitch: AvatarPitch): [number, number];

MapLibre icon-offset (1x cell pixels, scaled by icon-size) that puts the disc centre, not the cell centre, on the vehicle's coordinate.

ParameterTypeDefaultDescription
carAvatarCarrequired
pitchAvatarPitchrequired

Options and types: AvatarCar, AvatarPitch.

avatarIconSize

Function

ts
function avatarIconSize(car: AvatarCar, pitch: AvatarPitch, size?: AvatarSize | number): number;

MapLibre icon-size that makes the disc sizePx CSS pixels wide in a bucket (each bucket's disc is a different width in the cell, so the scale differs by pitch).

ParameterTypeDefaultDescription
carAvatarCarrequired
pitchAvatarPitchrequired
size?AvatarSize | numbernot stated

Options and types: AvatarCar, AvatarPitch, AvatarSize.

avatarImageId

Function

ts
function avatarImageId(car: AvatarCar, paint: AvatarPaint, pitch: AvatarPitch, headingIndex?: number): string;

The style image id of one cell, e.g. mapmap-avatar:city:signal-blue:p58:h090.

ParameterTypeDefaultDescription
carAvatarCarrequired
paintAvatarPaintrequired
pitchAvatarPitchrequired
headingIndex?numbernot stated

Options and types: AvatarCar, AvatarPaint, AvatarPitch.

avatarModelUrl

Function

ts
function avatarModelUrl(car: AvatarCar, options?: {
    lod?: 0 | 1;
    baseUrl?: string;
}): string;

URL of a car's glTF binary model, for your own three.js or deck.gl layer. lod: 1 is the lighter model (about 5k triangles). Repaint it by setting the Paint_GlacierWhite material's baseColorFactor from models/paints.json.

ParameterTypeDefaultDescription
carAvatarCarrequired
options?{ lod?: 0 | 1; baseUrl?: string; }not stated

Options and types: AvatarCar.

avatarPixelRatio

Function

ts
function avatarPixelRatio(car: AvatarCar, size: AvatarSize | number, devicePixelRatio: number): 1 | 2;

Which atlas resolution to load: the 1x set (256 px cells) unless the disc needs more device pixels than a 1x cell holds.

ParameterTypeDefaultDescription
carAvatarCarrequired
sizeAvatarSize | numberrequired
devicePixelRationumberrequired

Options and types: AvatarCar, AvatarSize.

avatarSizePx

Function

ts
function avatarSizePx(size?: AvatarSize | number): number;

A named size or a CSS pixel count, as the disc diameter in CSS pixels.

ParameterTypeDefaultDescription
size?AvatarSize | numbernot stated

Options and types: AvatarSize.

avatarSpriteUrl

Function

ts
function avatarSpriteUrl(car: AvatarCar, paint: AvatarPaint, pitch: AvatarPitch, options?: {
    baseUrl?: string;
    pixelRatio?: 1 | 2;
    ext?: "webp" | "json";
}): string;

URL of one sprite atlas (WebP) or its cell index (ext: "json", the MapLibre sprite JSON shape, for MapLibre Native and other consumers).

ParameterTypeDefaultDescription
carAvatarCarrequired
paintAvatarPaintrequired
pitchAvatarPitchrequired
options?{ baseUrl?: string; pixelRatio?: 1 | 2; ext?: "webp" | "json"; }not stated

Options and types: AvatarCar, AvatarPaint, AvatarPitch.

avatarSymbolLayer

Function

ts
function avatarSymbolLayer(source: string, id: string, pitch?: AvatarPitch): Record<string, unknown>;

A MapLibre symbol layer that draws avatar features (the cameraSymbolLayer pattern): image, rotation, size and offset come from each feature's properties (avatarFeatureProperties); the alignment is the bucket's (avatarAlignment). The vehicle never yields to labels.

ParameterTypeDefaultDescription
sourcestringrequired
idstringrequired
pitch?AvatarPitchnot stated

Options and types: AvatarPitch.

headingBucket

Function

ts
function headingBucket(courseDeg: number, bearingDeg: number): number;

The heading cell (0 to 35) for a vehicle course and a map bearing, both degrees clockwise from north: round(((course - bearing) mod 360) / 10) mod 36. The cell is relative to the camera, so it changes when the map rotates even if the vehicle does not.

ParameterTypeDefaultDescription
courseDegnumberrequired
bearingDegnumberrequired

pitchBucket

Function

ts
function pitchBucket(pitchDeg: number): AvatarPitch;

The pitch bucket for a map pitch (degrees from straight down): the nearest of 0, 30, 45 and 58, with boundaries at 15, 37.5 and 51.5. Pitches above 58 use 58 (the render is then slightly under-tilted, which reads fine up to the SDK's navigation pitch of 60 and beyond).

ParameterTypeDefaultDescription
pitchDegnumberrequired

Interfaces (@mapmap/maps/avatars)

AvatarFallbackEvent, AvatarManifest, AvatarManifestPitch, AvatarPuckOptions

AvatarFallbackEvent

Interface

ts
interface AvatarFallbackEvent

Why an AvatarPuck fell back to the Arrow puck.

PropertyTypeDefaultDescription
reason"load" | "decode" | "unsupported"requiredload: the artwork could not be fetched (network, CORS, 404, timeout); decode: it arrived but could not be decoded; unsupported: the browser has no fetch or createImageBitmap.
url?stringnot statedThe atlas URL involved, when there was one.

AvatarManifest

Interface

ts
interface AvatarManifest

The shape of AVATAR_MANIFEST (generated from the render metadata).

PropertyTypeDefaultDescription
readonly versionstringrequired
readonly licensestringrequired
readonly headingStepDegnumberrequired
readonly headingCountnumberrequired
readonly pitchesreadonly number[]required
readonly atlas{ readonly cellPx: number; readonly columns: number; readonly gapPx: number; }required
readonly carsreadonly { readonly id: string; readonly name: string; readonly discDiameterM: number; readonly pitches: { readonly [pitch: string]: AvatarManifestPitch; }; }[]required
readonly paintsreadonly { readonly id: string; readonly name: string; readonly hex: string; }[]required

AvatarManifestPitch

Interface

ts
interface AvatarManifestPitch

One pitch bucket's sprite geometry, in 1x cell pixels.

PropertyTypeDefaultDescription
readonly anchorPxreadonly [number, number]requiredThe disc centre (the vehicle's position) in the cell, origin top left.
readonly discPxnumberrequiredThe disc's width in the cell.
readonly headingsnumberrequiredCells in this bucket's atlas: 36 when pitched, 1 top-down.
readonly metresPerPxnumberrequiredMetres per cell pixel at the disc centre.

AvatarPuckOptions

Interface

ts
interface AvatarPuckOptions

Options for AvatarPuck.

PropertyTypeDefaultDescription
car?AvatarCar"city"The vehicle (default "city").
paint?AvatarPaint"glacier-white"The paint (default "glacier-white").
size?AvatarSize | numbernot statedDisc diameter: "s" 48, "m" 64 (default), "l" 80 CSS pixels, or a number.
interpolate?booleantrueGlide between fixes instead of snapping (default true), as PositionPuck.
assetBaseUrl?stringAVATAR_ASSET_BASE_URLWhere the artwork is served from (default AVATAR_ASSET_BASE_URL).
beforeId?stringon top of everything, like PositionPuckInsert the layer before this layer id (default: on top of everything, like PositionPuck).
prefetch?"current" | "all-pitches""current": only what is shownAlso fetch the other pitch buckets once the first is drawn (default "current": only what is shown).
onFallback?(event: AvatarFallbackEvent) => voidnot statedCalled once if the artwork cannot be used and the Arrow puck is drawn instead.
loadTimeoutMs?number10000Give up on an atlas request after this long, ms (default 10000).
devicePixelRatio?numberwindow.devicePixelRatioDevice pixel ratio override (default window.devicePixelRatio).
now?() => numberTest seam: clock override, defaults to Date.nowTest seam: clock override, defaults to Date.now.
requestFrame?(callback: () => void) => numberTest seam: frame scheduler override, defaults to rAFTest seam: frame scheduler override, defaults to rAF.
cancelFrame?(handle: number) => voidTest seam: frame canceller override, defaults to cancelAnimationFrameTest seam: frame canceller override, defaults to cancelAnimationFrame.
fetch?FetchLikenot statedTest seam: fetch override.
createImageBitmap?BitmapFactorynot statedTest seam: createImageBitmap override.

Types (@mapmap/maps/avatars)

AvatarCar, AvatarPaint, AvatarPitch, AvatarSize

AvatarCar

Type

ts
type AvatarCar = (typeof AVATAR_MANIFEST.cars)[number]["id"];

A released vehicle: "city" | "tourer" | "suv" | "van".

AvatarPaint

Type

ts
type AvatarPaint = (typeof AVATAR_MANIFEST.paints)[number]["id"];

A paint: "glacier-white" | "signal-blue" | "graphite" | ....

AvatarPitch

Type

ts
type AvatarPitch = 0 | 30 | 45 | 58;

A pitch bucket, degrees from straight down.

AvatarSize

Type

ts
type AvatarSize = "s" | "m" | "l";

A named size: the disc is 48 (s), 64 (m) or 80 (l) CSS pixels across.

Constants (@mapmap/maps/avatars)

AVATAR_ASSET_BASE_URL, AVATAR_CARS, AVATAR_MANIFEST, AVATAR_PAINT_HEX, AVATAR_PAINTS, AVATAR_PITCHES, AVATAR_SIZES

AVATAR_ASSET_BASE_URL

Constant

ts
const AVATAR_ASSET_BASE_URL: string;

Where the artwork is hosted. Public, unmetered, CORS-open and immutable (the path is versioned). Self-hosters serve the same tree from their own gateway and pass assetBaseUrl.

AVATAR_CARS

Constant

ts
const AVATAR_CARS: readonly AvatarCar[];

Every released car, in catalogue order.

AVATAR_MANIFEST

Constant

ts
const AVATAR_MANIFEST: {
    readonly version: "v2";
    readonly license: "MapMap Avatar Artwork Licence v1, https://mapmap.ai/docs/licensing#avatars";
    readonly headingStepDeg: 10;
    readonly headingCount: 36;
    readonly pitches: readonly [0, 30, 45, 58];
    readonly atlas: {
        readonly cellPx: 256;
        readonly columns: 6;
        readonly gapPx: 2;
    };
    readonly cars: readonly [
        {
            readonly id: "city";
            readonly name: "City";
            readonly discDiameterM: 4.1628;
            readonly pitches: {
                readonly "0": {
                    readonly anchorPx: readonly [128, 128];
                    readonly discPx: 220.920236;
                    readonly headings: 1;
                    readonly metresPerPx: 0.018843;
                };
                readonly "30": {
                    readonly anchorPx: readonly [128, 138.663];
                    readonly discPx: 243.54684;
                    readonly headings: 36;
                    readonly metresPerPx: 0.017092;
                };
                readonly "45": {
                    readonly anchorPx: readonly [128, 153.804];
                    readonly discPx: 245.768366;
                    readonly headings: 36;
                    readonly metresPerPx: 0.016938;
                };
                readonly "58": {
                    readonly anchorPx: readonly [128, 165.599];
                    readonly discPx: 245.768366;
                    readonly headings: 36;
                    readonly metresPerPx: 0.016938;
                };
            };
        },
        {
            readonly id: "tourer";
            readonly name: "Tourer";
            readonly discDiameterM: 5.1403;
            readonly pitches: {
                readonly "0": {
                    readonly anchorPx: readonly [128, 128];
                    readonly discPx: 210.867666;
                    readonly headings: 1;
                    readonly metresPerPx: 0.024377;
                };
                readonly "30": {
                    readonly anchorPx: readonly [128, 133.791];
                    readonly discPx: 238.185264;
                    readonly headings: 36;
                    readonly metresPerPx: 0.021581;
                };
                readonly "45": {
                    readonly anchorPx: readonly [128, 143.882];
                    readonly discPx: 245.767453;
                    readonly headings: 36;
                    readonly metresPerPx: 0.020915;
                };
                readonly "58": {
                    readonly anchorPx: readonly [128, 151.656];
                    readonly discPx: 245.767453;
                    readonly headings: 36;
                    readonly metresPerPx: 0.020915;
                };
            };
        },
        {
            readonly id: "suv";
            readonly name: "SUV";
            readonly discDiameterM: 4.8917;
            readonly pitches: {
                readonly "0": {
                    readonly anchorPx: readonly [128, 128];
                    readonly discPx: 214.363968;
                    readonly headings: 1;
                    readonly metresPerPx: 0.02282;
                };
                readonly "30": {
                    readonly anchorPx: readonly [128, 138.527];
                    readonly discPx: 237.200935;
                    readonly headings: 36;
                    readonly metresPerPx: 0.020623;
                };
                readonly "45": {
                    readonly anchorPx: readonly [128, 151.373];
                    readonly discPx: 245.772079;
                    readonly headings: 36;
                    readonly metresPerPx: 0.019903;
                };
                readonly "58": {
                    readonly anchorPx: readonly [128, 161.122];
                    readonly discPx: 245.772079;
                    readonly headings: 36;
                    readonly metresPerPx: 0.019903;
                };
            };
        },
        {
            readonly id: "van";
            readonly name: "Van";
            readonly discDiameterM: 4.9951;
            readonly pitches: {
                readonly "0": {
                    readonly anchorPx: readonly [128, 128];
                    readonly discPx: 213.714232;
                    readonly headings: 1;
                    readonly metresPerPx: 0.023373;
                };
                readonly "30": {
                    readonly anchorPx: readonly [128, 148.194];
                    readonly discPx: 236.208446;
                    readonly headings: 36;
                    readonly metresPerPx: 0.021147;
                };
                readonly "45": {
                    readonly anchorPx: readonly [128, 162.414];
                    readonly discPx: 245.769842;
                    readonly headings: 36;
                    readonly metresPerPx: 0.020324;
                };
                readonly "58": {
                    readonly anchorPx: readonly [128, 172.179];
                    readonly discPx: 245.769842;
                    readonly headings: 36;
                    readonly metresPerPx: 0.020324;
                };
            };
        }
   ];
    readonly paints: readonly [
        {
            readonly id: "glacier-white";
            readonly name: "Glacier White";
            readonly hex: "#F4F6FA";
        },
        {
            readonly id: "signal-blue";
            readonly name: "Signal Blue";
            readonly hex: "#3A86FF";
        },
        {
            readonly id: "graphite";
            readonly name: "Graphite";
            readonly hex: "#2A2F3A";
        },
        {
            readonly id: "silver";
            readonly name: "Silver";
            readonly hex: "#A9B3C2";
        },
        {
            readonly id: "racing-red";
            readonly name: "Racing Red";
            readonly hex: "#E5484D";
        },
        {
            readonly id: "sun-yellow";
            readonly name: "Sun Yellow";
            readonly hex: "#F5C518";
        },
        {
            readonly id: "teal";
            readonly name: "Teal";
            readonly hex: "#0F8B8D";
        },
        {
            readonly id: "magenta";
            readonly name: "Magenta";
            readonly hex: "#F845A2";
        }
   ];
};

The avatar catalogue and sprite geometry this build of the SDK draws with.

AVATAR_PAINT_HEX

Constant

ts
const AVATAR_PAINT_HEX: Readonly<Record<AvatarPaint, string>>;

Each paint's sRGB hex, for pickers and swatches.

AVATAR_PAINTS

Constant

ts
const AVATAR_PAINTS: readonly AvatarPaint[];

Every paint, in catalogue order.

AVATAR_PITCHES

Constant

ts
const AVATAR_PITCHES: readonly AvatarPitch[];

The pitch buckets, ascending.

AVATAR_SIZES

Constant

ts
const AVATAR_SIZES: Readonly<Record<AvatarSize, number>>;

The disc diameter in CSS pixels for each named size.

@mapmap/maps/road-signs

ts
import { /* … */ } from "@mapmap/maps/road-signs";

Functions (@mapmap/maps/road-signs)

resolveRoadRef, resolveSpeedSign, roadRefLabel, roadRefSvg, shieldSpriteName, speedSignLabel, speedSignSvg

resolveRoadRef

Function

ts
function resolveRoadRef(input: RoadRefInput): RoadRef[];

Resolve the shields for one way (SPEC 4.5): one per concurrent route, at most 3, never invented.

ParameterTypeDefaultDescription
inputRoadRefInputrequired

Options and types: RoadRefInput.

resolveSpeedSign

Function

ts
function resolveSpeedSign(input: SpeedSignInput): SpeedSign;

Resolve the speed sign for one road edge (SPEC 4.4). Never guesses a unit.

ParameterTypeDefaultDescription
inputSpeedSignInputrequired

Options and types: SpeedSignInput.

roadRefLabel

Function

ts
function roadRefLabel(ref: Pick<RoadRef, "text" | "tier">, locale?: string): string;

"Motorway M25", "A road A259", "Interstate 95", "US Route 101", "Route nationale 7"; "Autobahn A 9" in German.

ParameterTypeDefaultDescription
refPick<RoadRef, "text" | "tier">required
locale?stringnot stated

Options and types: RoadRef.

roadRefSvg

Function

ts
function roadRefSvg(ref: RoadRef, height: number, opts?: ComposeOptions): string;

The shield as an SVG string height px high, stretched to its text ("" for text-only refs).

ParameterTypeDefaultDescription
refRoadRefrequired
heightnumberrequired
opts?ComposeOptionsnot stated

Options and types: RoadRef, ComposeOptions.

shieldSpriteName

Function

ts
function shieldSpriteName(template: string): string;

Sprite image id of a shield blank in map-assets/sprites (icon-text-fit metadata merged in).

ParameterTypeDefaultDescription
templatestringrequired

speedSignLabel

Function

ts
function speedSignLabel(sign: Pick<SpeedSign, "kind" | "value" | "unit">, locale?: string): string;

"Speed limit 30 miles per hour", "National speed limit, 60 miles per hour", "No speed limit", "20 miles per hour zone".

ParameterTypeDefaultDescription
signPick<SpeedSign, "kind" | "value" | "unit">required
locale?stringnot stated

Options and types: SpeedSign.

speedSignSvg

Function

ts
function speedSignSvg(sign: SpeedSign, size: number, opts?: ComposeOptions): string;

The sign as an SVG string sized size px high ("" when nothing renders). 24 drops the unit caption and legend words; surface: "dark" adds the white halo; fitMode defaults to "official" (the drawings' own numeral widths).

ParameterTypeDefaultDescription
signSpeedSignrequired
sizenumberrequired
opts?ComposeOptionsnot stated

Options and types: SpeedSign, ComposeOptions.

Interfaces (@mapmap/maps/road-signs)

ComposeOptions, CountrySignProfile, FamilySpacing, GenericCountryEntry, GlyphData, Plausible, ResolvedProfile, RoadRef, RoadRefInput, ShieldTier, SignProfileTable, SignTables, SpeedSign, SpeedSignInput

ComposeOptions

Interface · also exported from @mapmap/maps/asset-markers

ts
interface ComposeOptions
PropertyTypeDefaultDescription
surface?Surfacenot stated
fitMode?FitModenot statedNumeral width rule; default "official".

CountrySignProfile

Interface · also exported from @mapmap/maps/asset-markers

ts
interface CountrySignProfile
PropertyTypeDefaultDescription
unitUnitrequired
speedSignFormSpeedSignFormrequired
nationalLimitSign"gb_nsl" | "none"required
noLimitSign"de_end" | "none"required
zoneFormZoneFormrequired
driveOnLeftbooleanrequired
implicitPartial<Record<ImplicitKey, ImplicitValue>>requiredImplicit values in the DISPLAY unit; a missing key means "no statutory default known" -> unknown.
subdivisions?Record<string, Partial<CountrySignProfile>>not statedISO 3166-2 overrides keyed by the Valhalla state_code suffix (WLS, QC, NSW, VLG, CA...).
plausiblePlausiblerequiredSanity bounds in the display unit for engine-only values; outside or off-step -> unknown.
shieldsShieldTier[]required
speedSignTemplate?SpeedTemplateIdnot statedTemplate drawn for a numeric limit when it differs from the form's own (ES ring ratio, SE yellow ground).
numeralFamily?NumeralFamilynot statedNumeral family for the speed sign when it differs from the template's default.

FamilySpacing

Interface · also exported from @mapmap/maps/asset-markers

ts
interface FamilySpacing

A family's word space and pair kerning (numerals|alphabet/<family>/_spacing.json), on the 100-unit cap grid. Kerning keys are two characters ("43": a 4 followed by a 3) or three with a space between ("A 6": the A, a space, the 6; the value is added to the space); the value is added to the left glyph's advance (or to the space).

PropertyTypeDefaultDescription
space?numberWord space advance; the composer's default is 28 unitsWord space advance; the composer's default is 28 units.
kern?Record<string, number>not stated

GenericCountryEntry

Interface · also exported from @mapmap/maps/asset-markers

ts
interface GenericCountryEntry
PropertyTypeDefaultDescription
implicit?Partial<Record<ImplicitKey, ImplicitValue>>not statedImplicit tokens verified for this country (e.g. RO:urban, RU:urban).

GlyphData

Interface · also exported from @mapmap/maps/asset-markers

ts
interface GlyphData
PropertyTypeDefaultDescription
dstringrequiredSingle path, cap height 100, baseline at y = 100.
advancenumberrequiredAdvance width in the same units.

Plausible

Interface · also exported from @mapmap/maps/asset-markers

ts
interface Plausible
PropertyTypeDefaultDescription
minnumberrequired
maxnumberrequired
stepnumberrequired

ResolvedProfile

Interface · also exported from @mapmap/maps/asset-markers

ts
interface ResolvedProfile extends GenericSignProfile

A country profile after alias resolution and subdivision merge.

Extends GenericSignProfile.

PropertyTypeDefaultDescription
countrystringrequired
subdivision?stringnot stated
driveOnLeft?booleannot stated
genericbooleanrequiredTrue when the profile came from the generic Vienna fallback.

RoadRef

Interface · also exported from @mapmap/maps/asset-markers

ts
interface RoadRef
PropertyTypeDefaultDescription
textstringrequiredText shown on the shield (display prefix stripped where the sign does).
tierstringrequiredTier id, "generic" for a ref with no national tier, "text" for refs shown as text only.
countrystringrequiredISO 3166-1 alpha-2, "" when unknown.
a11yLabelstringrequired
template?stringnot statedShield template to draw; absent for text-only refs.

RoadRefInput

Interface · also exported from @mapmap/maps/asset-markers

ts
interface RoadRefInput
PropertyTypeDefaultDescription
ref?stringnot statedWay-level ref, ; separated for concurrencies.
network?stringnot statedRaw OSM route network when there is a single ref.
roadClass?stringnot statedRoad class (motorway, trunk, primary...).
country?stringnot stated
subdivision?stringnot stated
tileNetwork?stringnot statedOpenMapTiles transportation_name.network of the way.
routeNetworks?string[]not statedroute_1..route_6 network values.
routeRefs?string[]not statedroute_1..route_6 ref values; when present they take precedence over ref.
locale?stringnot stated

ShieldTier

Interface · also exported from @mapmap/maps/asset-markers

ts
interface ShieldTier

One road-number tier of a country (SPEC 1.3 and 4.5).

PropertyTypeDefaultDescription
idstringrequiredStable tier id, also the key of the a11y label table (e.g. "gb-motorway", "us-interstate").
templatestringrequiredShield template id under templates/shield/ (2-digit variant for curved shapes).
template3?stringnot statedThree-digit variant for curved shapes (stretchOnly), chosen when the shield text has 3 or more characters.
networks?string[]not statedRaw OSM route network values that select this tier. * matches one colon-free segment.
tileNetworks?string[]not statedOpenMapTiles transportation_name.network values (both gb-* and omt-gb-* spellings).
refPattern?stringnot statedRef-prefix fallback (regular expression source) applied to the way-level ref.
roadClasses?string[]not statedThe ref-prefix fallback applies only on these road classes (e.g. GB primary route = trunk).
subdivisions?string[]not statedTile and ref-prefix matching apply only in these subdivisions (Valhalla state_code suffix).
stripPrefix?stringnot statedPrefix removed from the shield text (regular expression source), e.g. "^I[- ]?" for "I 95".
minzoomnumberrequiredMinimum map zoom for the shield (SPEC 3.5).

SignProfileTable

Interface · also exported from @mapmap/maps/asset-markers

ts
interface SignProfileTable

The canonical profiles.json document.

PropertyTypeDefaultDescription
version1required
countriesRecord<string, CountrySignProfile>required
aliasesRecord<string, string>requiredDependencies and territories that use another country's signs (IM, JE, GG -> GB; PR, GU, VI -> US).
genericGenericSignProfilerequired
genericCountriesRecord<string, GenericCountryEntry>requiredISO 3166-1 alpha-2 codes known to post limits in km/h; anything absent is unknown and renders nothing.

SignTables

Interface · also exported from @mapmap/maps/asset-markers

ts
interface SignTables

Tables injected into the composer (lane 3 embeds them in the generated modules).

PropertyTypeDefaultDescription
numeralsRecord<string, GlyphFamily>requirednumerals/<family>/ glyphs keyed by family then glyph name ("0".."9", "km", "per-h", "SPEED"...).
alphabets?Record<string, GlyphFamily>not statedalphabet/<family>/ glyphs keyed by family then character.
templatesRecord<string, string>requiredTemplate SVG strings keyed by template id (speed and shield ids are disjoint).
spacing?Record<string, FamilySpacing>not statedWord space and pair kerning per family (absent: space 28, no kerning).

SpeedSign

Interface · also exported from @mapmap/maps/asset-markers

ts
interface SpeedSign
PropertyTypeDefaultDescription
kindSpeedSignKindrequired
value?numbernot statedDisplay value in unit (kept for national and zone for the label).
unitUnitrequired
formSpeedSignFormrequired
a11yLabelstringrequired
template?SpeedTemplateIdnot statedTemplate to draw; absent when nothing renders (unknown, walk, none outside DE, unknown country).
family?NumeralFamilynot statedNumeral family for the number slot (profile override of the template default).
country?stringnot statedISO 3166-1 alpha-2 of the profile that resolved the sign.

SpeedSignInput

Interface · also exported from @mapmap/maps/asset-markers

ts
interface SpeedSignInput
PropertyTypeDefaultDescription
maxspeed?stringnot statedRaw OSM maxspeed when the API carries it.
maxspeedType?stringnot statedRaw OSM maxspeed:type when carried.
speedLimitKph?numbernot statedEngine value: 0 unknown, 255 unlimited, 5 walk.
country?stringnot statedISO 3166-1 alpha-2 of the edge.
subdivision?stringnot statedValhalla state_code suffix (WLS, QC, TX...).
locale?stringen-GBBCP 47 locale for the a11y label (default en-GB).

Types (@mapmap/maps/road-signs)

FitMode, GenericSignProfile, GlyphFamily, ImplicitKey, ImplicitValue, NumeralFamily, ShieldTemplateId, SpeedSignForm, SpeedSignKind, SpeedSignTemplateId, SpeedTemplateId, Surface, Unit, ZoneForm

FitMode

Type · also exported from @mapmap/maps/asset-markers

ts
type FitMode = "official" | "figma60";

How wide the numerals may run inside the sign (lead decision 1, 30 Sep 2026; a decision for Matt).

  • "official" (default): the cap height and width of the official drawing wherever one exists (GB P 670, IE TSM ch 5, ES R-301, US R2-1, AU R4-1); where no dimensioned drawing exists (Vienna working values, FR, JP, NZ, CA) the run is capped at 0.62 D (SPEC 3.3).
  • "figma60": the Figma rule of 30 Sep 2026, numerals within 0.60 of the inner disc or box.

GenericSignProfile

Type · also exported from @mapmap/maps/asset-markers

ts
type GenericSignProfile = Omit<CountrySignProfile, "driveOnLeft" | "subdivisions">;

Generic Vienna profile used for km/h countries outside the 20-country table.

GlyphFamily

Type · also exported from @mapmap/maps/asset-markers

ts
type GlyphFamily = Record<string, GlyphData>;

ImplicitKey

Type · also exported from @mapmap/maps/asset-markers

ts
type ImplicitKey = "urban" | "rural" | "trunk" | "motorway" | "living_street" | "bicycle_road" | "nsl_restricted" | "nsl_single" | "nsl_dual" | "zone20" | "zone30" | "zone40";

ImplicitValue

Type · also exported from @mapmap/maps/asset-markers

ts
type ImplicitValue = number | "none" | "walk";

NumeralFamily

Type · also exported from @mapmap/maps/asset-markers

ts
type NumeralFamily = "transport" | "motorway" | "din" | "fhwa" | "fhwa-c" | "fhwa-d" | "l1" | "fr-l1" | "jp" | "ccrige" | "pl" | "no-362" | "alfabeto-stretto" | "se-c31" | "dk";

ShieldTemplateId

Type

ts
type ShieldTemplateId = "au-a" | "au-b" | "au-m" | "au-nh-3" | "au-nh" | "au-nr-3" | "au-nr" | "au-sr-3" | "au-sr" | "ca-on" | "ca-qc-a" | "ca-tch" | "de-a" | "de-b" | "dk-e" | "dk-primary" | "dk-secondary" | "e-road" | "es-a" | "es-n" | "fr-a" | "fr-d" | "fr-e41" | "fr-e42" | "fr-e43" | "fr-e47" | "fr-n" | "gb-motorway" | "gb-nonprimary" | "gb-primary" | "generic" | "ie-m" | "ie-n" | "ie-r" | "it-a-3" | "it-a" | "it-s" | "it-ss" | "jp-e" | "jp-national-3" | "jp-national" | "jp-pref-3" | "jp-pref" | "nl-a" | "nl-n" | "no-e" | "no-fv" | "no-rv" | "nz-sh-3" | "nz-sh" | "pl-a" | "pl-dk" | "pl-dw" | "pl-s" | "pt-a" | "pt-ip" | "pt-other" | "se-e" | "se-rv" | "us-interstate-2" | "us-interstate-3" | "us-route-2" | "us-route-3" | "us-state-3" | "us-state";

Shield template ids (templates/shield/); curved shapes have a "-3" three-digit variant.

SpeedSignForm

Type · also exported from @mapmap/maps/asset-markers

ts
type SpeedSignForm = "gb" | "ie_kmh" | "vienna" | "mutcd" | "ca_maximum" | "ca_qc" | "au" | "jp";

How a numeric limit is drawn (SPEC 4.3).

SpeedSignKind

Type · also exported from @mapmap/maps/asset-markers

ts
type SpeedSignKind = "numeric" | "national" | "none" | "walk" | "zone" | "unknown";

SpeedSignTemplateId

Type

ts
type SpeedSignTemplateId = SpeedTemplateId;

Speed-sign template ids (templates/speed/).

SpeedTemplateId

Type · also exported from @mapmap/maps/asset-markers

ts
type SpeedTemplateId = SpeedSignForm | "es" | "vienna_se" | "vienna_nz" | "vienna_pl" | "vienna_fr" | "vienna_no" | "de" | "at" | "vienna_dk" | "vienna_pt" | "it" | "gb_nsl" | "de_end" | "gb_zone" | "vienna_zone" | "mutcd_zone";

Speed template ids under templates/speed/ (the forms plus the special glyphs and country variants).

Surface

Type · also exported from @mapmap/maps/asset-markers

ts
type Surface = "light" | "dark";

Unit

Type · also exported from @mapmap/maps/asset-markers

ts
type Unit = "mph" | "kmh";

MapMap road signs: speed-limit signs and road-number shields drawn from each country's official dimensions with MapMap's own numerals (no font file), plus the resolvers that turn route data into a sign. Published as @mapmap/maps/road-signs; the website keeps an identical copy.

const sign = resolveSpeedSign({ speedLimitKph: 48, country: "GB" }); // numeric 30 mph const svg = speedSignSvg(sign, 48, { surface: "dark" }); // "" when nothing renders const [ref] = resolveRoadRef({ ref: "M25", country: "GB" }); const badge = roadRefSvg(ref, 24);

Rules: the unit comes from the road's country, never the device; an unknown country, an unknown limit and "walk" render nothing; numerals are paths, so signs never follow font scale. Where a sign is shown, ship signAttributions for GB, IE, AU, NZ and JP (SPEC 2.1).

ZoneForm

Type · also exported from @mapmap/maps/asset-markers

ts
type ZoneForm = "gb_zone" | "vienna_zone" | "mutcd_zone" | "none";

Constants (@mapmap/maps/road-signs)

shieldTemplates, signAlphabets, signAttributions, signNumerals, signProfiles, signSpacing, speedSignTemplates

shieldTemplates

Constant

ts
const shieldTemplates: Record<ShieldTemplateId, string>;

Shield templates with stretch metadata (100 units high at their two-digit width).

signAlphabets

Constant

ts
const signAlphabets: Record<string, GlyphFamily>;

MapMap shield alphabets (alphabet/).

signAttributions

Constant

ts
const signAttributions: Readonly<Record<"GB" | "IE" | "AU" | "NZ" | "JP", string>>;

Attribution to ship wherever signs of these countries are shown (app licences screen, SDK NOTICE; SPEC 2.1). Other countries need none.

signNumerals

Constant

ts
const signNumerals: Record<string, GlyphFamily>;

MapMap numeral families (numerals/): single-path glyphs on a 100-unit cap grid.

signProfiles

Constant

ts
const signProfiles: SignProfileTable;

The canonical country table (map-assets/signs/profiles.json, SPEC 4.3).

signSpacing

Constant

ts
const signSpacing: Record<string, FamilySpacing>;

Word space and pair kerning per family (numerals|alphabet/<family>/_spacing.json).

speedSignTemplates

Constant

ts
const speedSignTemplates: Record<SpeedTemplateId, string>;

Speed-sign templates with their named slots (100 units high).

@mapmap/maps/asset-markers

ts
import { /* … */ } from "@mapmap/maps/asset-markers";

Also re-exports, documented above: ComposeOptions, CountrySignProfile, FamilySpacing, FitMode, GenericCountryEntry, GenericSignProfile, GlyphData, GlyphFamily, ImplicitKey, ImplicitValue, NumeralFamily, Plausible, ResolvedProfile, RoadRef, RoadRefInput, ShieldTier, SignProfileTable, SignTables, SpeedSign, SpeedSignForm, SpeedSignInput, SpeedSignKind, SpeedTemplateId, Surface, Unit, ZoneForm.

Functions (@mapmap/maps/asset-markers)

assetGroupOf, assetIconFor, beamImageId, borderPx, faceShape, faceSvg, facingSvg, layoutFace, markerImageId, puckBox, puckGroup, puckImageId, puckSvg, resolveFace, roadsideMarkerFor, signMarker

assetGroupOf

Function

ts
function assetGroupOf(cat: string): AssetGroupId;

The legend group of a category.

ParameterTypeDefaultDescription
catstringrequired

assetIconFor

Function

ts
function assetIconFor(cat: string, subtype: string | undefined): AssetGlyphId | "face" | "dot";

The glyph, "face" or "dot" for a (category, subtype); an unknown category is the generic puck.

ParameterTypeDefaultDescription
catstringrequired
subtypestring | undefinedrequired

beamImageId

Function

ts
function beamImageId(surface: MarkerSurface): string;

Sprite and image-registry id of the facing beam.

ParameterTypeDefaultDescription
surfaceMarkerSurfacerequired

Options and types: MarkerSurface.

borderPx

Function

ts
function borderPx(tier: MarkerTier, surface: MarkerSurface): number;

The die-cut border around a face, in px: Day a white border with an ink keyline, Night the 0.9 white rim.

ParameterTypeDefaultDescription
tierMarkerTierrequired
surfaceMarkerSurfacerequired

Options and types: MarkerTier, MarkerSurface.

faceShape

Function

ts
function faceShape(id: string): FaceShape | undefined;

The shape of a face id.

ParameterTypeDefaultDescription
idstringrequired

faceSvg

Function

ts
function faceSvg(ref: FaceRef, opts?: {
    size?: number;
    surface?: MarkerSurface;
    tier?: MarkerTier;
    label?: string;
}): string;

A face alone (the detail card header at 48 px by default), with its border. "" when it cannot be drawn.

ParameterTypeDefaultDescription
refFaceRefrequired
opts?{ size?: number; surface?: MarkerSurface; tier?: MarkerTier; label?: string; }not stated

Options and types: FaceRef, MarkerSurface, MarkerTier.

facingSvg

Function

ts
function facingSvg(surface?: MarkerSurface): string;

The facing beam: a soft wedge from the post's foot towards where the face looks, drawn pointing up (north) for icon-rotate by the facing bearing with icon-rotation-alignment: map, anchored at its centre on the measured point, so it always springs from the post's foot. The same ink wedge in both themes. Draw it only where facing is known.

ParameterTypeDefaultDescription
surface?MarkerSurfacenot stated

Options and types: MarkerSurface.

layoutFace

Function

ts
function layoutFace(ref: FaceRef, size: number, surface?: MarkerSurface): FaceLayout | undefined;

Lay out one face (template units) at a nominal size: what was drawn, for tests and legends.

ParameterTypeDefaultDescription
refFaceRefrequired
sizenumberrequired
surface?MarkerSurfacenot stated

Options and types: FaceRef, MarkerSurface.

markerImageId

Function

ts
function markerImageId(refs: FaceRef[], tier: MarkerTier, surface: MarkerSurface): string;

A stable image id for a marker: one per faces, values and words, tier and surface.

ParameterTypeDefaultDescription
refsFaceRef[]required
tierMarkerTierrequired
surfaceMarkerSurfacerequired

Options and types: FaceRef, MarkerTier, MarkerSurface.

puckBox

Function

ts
function puckBox(tier: PuckTier): number;

Image box of a puck, px (square; the disc's centre is the image centre, the anchor).

ParameterTypeDefaultDescription
tierPuckTierrequired

Options and types: PuckTier.

puckGroup

Function

ts
function puckGroup(id: AssetGlyphId, group?: string): AssetGroupId;

The group a glyph's puck is drawn in: group when the sprite has that variant, else the glyph's dominant group.

ParameterTypeDefaultDescription
idAssetGlyphIdrequired
group?stringnot stated

Options and types: AssetGlyphId.

puckImageId

Function

ts
function puckImageId(id: string, surface: MarkerSurface, group?: string): string;

Sprite and image-registry id of a puck: rs-puck-<glyph>-<group>-day|night (a group the glyph has no variant for: its dominant group).

ParameterTypeDefaultDescription
idstringrequired
surfaceMarkerSurfacerequired
group?stringnot stated

Options and types: MarkerSurface.

puckSvg

Function

ts
function puckSvg(id: AssetGlyphId, surface?: MarkerSurface, group?: AssetGroupId): string;

A puck image (SVG) for a glyph: its tier's size and weight, in its legend group's colour (default the dominant group).

ParameterTypeDefaultDescription
idAssetGlyphIdrequired
surface?MarkerSurfacenot stated
group?AssetGroupIdnot stated

Options and types: AssetGlyphId, MarkerSurface, AssetGroupId.

resolveFace

Function

ts
function resolveFace(cat: string, subtype: string | undefined, value: string | number | null | undefined): ResolvedFace | undefined;

The face for a finding (category, subtype, read value); undefined when the category is not a sign.

ParameterTypeDefaultDescription
catstringrequired
subtypestring | undefinedrequired
valuestring | number | null | undefinedrequired

roadsideMarkerFor

Function

ts
function roadsideMarkerFor(cat: string, subtype: string | undefined, value: string | number | null | undefined): RoadsideMarker;

What to draw for a finding: a sign face (sort key 1 regulatory, 2 warning, 3 information), an asset puck (its tier's sort key and minimum zoom, and the legend group whose colour it wears), or a dot. A finding the face map says is not a face (a marking misfiled as a sign, a fingerpost) is drawn as the glyph the rule names.

ParameterTypeDefaultDescription
catstringrequired
subtypestring | undefinedrequired
valuestring | number | null | undefinedrequired

Example

ts
import { roadsideMarkerFor, signMarker, signShortCredit } from "@mapmap/maps/asset-markers";

// A finding from the asset register: category, subtype (if any) and the value read.
const marker = roadsideMarkerFor("speed_limit", undefined, "30");
if (marker.kind === "face") {
  console.log(marker.face);
} else if (marker.kind === "puck") {
  console.log(marker.name, marker.group, marker.minzoom);
}
console.log(signMarker([{ face: "gb-670", value: "30" }])?.width, signShortCredit);

signMarker

Function

ts
function signMarker(refs: FaceRef[], opts?: {
    tier?: MarkerTier;
    surface?: MarkerSurface;
    lift?: number;
}): SignMarker | undefined;

A sign marker: one face or a stack on one post (top first). See SignMarker for the anchor.

ParameterTypeDefaultDescription
refsFaceRef[]required
opts?{ tier?: MarkerTier; surface?: MarkerSurface; lift?: number; }not stated

Options and types: FaceRef, MarkerTier, MarkerSurface.

Example

ts
import { signAttribution, signMarker } from "@mapmap/maps/asset-markers";

// A 30 limit (TSRGD diagram 670) at the full tier, drawn on its post.
const sign = signMarker([{ face: "gb-670", value: "30" }], { tier: "full" });
if (sign) {
  const el = document.createElement("div");
  el.innerHTML = sign.svg; // anchor: sign.anchor ("bottom" on a post)
  el.title = signAttribution; // show the OGL attribution wherever a face is shown
  document.body.append(el);
}

Interfaces (@mapmap/maps/asset-markers)

FaceLayout, FaceRef, FaceRule, FaceTables, ResolvedFace, SignMarker

FaceLayout

Interface

ts
interface FaceLayout
PropertyTypeDefaultDescription
WnumberrequiredWidth and height in template units (height 100).
Hnumberrequired
bodystringrequiredInner markup in template units (no root).
outlinestringrequiredThe outline element alone (no paint), for the die-cut border.
scalenumberrequiredpx per template unit at the requested size.
drawnArray<{ slot: string; text: string; capPx: number; }>requiredWhat was drawn, for tests: words and values, and the rendered cap height of each run in px.

FaceRef

Interface

ts
interface FaceRef

One face: a template id (gb-616) or a state (unresolved-roundel, rear-rect), with its read value or words.

PropertyTypeDefaultDescription
facestringrequired
value?stringnot statedA limit's value as read ("30", "2.6m", "7.5T", 6'6").
text?stringnot statedWords for a plate that carries them (a street name).

FaceRule

Interface

ts
interface FaceRule
PropertyTypeDefaultDescription
catstringrequired
subtypestringrequiredA taxonomy subtype, or "*" for any.
value?stringnot statedCase-insensitive pattern on the read value; its named group v fills value when arg is "$v".
facestringrequiredA face id, a state, or "none" (not a sign face: draw the asset glyph named in glyph).
glyph?stringnot statedWith face "none": the asset glyph (icons/assets) or "dot".
arg?stringnot stated"$v" (the pattern's named group (?<v>...): the value is never positional, so a guard's lookahead can never supply it), a literal value, or "text" (the read value as words on a plate).
priority1 | 2 | 3required1 regulatory, 2 warning, 3 information.
note?stringnot statedWhy the rule was added (its provenance); the resolver never reads it.

FaceTables

Interface

ts
interface FaceTables
PropertyTypeDefaultDescription
templatesRecord<string, string>requiredtemplates/face/*.svg keyed by id.
numeralsGlyphFamilyrequirednumerals/transport (digits, k, m, h, /).
lettersGlyphFamilyrequiredfaces/alphabet/transport (capitals).
nightWhitestringrequiredThe Night white for white grounds (templates/palette.json night "sign/white").
space?numbernot statedWord space of the transport family.

ResolvedFace

Interface

ts
interface ResolvedFace extends FaceRef

Extends FaceRef.

PropertyTypeDefaultDescription
priority1 | 2 | 3required
glyph?stringnot statedWith face "none": the asset glyph to draw instead.
rulenumberrequiredThe rule's index in the map (for tests and debugging).

SignMarker

Interface

ts
interface SignMarker
PropertyTypeDefaultDescription
svgstringrequired
widthnumberrequired
heightnumberrequired
anchor"bottom" | "center"requiredWhere the measured point is: the bottom centre (on a post) or the centre (small tier).

Types (@mapmap/maps/asset-markers)

AssetGlyphId, AssetGroupId, FaceShape, FaceTemplateId, MarkerSurface, MarkerTier, PlateShape, PuckSurface, PuckTier, RoadsideMarker

AssetGlyphId

Type

ts
type AssetGlyphId = "accessibility" | "barrier" | "bench" | "bicycle" | "billboard" | "board" | "bollard" | "bus_stop" | "cabinet" | "cafe" | "cctv" | "communal_bin" | "cone" | "construction" | "crane" | "crossing" | "drinking_fountain" | "ev_charger" | "fence" | "fingerpost" | "gate" | "grit_bin" | "gully" | "hedge" | "heritage_light" | "hydrant" | "info" | "level_crossing" | "litter_bin" | "manhole" | "mast" | "no_waiting" | "other" | "palm" | "parking" | "planter" | "postbox" | "railings" | "road_marking" | "scaffolding" | "shelter" | "skip" | "stall" | "street_light" | "telegraph_pole" | "traffic_calming" | "traffic_signal" | "tree" | "wall";

An asset glyph id (map-assets/icons/assets/).

AssetGroupId

Type

ts
type AssetGroupId = "carriageway" | "furniture" | "green" | "waste" | "commercial" | "works" | "heritage";

A Roadside legend group id.

FaceShape

Type

ts
type FaceShape = "roundel" | "triangle" | "triangle-down" | "octagon" | "rect" | "plate";

A face shape; unread and rear plates are drawn in the shape of the sign they stand for.

FaceTemplateId

Type

ts
type FaceTemplateId = "gb-504-1" | "gb-505-1" | "gb-510" | "gb-512-left" | "gb-512-right" | "gb-543" | "gb-544-1" | "gb-545" | "gb-557-1" | "gb-562" | "gb-601-1" | "gb-602" | "gb-606-ahead" | "gb-606-left" | "gb-606-right" | "gb-609-left" | "gb-609-right" | "gb-610-left" | "gb-610-right" | "gb-611-1" | "gb-612" | "gb-613" | "gb-614" | "gb-615" | "gb-616" | "gb-622-1a" | "gb-629-2a" | "gb-629a" | "gb-642" | "gb-652" | "gb-670" | "gb-671" | "gb-674" | "gb-801" | "gb-811" | "gb-816" | "gb-950" | "gb-956" | "gb-957" | "gb-cycle-route" | "gb-no-waiting" | "gb-parking-plate" | "gb-street-plate";

A face template id (templates/face/).

MarkerSurface

Type

ts
type MarkerSurface = "light" | "dark";

The ground a marker is drawn on: "light" (Day map) or "dark" (Night map).

MarkerTier

Type

ts
type MarkerTier = "small" | "full" | "card";

Zoom tier: "small" (z 16 to 17.5, shape and colour only), "full" (z 17.5 and above, on its post), "card" (the detail card header).

PlateShape

Type

ts
type PlateShape = "roundel" | "triangle" | "rect";

Shapes an unread or rear plate can take.

PuckSurface

Type

ts
type PuckSurface = "light" | "dark";

PuckTier

Type

ts
type PuckTier = "safety" | "furniture" | "ground";

RoadsideMarker

Type

ts
type RoadsideMarker = {
    kind: "face";
    face: ResolvedFace;
} | {
    kind: "puck";
    glyph: AssetGlyphId;
    group: AssetGroupId;
    tier: PuckTier;
    name: string;
    sort: number;
    minzoom: number;
} | {
    kind: "dot";
};

What to draw for a finding.

Constants (@mapmap/maps/asset-markers)

assetFallbackGroup, assetGlyphGroups, assetGlyphInfo, assetGlyphs, assetGroupColours, assetGroups, assetMap, assetTiers, BEAM_PX, faceRules, faceTemplates, MARKER_COLOURS, MIN_CAP_PX, PLATE_MAX_WIDTH, PUCK_COLOURS, PUCK_STYLES, SHAPE_SCALE, signAttribution, signShortCredit, STEM, TIER_PX

assetFallbackGroup

Constant

ts
const assetFallbackGroup: AssetGroupId;

The group a category outside every group falls into.

assetGlyphGroups

Constant

ts
const assetGlyphGroups: Readonly<Record<AssetGlyphId, readonly AssetGroupId[]>>;

Each glyph's legend groups, the dominant one first; the sprite holds one puck per (glyph, group).

assetGlyphInfo

Constant

ts
const assetGlyphInfo: Readonly<Record<AssetGlyphId, {
    name: string;
    tier: PuckTier;
}>>;

Each glyph's name (legend, card) and tier.

assetGlyphs

Constant

ts
const assetGlyphs: Readonly<Record<AssetGlyphId, string>>;

Asset glyphs: 24-unit SVG, currentColor, secondary class="mm2" at 0.35 opacity.

assetGroupColours

Constant

ts
const assetGroupColours: Readonly<Record<MarkerSurface, Readonly<Record<AssetGroupId, string>>>>;

The design system's asset-group palette (--asset-<group>, website/lib/asset-group-palette.ts) by map ground.

assetGroups

Constant

ts
const assetGroups: readonly {
    id: AssetGroupId;
    label: string;
    cats: readonly string[];
}[];

The Roadside legend, in order (a payload stores a group's index): each group's label and categories.

assetMap

Constant

ts
const assetMap: Readonly<Record<string, Readonly<Record<string, AssetGlyphId | "face" | "dot">>>>;

(category, subtype) to a glyph, "face" (a sign) or "dot"; "*" is the category's fallback.

assetTiers

Constant

ts
const assetTiers: Readonly<Record<PuckTier, {
    puck: number;
    minzoom: number;
    sort: number;
}>>;

Tiers: puck size (px), the zoom pucks appear from, and their symbol-sort-key (faces are 1 to 3).

BEAM_PX

Constant

ts
const BEAM_PX = 44;

Size of the facing beam image, px (square; the beam's apex is its centre).

faceRules

Constant

ts
const faceRules: readonly FaceRule[];

The face map rules (map-assets/signs/sources/roadside-face-map.json): first match wins.

faceTemplates

Constant

ts
const faceTemplates: Readonly<Record<FaceTemplateId, string>>;

Face templates (SVG, 100 units high, with slots).

MARKER_COLOURS

Constant

ts
const MARKER_COLOURS: {
    readonly light: {
        readonly ink: "#0f1115";
        readonly ground: "#ffffff";
        readonly unreadFill: "#d4d6d9";
        readonly unreadRing: "#6b6f75";
        readonly rearFill: "#6b6f75";
        readonly rearRail: "#d4d6d9";
        readonly stemOpacity: 0.62;
        readonly keylineOpacity: 0.18;
        readonly shadowOpacity: 0.28;
        readonly beamOpacity: 0.5;
    };
    readonly dark: {
        readonly ink: "#e9eef8";
        readonly ground: "#ffffff";
        readonly unreadFill: "#3e4a66";
        readonly unreadRing: "#a8b4cc";
        readonly rearFill: "#7c89a6";
        readonly rearRail: "#1f2c48";
        readonly stemOpacity: 0.8;
        readonly keylineOpacity: 0;
        readonly shadowOpacity: 0.55;
        readonly beamOpacity: 0.5;
    };
};

Marker colours: the design-system tokens of website/app/globals.css (Day :root, Night [data-theme="dark"]). Faces keep the sign palette; everything around a face is ink.

MIN_CAP_PX

Constant

ts
const MIN_CAP_PX = 4.5;

The smallest rendered cap height, in px, at which a plate's words are still drawn.

PLATE_MAX_WIDTH

Constant

ts
const PLATE_MAX_WIDTH = 4;

A worded plate (a street name) never grows wider than this many nominal sizes.

PUCK_COLOURS

Constant

ts
const PUCK_COLOURS: {
    readonly light: {
        readonly ink: "#0f1115";
        readonly ground: "#ffffff";
        readonly onColour: "#ffffff";
        readonly ringGlyph: "colour";
        readonly shadow: 0.22;
    };
    readonly dark: {
        readonly ink: "#e9eef8";
        readonly ground: "#0a1020";
        readonly onColour: "#ffffff";
        readonly ringGlyph: "ink";
        readonly shadow: 0.5;
    };
};

Design-system tokens (website/app/globals.css): Day :root, Night [data-theme="dark"]. ground is the disc behind a ring puck (and a solid puck's rim): white on Day, Night --ground, so a group colour keeps its 3:1 against it. ink is the colour of a puck with no group (a neutral puck). ringGlyph is the glyph's colour inside a ring or tint puck: the group colour on a Day map; ink on a Night map, where a mid-tone glyph of thin strokes on navy reads dim (the ring carries the colour).

PUCK_STYLES

Constant

ts
const PUCK_STYLES: Readonly<Record<PuckTier, PuckStyle>>;

Tier styles (run marker-colours, 4 Nov 2026: pucks wear their legend group's colour). Safety pucks are the largest and solid; street furniture is smaller, a coloured ring and glyph on the ground; things on the ground are smallest, flat (no shadow: they lie on the ground) and quietest.

SHAPE_SCALE

Constant

ts
const SHAPE_SCALE: Readonly<Record<FaceShape, number>>;

Optical size per shape: a square plate at the nominal size outweighs a roundel and a triangle reads smaller, so a face's longer side is the nominal size times this. Tuned on the review sheet (3 Nov 2026).

signAttribution

Constant

ts
const signAttribution = "Contains public sector information licensed under the Open Government Licence v3.0. Traffic sign images are Crown copyright.";

Show wherever a sign face is shown (OGL v3 attribution A).

signShortCredit

Constant

ts
const signShortCredit = "Sign images Crown copyright, OGL v3";

The one-line map credit form of the attribution.

STEM

Constant

ts
const STEM: {
    readonly length: 9;
    readonly width: 1.5;
    readonly gap: 2;
};

Stem geometry of the full tier, px.

TIER_PX

Constant

ts
const TIER_PX: Readonly<Record<MarkerTier, number>>;

Nominal face size per tier, in px: the longer side of a face, the height of a worded plate twice over.

@mapmap/maps/models

ts
import { /* … */ } from "@mapmap/maps/models";

Classes (@mapmap/maps/models)

ModelLayer, TransitVehicles3dLayer

ModelLayer

Class

ts
class ModelLayer { … }

glTF models as one MapLibre custom layer (renderingMode: "3d", so the basemap's own extrusions occlude the models and the models occlude them). Each model is drawn at its own anchor through modelClipMatrices, so models a continent apart are each placed exactly, on mercator and on the globe. The layer survives setStyle.

PropertyTypeDefaultDescription
readonly idstring
readonly type"custom"
readonly renderingMode"3d"
readonly sceneTHREE.Scene<THREE.Object3DEventMap>The three.js scene (lights and one root per model): an escape hatch.

Constructor and methods

  • constructor(map: MapMapMap, opts?: ModelLayerOptions)
  • onAdd(map: Map, gl: WebGLRenderingContext | WebGL2RenderingContext): void
  • onRemove(): void
  • render(_gl: WebGLRenderingContext | WebGL2RenderingContext, args: unknown): void
  • add(model: ModelSpec): Promise<void>: Load a model and place it. Resolves when it is on the map; rejects with the loader's error (no silent fallback). Adding an id that exists replaces that model.
  • remove(id: string): void: Remove a model (and its clip). Unknown ids are ignored.
  • setPosition(id: string, lngLat: [number, number], altitudeM?: number, bearingDeg?: number): void: Move a model; a clip: true footprint moves with it.
  • models(): string[]: The ids of the models on the map, in the order they were added.
  • dispose(): void: Remove the layer, every model and every clip it added.

Example

ts
import { map } from "./map.ts";
import { ModelLayer } from "@mapmap/maps/models";

// Needs the optional peer dependency three.
const models = new ModelLayer(map);
map.map.addLayer(models);
await models.add({ id: "kiosk", url: "https://example.com/kiosk.glb", lngLat: [-0.1276, 51.5072], bearingDeg: 30 });

TransitVehicles3dLayer

Class

ts
class TransitVehicles3dLayer implements CustomLayerInterface { … }

Live buses as 3D models when the map is tilted at street zoom.

Implements CustomLayerInterface.

PropertyTypeDefaultDescription
readonly idstring
readonly type"custom"
readonly renderingMode"3d"
readonly stats{ rebuilds: number; buses: number; drawCalls: number; }Counters for tests and meters: instance rebuilds, buses drawn, draw calls in the last frame.
readonly activebooleanWhether this device draws 3D buses at all (false on a touch screen unless touch: true).

Constructor and methods

  • constructor(layer2d: TransitVehiclesLayer, options?: TransitVehicles3dOptions)
  • currentFade(): number: How strongly the 3D buses draw right now, 0 to 1.
  • setFixes(vehicles: readonly TransitDrawnVehicle[]): void: The 2D layer's latest drawn vehicles. Rebuilds the instance matrices when the buses can be seen; otherwise keeps them for when they can. Called by the 2D layer's draw tick; there is no need to call it.
  • onAdd(map: Map, gl: WebGLRenderingContext | WebGL2RenderingContext): void
  • onRemove(): void
  • render(_gl: WebGLRenderingContext | WebGL2RenderingContext, args: unknown): void
  • dispose(): void: Remove the layer, hand the sprite back to the 2D layer and free the GPU buffers.

Example

ts
import { map } from "./map.ts";
import { TransitVehiclesLayer } from "@mapmap/maps";
import { TransitVehicles3dLayer } from "@mapmap/maps/models";

// 3D buses when the map is tilted at street zoom, fed by the 2D layer.
const buses = new TransitVehiclesLayer(map, { bbox: "viewport" });
buses.start();
map.map.addLayer(new TransitVehicles3dLayer(buses));

Functions (@mapmap/maps/models)

bearingToRotationY, bus3dFade, busDrawType, busGeometry, busInstances, busScaleFloor, decodeBusModel, defaultLights, doubleDeckerGeometry, followedRingGeometry, footprintPolygon, lngLatFromLocal, loadGlb, localOffset, metresPerPixel, placeModel, roundedRectOutline

bearingToRotationY

Function

ts
function bearingToRotationY(bearingDeg: number): number;

A compass bearing (degrees clockwise from north, seen from above) as a three.js yaw about +Y. NEGATIVE: clockwise from above is a negative rotation about an up axis (the San Francisco landmark sign trap).

ParameterTypeDefaultDescription
bearingDegnumberrequired

bus3dFade

Function

ts
function bus3dFade(view: {
    zoom: number;
    pitch: number;
}, opts: {
    fadeIn: [number, number];
    minPitch: number;
}): number;

How strongly the 3D buses draw, 0 to 1: the zoom fade (fadeIn) times the pitch fade (full from minPitch, nothing 5 degrees below). The 2D sprite draws at 1 - fade.

ParameterTypeDefaultDescription
view{ zoom: number; pitch: number; }required
opts{ fadeIn: [number, number]; minPitch: number; }required

busDrawType

Function

ts
function busDrawType(v: Partial<Pick<TransitDrawnVehicle, "drawAs" | "vehicleType">>, defaultType?: BusVehicleType): BusVehicleType;

The body type a drawn vehicle is drawn as: the 2D layer's drawAs, else its feed type, else defaultType.

ParameterTypeDefaultDescription
vPartial<Pick<TransitDrawnVehicle, "drawAs" | "vehicleType">>required
defaultType?BusVehicleTypenot stated

Options and types: TransitDrawnVehicle, BusVehicleType.

busGeometry

Function

ts
function busGeometry(type?: BusVehicleType, livery?: "day" | "night"): THREE.BufferGeometry;

A modelled UK bus of body type (default the generic one), front facing -Z (north at bearing 0), wheels on y = 0, the door on the nearside (-X), as ONE indexed geometry with vertex colours from the livery slots (BUS_3D_LIVERY): body, glass, a light roof (what reads from above), blank blind, trim, tyres, head and tail lights. Our own geometry, generated by tools/bus-model/build_bus.py.

ParameterTypeDefaultDescription
type?BusVehicleTypenot stated
livery?"day" | "night"not stated

Options and types: BusVehicleType.

busInstances

Function

ts
function busInstances(vehicles: readonly TransitDrawnVehicle[], anchor: [number, number], scale: number, max: number, defaultType?: BusVehicleType): BusInstances;

Instance matrices (column-major 4x4, local metres from anchor, X east, Z south, front facing north at bearing 0) for the max drawable buses nearest the anchor, split by body type (busDrawType). A bus without a heading is left to the 2D layer. A bus is faded (its fleet's dim matrices) when it is stale, or when another vehicle is followed.

ParameterTypeDefaultDescription
vehiclesreadonly TransitDrawnVehicle[]required
anchor[number, number]required
scalenumberrequired
maxnumberrequired
defaultType?BusVehicleTypenot stated

Options and types: TransitDrawnVehicle, BusVehicleType.

busScaleFloor

Function

ts
function busScaleFloor(zoom: number, lat: number, minLengthPx: number, lengthM?: number): number;

The scale on the true-size bus so it is at least minLengthPx long on screen (1 from then on).

ParameterTypeDefaultDescription
zoomnumberrequired
latnumberrequired
minLengthPxnumberrequired
lengthM?numbernot stated

decodeBusModel

Function

ts
function decodeBusModel(type?: BusVehicleType): DecodedBusModel;

One modelled body type's buffers, decoded once and cached: positions from Int16 millimetres, normals from Int8, the slot of every vertex from the slot runs, and the triangle indices from their varint coding (each corner is (next unused vertex - index), so a vertex's first use is 0).

ParameterTypeDefaultDescription
type?BusVehicleTypenot stated

Options and types: BusVehicleType.

defaultLights

Function

ts
function defaultLights(): THREE.Light[];

The London demo's daylight: a sky/ground hemisphere and an afternoon sun from the south-west.

doubleDeckerGeometry

Function

ts
function doubleDeckerGeometry(livery?: "day" | "night"): THREE.BufferGeometry;

The modelled UK double-decker, 10.9 x 2.55 x 4.3 m (busGeometry with "double"): front facing -Z, wheels on y = 0, one indexed geometry with vertex colours from the livery slots.

ParameterTypeDefaultDescription
livery?"day" | "night"not stated

followedRingGeometry

Function

ts
function followedRingGeometry(scale: number, bandM: number, clearanceM?: number, type?: BusVehicleType): THREE.BufferGeometry;

The followed bus's ground ring, in the 2D marker's colours: a white band then an ink band around the footprint of a bus of body type (scale times the true footprint, plus clearanceM), each bandM metres wide, flat on the ground. One geometry with vertex colours.

ParameterTypeDefaultDescription
scalenumberrequired
bandMnumberrequired
clearanceM?numbernot stated
type?BusVehicleTypenot stated

Options and types: BusVehicleType.

footprintPolygon

Function

ts
function footprintPolygon(object: THREE.Object3D, lngLat: [number, number], maxHeightM?: number): Polygon | null;

The lng/lat footprint polygon of a placed model: the convex hull of its base ring, closed. When the ring is degenerate (fewer than 3 distinct points, a model with no flat base) the XZ bounding rectangle of every vertex is used instead.

ParameterTypeDefaultDescription
objectTHREE.Object3Drequired
lngLat[number, number]required
maxHeightM?numbernot stated

lngLatFromLocal

Function

ts
function lngLatFromLocal(anchor: [number, number], x: number, z: number): [number, number];

The inverse of localOffset: the [lng, lat] at local metres (x, z) from anchor.

ParameterTypeDefaultDescription
anchor[number, number]required
xnumberrequired
znumberrequired

loadGlb

Function

ts
function loadGlb(url: string): Promise<THREE.Group>;

Load a .glb (meshopt or plain) and return its scene. Rejects with the loader's own error.

ParameterTypeDefaultDescription
urlstringrequired

localOffset

Function

ts
function localOffset(lngLat: [number, number], anchor: [number, number]): {
    x: number;
    z: number;
};

Local offset in metres (X east, Z south, the three.js frame every MapMap 3D scene uses) of lngLat from anchor, through web mercator at the anchor's scale: (merc - anchorMerc) / meterInMercatorCoordinateUnits(anchor), the same expression the London and San Francisco demos evaluate with maplibregl.MercatorCoordinate.

ParameterTypeDefaultDescription
lngLat[number, number]required
anchor[number, number]required

metresPerPixel

Function

ts
function metresPerPixel(zoom: number, lat: number): number;

Metres per CSS pixel at zoom and latitude lat (512 px tiles).

ParameterTypeDefaultDescription
zoomnumberrequired
latnumberrequired

placeModel

Function

ts
function placeModel(object: THREE.Object3D, placement: Placement, anchor?: [number, number]): THREE.Object3D;

Seat a loaded model: bearing as rotation.y = -bearing, uniform scale, and its origin at localOffset(lngLat, anchor) with y = altitudeM. The model's own origin is its ground point (glTF bakes export Y-up metres with the origin at ground centre). With no anchor the model sits at the scene origin, which is how ModelLayer places each model (every model is drawn at its own anchor). For apps that keep their own scene.

ParameterTypeDefaultDescription
objectTHREE.Object3Drequired
placementPlacementrequired
anchor?[number, number]not stated

Options and types: Placement.

roundedRectOutline

Function

ts
function roundedRectOutline(halfL: number, halfW: number, r: number, n?: number): [number, number][];

The outline of a rounded rectangle centred on the origin in the XZ plane, halfL along Z, halfW along X, corner radius r, n points per corner. Offsetting halfL, halfW and r by the same distance gives the parallel outline point for point, which is how the ring's bands are built.

ParameterTypeDefaultDescription
halfLnumberrequired
halfWnumberrequired
rnumberrequired
n?numbernot stated

Interfaces (@mapmap/maps/models)

BusFleet, BusInstances, DecodedBusModel, ModelLayerOptions, ModelSpec, Placement, TransitVehicles3dOptions

BusFleet

Interface

ts
interface BusFleet

One body type's instance matrices: the buses at full strength and the faded ones.

PropertyTypeDefaultDescription
fullFloat32Arrayrequired
fullCountnumberrequired
dimFloat32Arrayrequired
dimCountnumberrequired

BusInstances

Interface

ts
interface BusInstances

The instance data for one rebuild: a fleet per body type, and where the followed bus is.

PropertyTypeDefaultDescription
fleetsRecord<BusVehicleType, BusFleet>required
countnumberrequiredBuses placed, every type.
followed{ x: number; z: number; rotationY: number; type: BusVehicleType; } | nullrequiredThe followed bus, in local metres from the anchor, or null when it is not drawn.

DecodedBusModel

Interface

ts
interface DecodedBusModel

A modelled bus decoded from the generated data, in metres.

PropertyTypeDefaultDescription
positionsFloat32Arrayrequired
normalsFloat32Arrayrequired
slotsUint8ArrayrequiredThe colour slot of each vertex, an index into the generated slot names (body, glass, roof, blind, trim, tyre, head, tail).
indexUint16Arrayrequired

ModelLayerOptions

Interface

ts
interface ModelLayerOptions
PropertyTypeDefaultDescription
id?string"mapmap-models"Default "mapmap-models".
models?ModelSpec[]not statedModels to add straight away (errors are logged; use add to await them).
slot?Slotdirectly above building-3d when present, else "middle"Insertion slot. Default: directly above building-3d when present, else "middle".
beforeId?stringnot statedInsert below this layer id while it exists (then the slot applies).
terrain?"clamp" | "absolute"not stated"clamp" (default): each model's altitude is above the terrain under its anchor (queryTerrainElevation), so it stands on 3D terrain. Only the anchor is clamped: a long model does not follow the ground (the MapLibre 6.13 draping hooks are the fix, see supportsTerrainDraping). "absolute": altitude is metres above sea level.
lights?"default" | THREE.Light[]not stated"default" (the London demo's daylight) or your own lights.
frustumCulled?falsenot statedAlways false: every object is drawn with frustum culling off. The option only documents it.

ModelSpec

Interface

ts
interface ModelSpec

One glTF model on the map.

PropertyTypeDefaultDescription
idstringrequiredUnique within the layer.
urlstringrequiredA .glb (meshopt-compressed or plain), https or same-origin.
lngLat[number, number]requiredWhere the model's origin (its ground point) stands.
altitudeM?number0Metres above the ground (terrain: "clamp") or above sea level ("absolute"). Default 0.
bearingDeg?number0Compass bearing, degrees clockwise from north. Default 0.
scale?number1Uniform scale; model units are metres. Default 1.
clip?boolean | Polygonnot statedHide the basemap's buildings under the model. true uses the convex hull of the model's base ring (vertices within 0.5 m of its lowest point) projected to lng/lat; a Polygon is used as given.

Placement

Interface

ts
interface Placement

A model's placement, in the shape placeModel reads.

PropertyTypeDefaultDescription
lngLat[number, number]required
altitudeM?numbernot stated
bearingDeg?numbernot stated
scale?numbernot stated

TransitVehicles3dOptions

Interface

ts
interface TransitVehicles3dOptions

Options for TransitVehicles3dLayer.

PropertyTypeDefaultDescription
id?string"mapmap-transit-vehicles-3d"Layer id. Default "mapmap-transit-vehicles-3d".
fadeIn?[number, number][15.5, 16.5]Zoom band over which the 3D buses fade in and the sprite fades out. Default [15.5, 16.5].
minPitch?number30Camera pitch, degrees, from which the 3D buses draw fully (faded in over the 5 degrees below). Default 30.
max?number200Most buses drawn, nearest the centre of the view first. Default 200.
touch?booleanfalse: desktop onlyDraw on touch devices too (a (pointer: coarse) screen). Default false: desktop only.
touchMax?number80Most buses drawn on a touch screen (when touch is on), nearest the centre of the view first. Default 80.
minLengthPx?number40Shortest on-screen length of a bus, CSS px, before it reaches true size. Default 40.
slot?Slotthe SDK's middle slot, under the labelsWhere in the style the layer sits. Default: the SDK's middle slot, under the labels.
beforeId?stringnot statedInsert before this layer id instead of a slot.

Constants (@mapmap/maps/models)

BUS_3D_LIVERY, BUS_DIMENSIONS, DOUBLE_DECKER, TRANSIT_3D_DEFAULTS, TRANSIT_3D_PITCH_RAMP

BUS_3D_LIVERY

Constant

ts
const BUS_3D_LIVERY: {
    readonly day: {
        readonly body: "#15181e";
        readonly glass: "#8fa3bb";
        readonly roof: "#f4f6f8";
        readonly blind: "#2b3038";
        readonly trim: "#4a515c";
    };
    readonly night: {
        readonly body: "#aab3c0";
        readonly glass: "#1c222b";
        readonly roof: "#f1f3f6";
        readonly blind: "#0e1116";
        readonly trim: "#6b7480";
    };
};

The body colours per map ground. Day: the 2D marker's ink with light blue-grey glass and a near-white roof, so a bus stands off the light basemap and reads as a bus (the 0.21.0 slate read grey and small). Night: light grey-blue with dark glass, because an ink bus vanishes on the Night base, whose roads are slate. blind is the blank destination display, trim the bumpers, hatches, hubs and mirror arms.

BUS_DIMENSIONS

Constant

ts
const BUS_DIMENSIONS: Record<BusVehicleType, {
    lengthM: number;
    widthM: number;
    heightM: number;
}>;

Each modelled body type's length, width and height, metres (height to the top of any roof hatch or pod).

DOUBLE_DECKER

Constant

ts
const DOUBLE_DECKER: {
    readonly lengthM: 10.9;
    readonly widthM: 2.55;
    readonly heightM: 4.3;
};

A UK double-decker, metres (the modelled one, roof hatches left out of the height).

TRANSIT_3D_DEFAULTS

Constant

ts
const TRANSIT_3D_DEFAULTS: {
    readonly fadeIn: [number, number];
    readonly minPitch: 30;
    readonly max: 200;
    readonly touch: false;
    readonly touchMax: 80;
    readonly minLengthPx: 40;
};

Defaults for TransitVehicles3dOptions.

TRANSIT_3D_PITCH_RAMP

Constant

ts
const TRANSIT_3D_PITCH_RAMP = 5;

The pitch band, degrees, below minPitch over which the buses fade in.

@mapmap/maps/tiles

ts
import { /* … */ } from "@mapmap/maps/tiles";

Classes (@mapmap/maps/tiles)

TilesLayer

TilesLayer

Class

ts
class TilesLayer { … }

A 3D Tiles tileset as one MapLibre custom layer (renderingMode: "3d"). Survives setStyle.

PropertyTypeDefaultDescription
readonly idstring
readonly type"custom"
readonly renderingMode"3d"
readonly tilesTilesRendererThe 3DTilesRendererJS renderer: an escape hatch (plugins, events, errorTarget).
readonly sceneTHREE.Scene<THREE.Object3DEventMap>The three.js scene the tiles are drawn in.

Constructor and methods

  • constructor(map: MapMapMap, opts: TilesLayerOptions)
  • getAnchor(): [number, number] | null: The [lng, lat] the tileset is drawn at, once its root has loaded (or given).
  • onAdd(map: Map, gl: WebGLRenderingContext | WebGL2RenderingContext): void
  • onRemove(): void
  • render(_gl: WebGLRenderingContext | WebGL2RenderingContext, args: unknown): void
  • dispose(): void: Remove the layer, its clip and every loaded tile.

Example

ts
import { map } from "./map.ts";
import { TilesLayer } from "@mapmap/maps/tiles";

// Needs the optional peer dependencies three and 3d-tiles-renderer.
const tiles = new TilesLayer(map, { url: "https://example.com/tileset/tileset.json" });
map.map.addLayer(tiles);

Interfaces (@mapmap/maps/tiles)

TilesLayerOptions

TilesLayerOptions

Interface

ts
interface TilesLayerOptions

@mapmap/maps/tiles: OGC 3D Tiles 1.0 / 1.1 on a MapMap map through 3DTilesRendererJS (3d-tiles-renderer, Apache-2.0, NASA JPL / AMMOS): TilesLayer.

ts
import { TilesLayer } from "@mapmap/maps/tiles";
const tiles = new TilesLayer(map, { url: "https://example.com/tileset.json" });

Its own subpath (from 0.19.0; it was in @mapmap/maps/models before), because it is the only importer of 3d-tiles-renderer: a bundler resolves every import of a module it includes, static or dynamic, so an app that draws glTF models alone must not have to install it. Needs both optional peers, three and 3d-tiles-renderer.

The tileset is re-centred so its anchor (by default the centre of its own root bounding volume) is the local origin, with X east, Y up and Z south, the frame every MapMap 3D scene uses, and then drawn through the same bridge as ModelLayer (modelClipMatrices, GLOBE_BLEND_GLSL injected into every tile's materials as it loads).

Level of detail and culling in TilesRenderer need a camera with a real view matrix, which a MapLibre custom layer does not get. The layer reconstructs one each frame: projectionMatrix is MapLibre's view-to-clip matrix P, and the view in the tileset's local metres is inverse(P) * ClipMatrices.mercator, so P * view is exactly the matrix the tiles are drawn with. On the globe below the globe-to-mercator zoom band the mercator reconstruction is an approximation (the tileset is a few pixels across there); cap maxDepth if a tileset over-refines.

PropertyTypeDefaultDescription
id?string"mapmap-tiles"Default "mapmap-tiles".
urlstringrequiredThe tileset's tileset.json URL.
anchor?[number, number]the centre of its root bounding volume[lng, lat] the tileset is re-centred on. Default: the centre of its root bounding volume.
errorTarget?number16Screen-space error target in pixels (3DTilesRendererJS errorTarget). Default 16.
maxDepth?numberunlimitedDeepest tile level to load. Default unlimited.
clip?Polygonnot statedHide the basemap's buildings inside this polygon (map.addClip).
slot?Slotnot stated
beforeId?stringnot stated
terrain?"clamp" | "absolute"not stated"absolute" (default): the tileset's own heights (above the WGS84 ellipsoid) are used as metres above the map's datum. "clamp": the tileset is lifted by the terrain elevation under its anchor, for tilesets authored with height 0 at the ground.

@mapmap/maps/live

ts
import { /* … */ } from "@mapmap/maps/live";

Classes (@mapmap/maps/live)

AuroraLayer, EarthEventsLayer, WeatherLayer, WindLayer

AuroraLayer

Class

ts
class AuroraLayer { … }

The NOAA SWPC aurora forecast, drawn on the night side.

PropertyTypeDefaultDescription
readonly ids{ source: string; layers: string[]; }

Constructor and methods

  • constructor(map: MapMapMap, options?: AuroraLayerOptions)
  • start(): void: Read the forecast now and every refreshMs. Safe to call before the style has loaded.
  • stop(): void: Stop polling. What is drawn stays.
  • remove(): void: Stop, and remove the layer, the credit carrier and every listener. Safe to call twice.
  • setTime(atMs: number | null): void: Move the sun (the night gate) to a scene time; null is now. The aurora is drawn only within 3 hours of now.
  • report(): AuroraReport

Example

ts
import { map } from "./map.ts";
import { AuroraLayer } from "@mapmap/maps/live";

const aurora = new AuroraLayer(map);
aurora.start();

EarthEventsLayer

Class

ts
class EarthEventsLayer { … }

Live Earth events: quakes, volcano alerts and fire cells.

PropertyTypeDefaultDescription
readonly ids{ source: Record<EventType, string>; layers: string[]; }The source ids by type, and every layer id this layer owns.

Constructor and methods

  • constructor(map: MapMapMap, options?: EarthEventsLayerOptions)
  • start(): void: Start reading and drawing. Safe to call before the style has loaded.
  • stop(): void: Stop polling. What is drawn stays.
  • remove(): void: Stop, and remove every layer, source, image and listener. Safe to call twice.
  • setTypes(types: EventType[]): void: The types drawn from now on; a type switched on is read at once.
  • setBase(base: EventsBase): void: The map ink; quake rings re-paint without a refetch.
  • setBbox(bbox: EarthEventsLayerOptions["bbox"]): void: The area to ask the gateway for (a refetch).
  • report(): EarthEventsReport: The feeds' state after the latest poll.
  • select(detail: EventDetail | null): void: Ring a quake (or clear with null); other kinds only open onSelect.
  • pulsing(): string[]: Quake ids pulsing now or waiting to (for tests).

Example

ts
import { map } from "./map.ts";
import { EarthEventsLayer } from "@mapmap/maps/live";

const events = new EarthEventsLayer(map, { types: ["quake", "volcano"], minMagnitude: 4 });
events.start();

WeatherLayer

Class

ts
class WeatherLayer { … }

Forecast colour fields and pressure lines.

PropertyTypeDefaultDescription
readonly ids{ source: string[]; layers: string[]; }The credit carrier source, and every layer id currently installed.

Constructor and methods

  • constructor(map: MapMapMap, options?: WeatherLayerOptions)
  • start(): void: Load the manifest and show the frame nearest now. Never plays. Safe before the style has loaded.
  • stop(): void: Stop playback and any fetch. What is drawn stays.
  • remove(): void: Stop, and remove every layer, source and listener. Safe to call twice.
  • setField(field: WeatherField | null): void: Draw a field (or null for none). Opening a field with nothing else on shows the live hour.
  • setIsobars(on: boolean): void: Draw the pressure lines.
  • seek(index: number): void: Ask for frame index (clamped). The old frame stays up until it is drawable.
  • setTime(atMs: number | null): void: Show the frame whose valid time is nearest atMs (null: now).
  • play(on: boolean): void: Play the frames, 750 ms each with a 1.5 s hold on the last, looping. A failed frame stops it.
  • setBase(base: "light" | "dark"): void: The map ink; fields and lines are rebuilt for it without a refetch of the manifest.
  • frames(): WeatherFrame[]: The 17 frames of the newest run, oldest first.
  • report(): WeatherReport

Example

ts
import { map } from "./map.ts";
import { WeatherLayer } from "@mapmap/maps/live";

const weather = new WeatherLayer(map, { field: "rain" });
weather.start();
weather.play(true);

WindLayer

Class

ts
class WindLayer { … }

Wind particles from the NOAA GFS forecast. Forecast, not an observation.

PropertyTypeDefaultDescription
readonly ids{ source: string[]; layers: string[]; }The layer ids this layer owns while installed.

Constructor and methods

  • constructor(map: MapMapMap, options?: WindLayerOptions)
  • start(): void: Load the manifest and the frame for now. Safe to call before the style has loaded.
  • stop(): void: Stop fetching. What is drawn stays (the particles keep moving).
  • remove(): void: Stop, and remove every layer, source, image and listener. Safe to call twice.
  • setTime(atMs: number | null): void: Show the frame whose valid time is nearest atMs (null: now). A new frame crossfades the velocity (280 ms) with no particle reset.
  • setDim(factor: number): void: Multiply the trails' alpha, 0 to 1 (under a colour field the host dims the wind; see windDimUnderField).
  • setVisible(on: boolean): void
  • setFollowing(on: boolean): void: True while a follow camera drives the map: small programmatic moves keep the trails.
  • setBase(base: "light" | "dark"): void: The map ink; the particles and arrows are rebuilt for it without a refetch.
  • report(): WindReport
  • sample(lngLat: [number, number]): { u: number; v: number; speedMs: number; headingDeg: number; } | null: The wind at a point from the frame shown, read back from its pixels once; null before a frame is ready.

Example

ts
import { map } from "./map.ts";
import { WindLayer } from "@mapmap/maps/live";

const wind = new WindLayer(map);
wind.start();
console.log(wind.sample([-0.1276, 51.5072])?.speedMs);

Functions (@mapmap/maps/live)

auroraLabel, buildFieldMesh, decodeValue, detailFromFeature, equirectUv, eventIds, fieldStops, hexRgb01, liveFetch, mercatorY, nearestFrameIndex, parseAuroraFile, pickWindFrame, preferHalf, quakeRadius, solarElevationDeg, subsolarPoint, timeAgo, windDimUnderField, windHeadingDeg, windSpeed

auroraLabel

Function

ts
function auroraLabel(kp: number | null | undefined): string;

The row's readout: "Quiet" under Kp 3, else "Kp 4" (rounded); "Unavailable" without one.

ParameterTypeDefaultDescription
kpnumber | null | undefinedrequired

buildFieldMesh

Function

ts
function buildFieldMesh(stepDeg?: number): FieldMesh;

A lng/lat grid over the whole sphere, stepDeg per cell, with its top and bottom rows at the poles. Pole vertices carry the flag MapLibre's prelude reads (rawPos.y beyond +-32767.5) so they land exactly on the pole on the globe and are culled on the flat map.

ParameterTypeDefaultDescription
stepDeg?numbernot stated

decodeValue

Function

ts
function decodeValue(r: number, g: number, b: number, encoding: Pick<FieldEncoding, "scale" | "offset">): number;

The value a 24-bit pixel encodes.

ParameterTypeDefaultDescription
rnumberrequired
gnumberrequired
bnumberrequired
encodingPick<FieldEncoding, "scale" | "offset">required

Options and types: FieldEncoding.

detailFromFeature

Function

ts
function detailFromFeature(ids: Pick<EventIds, "quakeRing" | "quakeCore" | "volcano" | "fire">, f: {
    layer?: {
        id?: string;
    };
    properties?: Record<string, unknown> | null;
    geometry?: {
        type?: string;
        coordinates?: unknown;
    };
}): EventDetail | null;

What a tapped feature opens, or null. layerId is the layer the feature came from.

ParameterTypeDefaultDescription
idsPick<EventIds, "quakeRing" | "quakeCore" | "volcano" | "fire">required
f{ layer?: { id?: string; }; properties?: Record<string, unknown> | null; geometry?: { type?: string; coordinates?: unknown; }; }required

Options and types: EventIds.

equirectUv

Function

ts
function equirectUv(lng: number, lat: number, width?: number, height?: number): [number, number];

Texture coordinates of a point in the equirect PNG (texel centres: column c is at 180 W + c x 0.25 deg, row r at 90 N - r x 0.25 deg). The u coordinate wraps (REPEAT), so 180 E lands back on column 0.

ParameterTypeDefaultDescription
lngnumberrequired
latnumberrequired
width?numbernot stated
height?numbernot stated

eventIds

Function

ts
function eventIds(id: string): EventIds;

The source, layer and image ids for a prefix.

ParameterTypeDefaultDescription
idstringrequired

fieldStops

Function

ts
function fieldStops(field: WeatherFieldId, base: "light" | "dark"): FieldStop[];

The ramp a field is drawn with on a base.

ParameterTypeDefaultDescription
fieldWeatherFieldIdrequired
base"light" | "dark"required

hexRgb01

Function

ts
function hexRgb01(hex: string): [number, number, number];
ParameterTypeDefaultDescription
hexstringrequired

liveFetch

Function

ts
function liveFetch(url: string, options?: LiveFetchOptions): Promise<Response>;

fetch for a live file or endpoint. Rejects on a non-2xx answer with the problem+json code in the message ("HTTP 501 weather-frames-not-enabled"), or "HTTP 404" when the body carries none.

ParameterTypeDefaultDescription
urlstringrequired
options?LiveFetchOptionsnot stated

Options and types: LiveFetchOptions.

mercatorY

Function

ts
function mercatorY(latDeg: number): number;

Web-mercator y (0..1, 0 at 85.05 N) for a latitude; beyond +-85.05 it runs past 0..1, which the globe prelude maps back to the true latitude.

ParameterTypeDefaultDescription
latDegnumberrequired

nearestFrameIndex

Function

ts
function nearestFrameIndex(frames: WeatherFrame$1[], atMs: number): number;

The frame whose valid time is nearest atMs (the earlier on a tie), or -1.

ParameterTypeDefaultDescription
framesWeatherFrame$1[]required
atMsnumberrequired

parseAuroraFile

Function

ts
function parseAuroraFile(body: unknown): AuroraFile | null;

The file's fields, or null when it is not one. Both shapes parse.

ParameterTypeDefaultDescription
bodyunknownrequired

pickWindFrame

Function

ts
function pickWindFrame(manifest: WeatherManifest$1, atMs: number, base: string, { half }?: {
    half?: boolean;
}): ChosenWindFrame | null;

The wind frame whose valid time is nearest atMs, from the newest run that has wind at all. Frame paths are relative to the weather base. Returns null when the manifest has no usable wind frame.

ParameterTypeDefaultDescription
manifestWeatherManifest$1required
atMsnumberrequired
basestringrequired
{ half }?{ half?: boolean; }not stated

preferHalf

Function

ts
function preferHalf(zoom: number, touch: boolean): boolean;

Half-resolution frames at globe zoom and on touch screens; full from zoom 4 on a pointer device (CONTRACT.md 3.2, the shared client rule; lane 1B's weather-field.ts carries the same rule for the colour fields).

ParameterTypeDefaultDescription
zoomnumberrequired
touchbooleanrequired

quakeRadius

Function

ts
function quakeRadius(mag: number): number;
ParameterTypeDefaultDescription
magnumberrequired

solarElevationDeg

Function

ts
function solarElevationDeg([lng, lat]: [number, number], atMs: number): number;

Solar elevation in degrees at [lng, lat] for a moment: 90 minus the great-circle distance to the subsolar point (spherical cosine rule).

ParameterTypeDefaultDescription
[lng, lat][number, number]required
atMsnumberrequired

subsolarPoint

Function

ts
function subsolarPoint(atMs: number): [number, number];

Subsolar point [lng, lat] for a moment (epoch milliseconds).

ParameterTypeDefaultDescription
atMsnumberrequired

timeAgo

Function

ts
function timeAgo(then: number, now: number): string;

"Just now", "38 min ago", "5 h ago", "3 days ago".

ParameterTypeDefaultDescription
thennumberrequired
nownumberrequired

windDimUnderField

Function

ts
function windDimUnderField(zoom: number): number;
ParameterTypeDefaultDescription
zoomnumberrequired

windHeadingDeg

Function

ts
function windHeadingDeg(u: number, v: number): number;

The compass bearing the air moves TOWARDS, degrees clockwise from north (an arrow's icon-rotate). Meteorology quotes where wind comes FROM; an arrow on a map points where it goes.

ParameterTypeDefaultDescription
unumberrequired
vnumberrequired

windSpeed

Function

ts
function windSpeed(u: number, v: number): number;

Speed in metres per second.

ParameterTypeDefaultDescription
unumberrequired
vnumberrequired

Interfaces (@mapmap/maps/live)

AuroraFile, AuroraLayerOptions, AuroraReport, AuroraSource, EarthEventsFeedReport, EarthEventsLayerOptions, EarthEventsReport, EventIds, FieldEncoding, FieldMesh, FieldStop, LiveFetchOptions, WeatherFrame, WeatherLayerOptions, WeatherManifest, WeatherReport, WeatherSource, WindFrameRef, WindLayerOptions, WindMeta, WindReport, WindSource

AuroraFile

Interface

ts
interface AuroraFile

The aurora forecast's fields: the box's latest.json, or the gateway's GET /v1/space-weather envelope (either parses to this).

PropertyTypeDefaultDescription
observation_timestringrequired
forecast_timestringrequired
kpnumberrequired
kp_time?string | nullnot stated
max_probability?numbernot stated
generated_at?stringnot stated
attribution?stringnot stated
png?stringnot statedThe grid PNG URL when the envelope names one (aurora.png); the envelope's wins.

AuroraLayerOptions

Interface

ts
interface AuroraLayerOptions
PropertyTypeDefaultDescription
nightOnly?booleantrueDraw only where the sun is below the horizon, eased by the night factor. Default true.
breathe?booleantrueThe 12 s breathe (alpha x 0.85 to 1). Default true; off under reduced motion.
refreshMs?number300,000Poll interval, milliseconds. Default 300,000; at least 60,000.
onReport?(report: AuroraReport) => voidnot stated
source?AuroraSourcenot stated
baseUrl?stringnot stated
apiKey?stringnot stated
id?string"mapmap-aurora"Id prefix. Default "mapmap-aurora".
slot?LiveSlot"middle"Where in the style the layer sits. Default "middle".
beforeId?LiveBeforeIdnot statedInsert before this layer (or the layer a function returns) instead of the slot's.

AuroraReport

Interface

ts
interface AuroraReport
PropertyTypeDefaultDescription
status"off" | "loading" | "ready" | "unavailable" | "now-only"required
kpnumber | nullrequired
forecastTimestring | nullrequired
observationTimestring | nullrequired
labelstringrequiredauroraLabel(kp): "Kp 4", "Quiet", "Unavailable", or "Now only".

AuroraSource

Interface

ts
interface AuroraSource

Where the layer reads from, other than the map's gateway.

PropertyTypeDefaultDescription
jsonUrlstringrequiredlatest.json on a box host, or a GET /v1/space-weather URL.
pngUrl?stringthe JSON's aurora.png, or latest.png beside a box JSONThe grid PNG. Default: the JSON's aurora.png, or latest.png beside a box JSON.

EarthEventsFeedReport

Interface

ts
interface EarthEventsFeedReport
PropertyTypeDefaultDescription
status"ok" | "stale" | "unknown" | "error"required
countnumber | nullrequiredQuakes and volcano alerts in the answer; fire detections (not cells) for fires. Null before the first answer.
fetchedAtstring | nullrequired
ageSnumber | nullrequired
labelstringrequired"48 today", "6 alerts", "23,499 detections", "Unavailable", "Loading".

EarthEventsLayerOptions

Interface

ts
interface EarthEventsLayerOptions
PropertyTypeDefaultDescription
types?EventType[]all threeWhich types to draw. Default all three.
bbox?[number, number, number, number] | "world"one fetch, the files are global[west, south, east, north] for the gateway's bbox, or "world" (default: one fetch, the files are global).
minMagnitude?number2.5Smallest quake magnitude, 2.5 to 9. Default 2.5.
pollMs?Partial<Record<EventType, number>>60,000 (quakes), 600,000 (volcanoes), 1,800,000 (fires)Poll interval per type, milliseconds. Defaults 60,000 (quakes), 600,000 (volcanoes), 1,800,000 (fires); at least 30,000.
base?EventsBasenot statedThe map ink: "light" (default) or "dark".
pulse?booleantrueOne 6 s ring per quake first seen this session and under 2 h old. Default true; never under reduced motion.
popup?(detail: EventDetail) => string | HTMLElementnot statedA tap opens a popup built from this. Omit for none.
onSelect?(detail: EventDetail | null) => voidnot statedCalled with the tapped event, or null when a tap hits none (see clearOnEmptyClick).
clearOnEmptyClick?booleantrueWhether a tap on empty map clears the selection: it calls onSelect(null), drops the quake ring and closes the popup. Default true. Set false and an empty tap does none of those: an open card and its ring stay until the host calls select(null) (its close button, Esc).
deferToLayers?string[]not statedLayer ids that win a tap. When one of them has a feature under the tap (a satellite or bus layer, say), the layer ignores the tap entirely: no onSelect, no popup change, the ring stays. Ids not on the map are skipped.
onReport?(report: EarthEventsReport) => voidnot statedCalled after every poll and every change of what is drawn.
source?EarthEventsSourcenot stated
baseUrl?stringnot stated
apiKey?stringnot stated
id?string"mapmap-events"Id prefix. Default "mapmap-events".
slot?LiveSlot"middle"Where in the style the layer sits. Default "middle".
beforeId?LiveBeforeIdnot statedInsert before this layer (or the layer a function returns) instead of the slot's.

EarthEventsReport

Interface

ts
interface EarthEventsReport
PropertyTypeDefaultDescription
quakeEarthEventsFeedReportrequired
volcanoEarthEventsFeedReportrequired
fireEarthEventsFeedReportrequired
receivedAtnumber | nullrequiredWhen the last answer arrived, epoch milliseconds.
errorbooleanrequiredTrue when the last poll of any drawn type failed.

EventIds

Interface

ts
interface EventIds
PropertyTypeDefaultDescription
sourceRecord<EventType, string>required
quakeCorestringrequired
quakePulsestringrequired
quakeRingstringrequired
volcanostringrequired
firestringrequired
fireHeatstringrequired
iconstringrequired
layersRecord<EventType, string[]>required

FieldEncoding

Interface

ts
interface FieldEncoding

encodings.<field> in the manifest.

PropertyTypeDefaultDescription
unitstringrequired
scalenumberrequired
offsetnumberrequired
maplibre{ encoding: "custom"; redFactor: number; greenFactor: number; blueFactor: number; baseShift: number; }required

FieldMesh

Interface

ts
interface FieldMesh
PropertyTypeDefaultDescription
verticesFloat32ArrayrequiredPer vertex: mercator x, mercator y, u, v, pole flag (-1 N, 1 S, 0).
indicesUint32Arrayrequired
columnsnumberrequired
rowsnumberrequired

FieldStop

Interface

ts
interface FieldStop
PropertyTypeDefaultDescription
valuenumberrequired
colourstringrequired
alphanumberrequired

LiveFetchOptions

Interface

ts
interface LiveFetchOptions
PropertyTypeDefaultDescription
apiKey?string | undefinednot statedThe API key. Sent as Authorization: Bearer <key> under baseUrl only.
baseUrl?string | undefinednot statedThe gateway origin the key belongs to (the map's baseUrl).
signal?AbortSignal | undefinednot stated

WeatherFrame

Interface

ts
interface WeatherFrame

One frame of the newest run.

PropertyTypeDefaultDescription
runstringrequiredThe run's time (ISO).
hournumberrequiredForecast hour.
validAtstringrequiredThe valid time (ISO).
keystringrequiredThe frame's id in layer and source names, e.g. 2026101700-f006.

WeatherLayerOptions

Interface

ts
interface WeatherLayerOptions
PropertyTypeDefaultDescription
field?WeatherField | nullnull: nothing until setFieldThe field to draw. Default null: nothing until setField.
isobars?booleanfalseDraw the pressure lines (with the polar fade). Default false.
resolution?"auto" | "full" | "half"not stated"auto" (default): half at globe zoom and on touch, full from zoom 4 on a pointer device.
base?"light" | "dark"not statedThe map ink: "light" (default) or "dark".
opacity?number1Field opacity multiplier, 0 to 1. Default 1.
stops?Partial<Record<WeatherField, FieldStop[]>>not statedYour own colour ramp per field.
prefetch?number2Frames installed hidden ahead of the shown one. Default 2.
maxTextures?number6Baked frames kept on the GPU. Default 6.
onReport?(report: WeatherReport) => voidnot statedCalled after every change of what is shown or loaded.
onError?(message: string, frameKeys: string[]) => voidnot statedCalled when a frame's file cannot be loaded.
source?WeatherSourcenot stated
baseUrl?stringnot stated
apiKey?stringnot stated
id?string"mapmap-weather"Id prefix. Default "mapmap-weather".
slot?LiveSlot"middle"Where in the style the layer sits. Default "middle".
beforeId?LiveBeforeIdnot statedInsert before this layer (or the layer a function returns) instead of the slot's.

WeatherManifest

Interface

ts
interface WeatherManifest extends Omit<WeatherManifest$1, "models">

The manifest as the weather views read it: wind-field.ts's shape plus the encodings and the field keys. Extends, never replaces, the wind one.

Extends Omit<WeatherManifest$1, "models">.

PropertyTypeDefaultDescription
encodings?Partial<Record<WeatherFieldId, FieldEncoding>>not stated
models?{ gfs?: { runs?: { run: string; generated_at?: string; frames?: WeatherFrameRef[]; }[]; }; }not stated

WeatherReport

Interface

ts
interface WeatherReport
PropertyTypeDefaultDescription
status"loading" | "ready" | "unavailable"required
manifestStatus"ok" | "stale" | "unknown"requiredThe manifest's freshness: stale when older than 7 hours.
fieldWeatherField | nullrequired
isobarsbooleanrequired
framesWeatherFrame[]required
indexnumberrequiredThe frame asked for.
playingbooleanrequired
resolution"full" | "half" | nullrequiredThe resolution on screen, or null when no field is drawn.
failed{ field: WeatherField; frameKey: string; reason: string; } | nullrequiredSet while the hour asked for could not be loaded.
unavailablePartial<Record<WeatherField, string>>requiredFields that cannot be drawn for the hour asked for, with plain words.
legend{ unit: string; stops: { value: number; colour: string; alpha: number; }[]; ticks: number[]; } | nullrequired
label"Forecast, not an observation"requiredAlways "Forecast, not an observation".

WeatherSource

Interface

ts
interface WeatherSource

Where the layer reads from, other than the map's gateway.

PropertyTypeDefaultDescription
manifestUrlstringrequiredThe manifest, or a GET /v1/weather/frames URL.
basestringrequiredThe base the frame paths resolve against (ends with a slash).
tiles?(gatewayId: string, ext: "png" | "mvt") => string${baseUrl}/tiles/${id}/{z}/{x}/{y}.${ext}The isobars tile source for a gateway tile id. A template with {z}/{x}/{y} becomes a vector tiles source; anything else (pmtiles://..., a TileJSON URL) becomes its url. Default: ${baseUrl}/tiles/${id}/{z}/{x}/{y}.${ext}.

WindFrameRef

Interface

ts
interface WindFrameRef
PropertyTypeDefaultDescription
hournumberrequired
valid_atstringrequired
wind{ png: string; json: string; } | nullrequired
half?{ wind?: { png: string; json: string; } | null; } | nullnot statedManifest v3 (lane 1E, CONTRACT.md 3.2): the 720 x 361 frame set, same orientation and encodings. Optional: absent until the pipeline builds it.

WindLayerOptions

Interface

ts
interface WindLayerOptions
PropertyTypeDefaultDescription
particles?number65,536, or 16,384 on touchParticle count; rounded up to a square state texture. Default 65,536, or 16,384 on touch.
fade?number0.94Trail fade per frame, 0 to 1. Default 0.94.
base?"light" | "dark"not stated"dark" draws pale particles (the night globe), "light" (default) dark ink.
lowPower?booleanon touch screensCap the animation at about 30 fps. Default: on touch screens.
resolution?"auto" | "full" | "half"not stated"auto" (default): half-resolution frames at globe zoom and on touch.
fallback?"arrows" | "none"not statedWhat to draw under reduced motion or when a shader fails: "arrows" (default) or "none".
firstPictureWaitMs?number2500How long the first frame waits for the map's first complete picture (idle) before it is drawn, in ms. Default 2500. 0 draws it as soon as it is decoded, for a page where the wind is the first picture. The frame downloads during the wait either way.
onReport?(report: WindReport) => voidnot stated
onError?(message: string) => voidnot stated
source?WindSourcenot stated
baseUrl?stringnot stated
apiKey?stringnot stated
id?string"mapmap-wind"Id prefix. Default "mapmap-wind".
slot?LiveSlot"middle"Where in the style the layer sits. Default "middle".
beforeId?LiveBeforeIdnot statedInsert before this layer (or the layer a function returns) instead of the slot's.

WindMeta

Interface

ts
interface WindMeta

One wind frame's sidecar (f<hhh>.json).

PropertyTypeDefaultDescription
sourcestringrequired
runstringrequired
forecast_hournumberrequired
valid_atstringrequired
widthnumberrequired
heightnumberrequired
uMinnumberrequired
uMaxnumberrequired
vMinnumberrequired
vMaxnumberrequired
label?stringnot stated

WindReport

Interface

ts
interface WindReport
PropertyTypeDefaultDescription
status"loading" | "ready" | "unavailable"required
mode"particles" | "arrows" | nullrequired"particles", or "arrows" for the static fallback; null before a frame is ready.
reason"reduced-motion" | "gpu" | nullrequired
frame{ run: string; hour: number; validAt: string; } | nullrequired
resolution"full" | "half" | nullrequired
label"Forecast, not an observation"requiredAlways "Forecast, not an observation".

WindSource

Interface

ts
interface WindSource

Where the layer reads from, other than the map's gateway.

PropertyTypeDefaultDescription
manifestUrlstringrequiredThe manifest, or a GET /v1/weather/frames URL.
basestringrequiredThe base the frame paths resolve against (ends with a slash).

Types (@mapmap/maps/live)

EarthEventsSource, EventDetail, EventsBase, EventType, WeatherField

EarthEventsSource

Type

ts
type EarthEventsSource = {
    url: string;
} | {
    files: Record<EventType, string>;
    status: string;
};

Where the layer reads from, other than the map's gateway.

EventDetail

Type

ts
type EventDetail = {
    kind: "quake";
    id: string;
    lng: number;
    lat: number;
    mag: number;
    place: string;
    time: number;
    depthKm: number | null;
    url: string;
} | {
    kind: "volcano";
    id: string;
    lng: number;
    lat: number;
    name: string;
    colorCode: string;
    alertLevel: string;
    sentUtc: string | null;
    noticeUrl: string;
    observatory: string;
    coverage: string;
} | {
    kind: "fire";
    cell: string;
    lng: number;
    lat: number;
    count: number;
    maxFrp: number;
    highConfidenceShare: number;
    acqDate: string;
    label: string;
};

What a tap on an event opens. A fire cell always carries label; a volcano coverage.

EventsBase

Type

ts
type EventsBase = "light" | "dark";

The map ink the quake ring is drawn in.

EventType

Type

ts
type EventType = "quake" | "volcano" | "fire";

The three kinds of event.

WeatherField

Type

ts
type WeatherField = WeatherFieldId;

The four colour fields.

Constants (@mapmap/maps/live)

AURORA_SHORT_CREDIT, AURORA_STALE_MS, DEFAULT_LIVE_LABEL, EVENT_TYPES, EVENTS_SHORT_CREDITS, FIELD_PNG_HEIGHT, FIELD_PNG_WIDTH, FIRES_HONEST, VOLCANOES_HONEST, WEATHER_FIELDS, WEATHER_SHORT_CREDIT, WIND_PARTICLES_DESKTOP, WIND_PARTICLES_TOUCH

AURORA_SHORT_CREDIT

Constant

ts
const AURORA_SHORT_CREDIT = "Aurora: NOAA SWPC forecast";

AURORA_STALE_MS

Constant

ts
const AURORA_STALE_MS: number;

A forecast older than this is not drawn and reads "Unavailable": the box timer has stopped, and an hour-old forecast is no longer one.

DEFAULT_LIVE_LABEL

Constant

ts
const DEFAULT_LIVE_LABEL = "Feed status unknown";

The label a live layer reports before anything vouches for its feed.

EVENT_TYPES

Constant

ts
const EVENT_TYPES: readonly EventType[];

All three event types, in draw order (bottom to top: fires, quakes, volcanoes).

EVENTS_SHORT_CREDITS

Constant

ts
const EVENTS_SHORT_CREDITS: Record<EventsFeed, string>;

Each source's short credit, carried on its map source (attribution), so the one credit line names it while the layer is on.

FIELD_PNG_HEIGHT

Constant

ts
const FIELD_PNG_HEIGHT = 721;

FIELD_PNG_WIDTH

Constant

ts
const FIELD_PNG_WIDTH = 1440;

A weather colour field drawn from the pipeline's global equirectangular PNG (lane E, <field>_png: 1440 by 721, row 0 at 90 N, column 0 at 180 W, value-encoded 24-bit RGB), on the globe and the flat map, to the poles. Lane D's primary renderer (coordinator note, 13 Oct 2026); the PMTiles + color-relief path in weather-layers.ts is the per-frame fallback.

Why a custom layer: the tiled field costs 36 to 53 range requests and 2.5 to 3.7 s per frame at globe zoom (spike section 5) and smears its top row into a fan at the pole. One PNG per frame is one request, and a mesh that runs to the poles covers them.

How:

  • Bake once per frame. The PNG is uploaded as bytes (no colour management, no premultiply) and one off-screen pass decodes every texel with the manifest's formula, (R*65536 + G*256 + B) * scale + offset, and colours it with the design ramp (the same piecewise-linear rule as color-relief), into a premultiplied RGBA8 texture with mipmaps. Decoding before filtering is the point: filtering the encoded bytes would blend the digits of two numbers.
  • Draw every frame through MapLibre's projection prelude (tier 1 in web-sdk custom-layer-projection.ts, the wind layer's path): a 1.5 degree mesh in web-mercator 0..1, plus pole vertices flagged the way MapLibre flags its own, so projectTile puts it on the sphere, the flat map, or the blend between them.
  • Crossfade in one pass. Up to two frames are bound at once and summed by their opacities, so the field never dims mid-fade.

The layer never fetches on the main thread's critical path: the blob is fetched and decoded (createImageBitmap) off it, and only the upload and the bake (one quad over 1440 by 721) run inside prerender.

FIRES_HONEST

Constant

ts
const FIRES_HONEST = "Satellite-detected heat, not confirmed fires";

The honest labels (contract section 8).

VOLCANOES_HONEST

Constant

ts
const VOLCANOES_HONEST = "US-monitored volcanoes only";

WEATHER_FIELDS

Constant

ts
const WEATHER_FIELDS: readonly WeatherField[];

The fields, in the order a control would list them.

WEATHER_SHORT_CREDIT

Constant

ts
const WEATHER_SHORT_CREDIT = "Weather: NOAA GFS forecast, processed by MapMap";

The credit on the map line for everything drawn from NOAA GFS: wind, rain, temperature and pressure. One string for all of them, so the credit line carries it once however many weather layers are on. NOAA asks that processed data is never presented as unaltered, so it says processed.

WIND_PARTICLES_DESKTOP

Constant

ts
const WIND_PARTICLES_DESKTOP = 65536;

Particle counts by device class (contract section 11).

WIND_PARTICLES_TOUCH

Constant

ts
const WIND_PARTICLES_TOUCH = 16384;