Skip to content
This site is a preview of pull request #1081.

How the map composes

MapLibre Compose has no public map view object. MapState defines a logical map, including its base style and declarative style content. MaplibreMap presents that state. MapState provides camera, viewport, projection, and feature-query operations while the map is attached.

A MapLibre style is a document with sources and layers. The initialBaseStyle parameter loads that document without modification. The trailing rememberMapState block declares your sources, layers, and their positions in the layer stack.

App.kt
val runtime = DefaultMapRuntime.instance
val state =
rememberMapState(
runtime = runtime,
initialBaseStyle = 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 its handle in mapState.style.layers, or replace it with Anchor.Replace and declare its replacement yourself.

initialBaseStyle seeds the map once. Changing that input does not reload the remembered map; assign mapState.style.baseStyle to switch styles.

Composition owns the definitions and lifetimes of declared sources, layers, and images. Handles reject definition writes and removal commands for those resources. 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.

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.

When you assign mapState.style.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 that names a base layer applies only when that layer exists in the new style.

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.

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 names a base style layer by its ID.