# @elabs-ai/components-maps > MapLibre GL maps: MapCanvas, markers, popups, controls, routes, arcs, GeoJSON, clusters. Import from `@elabs-ai/components-maps`. Part of brand-ui — see the root `llms.txt` for routing. ## Components - DEFAULT_MAP_HEIGHT - MAP_BREAKPOINT_THRESHOLDS - MAP_BREAKPOINTS - MAP_CORNERS - MAP_LABEL_ANCHORS - MapAnnotation - MapAnnotationKey - MapArc - MapCanvas — Root MapLibre canvas — theme-aware basemap; the ref is the raw MapLibre Map. With `plan` it is a non-geographic plan instead (a floor, a plant, a carriage) and every layer inside speaks plan units. - avoid: Hiding MapLibre's attribution control — the default Carto basemap styles/tiles require it. - avoid: Importing maplibre-gl CSS in the app — MapCanvas imports its own CSS plus the brand popup overrides. - avoid: Rendering it in an RSC/SSR path with no client boundary — MapLibre needs WebGL. - avoid: Mapping plan units into DEGREES to fake a plan coordinate system — degrees are not linear on screen, so a 16:9 plan renders at 2:1. Declare `plan` and let createPlanCrs map into normalized Mercator, where a rectangle stays a rectangle at every zoom. - avoid: Leaving rotation and pitch on for a plan — a tilted floor plan is unreadable. The `plan` prop turns dragRotate, pitchWithRotate and touchPitch off; do not switch them back on. - avoid: Combining `plan` with a globe projection — a plan is flat; the projection is ignored with a one-time warning. - MapClusterLayer — Clusters dense point data into count bubbles that split apart as you zoom in. - avoid: Hardcoding the cluster step colors — the steps resolve from the status tokens. - avoid: Clustering a handful of points — plain MapMarkers read better below roughly 50 points. - avoid: Using it on a plan map — the count is a symbol text-field, and a plan's blank style has no glyph endpoint, so every count renders as nothing. Group the points yourself and draw them with MapGeoJSON. - MapControls - MapGeoJSON - MapInset - MapLegend - MapMarker — A point on the map, optionally carrying content, a label, a popup or a tooltip. - avoid: Hardcoding a marker color — resolve a semantic token; WebGL can't read CSS variables directly. - avoid: Hundreds of individual markers — switch to MapClusterLayer above roughly 50 points. - MapMarkerContent - MapMarkerLabel - MapMarkerPopup - MapMarkerTooltip - MapNorthArrow - MapPlanImage — The picture under a plan's shapes — a floor plan, a blueprint, a site photo — placed by its corner coordinates in plan units. - avoid: One baked-in-colour picture for every theme — a white floor plan either glares or swallows the data ink on a dark theme. Prefer vector-only, else swap the asset on the resolved theme, else desaturate it and dim it. - avoid: Tearing the component down to hide a floor — set `visible` (a visibility change) or swap `src`, so nothing refetches and nothing cross-fades. - avoid: Zooming a raster far past its native resolution — past roughly 2× it is mush; the shapes stay crisp, so let them carry the detail. - MapPlanLegend — The key to a plan's status channels — the tone swatch, the outline style and the word, so the textures and dashes on the canvas mean something. - avoid: Leaving it out because the colours are 'obvious' — the texture and the dash are the channels greyscale keeps, and nobody guesses what a dash means without a key. - avoid: Writing the status words in the component — they are a `labels` prop so an app can localize them. - MapPlanOverlay — The keyboard and label layer of a plan: one real