How the map composes
MapState defines a
logical map, including its base style and declarative style content.
MaplibreMap presents that state in Compose UI. Android hosts can also
present it on a caller-owned Surface. MapState provides camera,
viewport, projection, and feature-query operations while the map is attached.
The style is base plus content
Section titled “The style is base plus content”A MapLibre style is a document with sources and layers. The baseStyle
parameter loads that document without modification. The trailing
rememberMapState block declares your sources, layers, and their
positions in the layer stack.
val runtime = DefaultMapRuntime.instanceval state = rememberMapState( runtime = runtime, baseStyle = BaseStyle.Uri("https://tiles.openfreemap.org/styles/liberty"), ) { // Sources and layers declared here are added to the base style. }MaplibreMap(state = state)The library manages the sources and layers in the style block. It
does not modify the rest of the base style. To change a base style layer, use
the asMutable view of its LayerHandle from mapState.style.layers.
Composition owns the definitions and lifetimes of declared sources, layers, and
images. Their handles expose reads and runtime operations; asMutable is null.
For other resources, asMutable provides definition writes and remove().
Use mapState.style.sources[source] to obtain a declared source’s typed handle for
feature state, cluster queries, and invalidation. These runtime operations do not
change its declared definition. Handles belong to one loaded style generation;
look them up again after a style reload or resource replacement.
A handle write does not wait for the map to apply it. On MapLibre Native the
write runs on the map’s own thread after the call returns; MapLibre GL JS
applies it during the call. When the engine rejects a written value, the
library logs a warning and the previous value stays in place. The same applies
to mapState.style.transition, light, sky, and projection.
Recomposition updates the style
Section titled “Recomposition updates the style”The style block is evaluated as a Compose composition. When the state that it reads changes, it recomposes, and the library applies the difference to the style: a layer that is no longer in the composition is removed from the style, a new layer is added, and a changed property is updated in place. You do not call add or remove functions yourself.
This is the same contract as Compose UI: describe the map content for the current state, and let the runtime reconcile it.
Style switches re-apply your content
Section titled “Style switches re-apply your content”When you change baseStyle, the map loads the new style and evaluates
the style block against it. Each evaluation declares your
sources and layers against the new style. They persist across the switch
without extra code. An Anchor is resolved against the new style’s layers.
To share one definition between several maps, write the style content as a
composable function and call that function from each style block. The same
function applies to rememberMapState, MapRuntime.createMapState, and
MapRuntime.createSnapshotter.
Style content reads its host through two composition locals.
LocalViewport contains the viewport that the content is evaluated
for. An interactive map provides its rendered viewport, which is null until the
map has drawn a frame, and a snapshotter provides the viewport of the capture
request. LocalMapState contains the interactive map, and is null
inside a snapshotter. Content that requires the map checks for null at the
read. Content that runs on both hosts branches on it.
Layer and source IDs
Section titled “Layer and source IDs”Layers and sources have string IDs because the underlying MapLibre style
identifies them by ID. Within one map, each layer ID must be unique, including
against the base style’s layers. A feature query takes layer IDs to limit its
scope, and an Anchor can select a base style layer by its ID.