This repository is a working reference for using MapLibre Native inside Slint applications.
Its scope is running the two together from C++, and there are two ways to do that. The default renders on WebGPU and works on Linux, macOS and Windows. Where OpenGL is available, a second path hands Slint a borrowed GL texture instead, with no copy through host memory. Which one you can use is decided by what Slint accepts, described in docs/rendering-paths.md. If you need a combination outside those two, reach for maplibre-native-rs directly rather than bending this one.
The important thing here is not packaging polish. The important thing is that the combination actually works today across desktop platforms, with a reusable Slint component surface in src/.
Two directories are the repository:
src/is the reusable Slint component API.cpp/is the backend that implements it, and the demo that uses it. It needs the MapLibre Native git submodule, so clone with--recursive.
Everything under experiments/ is an experiment. It is not supported, it may be broken at any moment, and it will be deleted if it leads nowhere:
experiments/rust/reaches MapLibre throughmaplibre-native-rs. It is not a way to build this without C++: the crate builds MapLibre Native from source underneath.experiments/ffi/explores the experimental C API frommaplibre-native-ffi.
Use the path this repository supports rather than assembling your own beside it. In particular, do not stand up a GL or EGL context of your own next to the one Slint's renderer owns.
Contributors and coding agents should also read AGENTS.md and AI_POLICY.md.
- A reusable Slint component library centered on
src/maplibre.slint - A reusable C++ backend library target (
maplibre-native-slint::mbgl-slint) you can link from your own CMake app - A canonical C++ backend integration that works on Linux, Windows, and macOS
- A practical reference for people who want to build their own Slint + MapLibre app
- A place to validate backend choices such as WebGPU (
wgpu-native) and Metal/OpenGL fallbacks
- Not yet a polished end-user SDK
- Not yet an installable, versioned package (no
find_package/ system install yet). You consume it viaFetchContent/add_subdirectory, see Use It In Your Own App - Not a "everything is magically wired for you" drop-in. You still write the small
MMapAdapterwiring in your ownmain(seecpp/main.cpp)
Today, the most honest way to describe this repository is:
If you want to build a Slint application that embeds MapLibre, this repository shows a real cross-platform way to do it.
If you want something that works today, use the C++ path as the reference implementation.
- The reusable Slint API lives in
src/ - The authoritative backend wiring lives in
cpp/main.cpp - The demo shell lives in
cpp/map_window.slint
The Rust demo exists to mirror the same Slint component contract, but it depends on maplibre-native-rs and its current 0.8.x API surface. It is still only practical on Linux today. Treat it as an experimental companion, not the primary integration path.
Platform-specific build guides:
- Linux: Ubuntu 24.04 Build Guide
- Windows: Windows 11 Build Guide
- macOS: macOS Apple Silicon Build Guide
Typical Linux build:
git clone https://github.com/maplibre/maplibre-native-slint.git
cd maplibre-native-slint
git submodule update --init --recursive
cmake -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build
./build/cpp/maplibre-slint-exampleThe default build prefers the WebGPU backend with wgpu-native when available.
For Windows and macOS specifics, use the platform guides above.
The public Slint entrypoint is src/maplibre.slint:
import { MMapView, MMapAdapter } from "@maplibre-native-slint/maplibre.slint";The key exported symbols are:
MMapView: the reusable visual map componentMMapAdapter: the global bridge between the Slint UI and a native backend
Minimal UI usage looks like this:
import { MMapView } from "@maplibre-native-slint/maplibre.slint";
export component App inherits Window {
preferred-width: 800px;
preferred-height: 600px;
map := MMapView {
style-url: "https://demotiles.maplibre.org/style.json";
center-lat: 35.6895;
center-lon: 139.6917;
zoom: 10;
}
}That is the reusable UI layer.
What still needs to be provided by the host application is the native backend wiring for MMapAdapter. The canonical example of that wiring is cpp/main.cpp.
The repository is consumable directly from another CMake project, with no system install needed. Fetch it and link the reusable backend target maplibre-native-slint::mbgl-slint, which publicly propagates MapLibre Native, Slint, cpr, the GL/WebGPU libraries, and the backend headers:
include(FetchContent)
FetchContent_Declare(
maplibre-native-slint
GIT_REPOSITORY https://github.com/maplibre/maplibre-native-slint.git
GIT_TAG <pin-a-commit>
)
FetchContent_MakeAvailable(maplibre-native-slint)
add_executable(my-app main.cpp)
# Import the reusable Slint components via the @maplibre-native-slint alias.
slint_target_sources(my-app my.slint
LIBRARY_PATHS maplibre-native-slint=${maplibre-native-slint_SOURCE_DIR}/src)
target_link_libraries(my-app PRIVATE maplibre-native-slint::mbgl-slint)Your main.cpp wires the Slint MMapAdapter callbacks to a SlintMapLibre
instance (from slint_maplibre_headless.hpp, provided by the target). Copy
cpp/main.cpp as the starting point.
The default build uses WebGPU (wgpu-native). To use OpenGL instead, disable
WebGPU and select a backend explicitly. A bare -DMLN_WITH_WEBGPU=OFF
fails fast with a message telling you to pick one:
cmake -B build -DMLN_WITH_WEBGPU=OFF -DMLN_WITH_OPENGL=ONA system-installed Slint is used if found, otherwise Slint is built from source.
A system Slint built against a foreign Qt/ICU can bake its RUNPATH into your
binary and break portability, so force a self-contained build with:
cmake -B build -DMLN_SLINT_USE_SYSTEM=OFFFor a fully self-contained, no-Qt result (kiosk / embedded), combine it with the winit + FemtoVG Slint backend:
cmake -B build \
-DMLN_WITH_WEBGPU=OFF -DMLN_WITH_OPENGL=ON \
-DMLN_SLINT_USE_SYSTEM=OFF \
-DSLINT_FEATURE_BACKEND_QT=OFF \
-DSLINT_FEATURE_BACKEND_WINIT=ON \
-DSLINT_FEATURE_RENDERER_FEMTOVG=ONsrc/m-map-view.slintdefines the reusable map componentsrc/m-map-adapter.slintdefines the backend bridge contractsrc/maplibre.slintis the public entrypoint
cpp/src/slint_maplibre_headless.cppholds the current production-grade backend logic- It is packaged as the
mbgl-slintlibrary target (aliasmaplibre-native-slint::mbgl-slint) so apps and tests link it instead of recompiling the sources cpp/main.cppwiresMMapAdapterto that backendcpp/map_window.slintis a demo shell showing how to use the reusable component
experiments/rust/main.slintmirrors the same Slint component contract as the C++ demoexperiments/rust/src/maplibre.rswiresMMapAdaptertomaplibre-native-rs- This path is useful for experimentation on Linux, but it is not the repository's primary story today
How a MapLibre frame reaches a Slint surface, which of the two build targets to use, what Slint will and will not accept as a texture, the platform status and the build backend flags all live in docs/rendering-paths.md.
The short version: Slint accepts a borrowed texture only from OpenGL, so the OpenGL path can hand its frame over directly while the WebGPU default copies through host memory. That is a property of the toolkit, not a shortcut taken here.
Styles, tiles, PMTiles archives and glyphs can all be served straight from disk
with file://, with no local HTTP server in front of them. See
docs/offline-assets.md.
src/- reusable Slint component APIcpp/- canonical C++ backend integration and demo appexperiments/- experiments, not part of the supported path:experiments/rust/- Linux-oriented experimental Rust backend integrationexperiments/ffi/- exploration of the experimental C API frommaplibre-native-ffi
vendor/- MapLibre Native and other vendored dependenciesdocs/build_guides/- platform-specific build guidesdocs/testing.md- testing instructions
Relevant test/documentation entrypoints:
For the Rust backend specifically:
- use Rust 1.90 or newer (
maplibre-native-rs0.8.x requires it) - on Linux, the default backend is OpenGL and
cargo testbuildsmaplibre-nativefrom source throughmaplibre-native-rs - renderer integration tests are opt-in via
MAPLIBRE_NATIVE_SLINT_RUN_RENDERER_TESTS=1so CI can stay headless by default
For day-to-day validation, the most important checks are:
- the C++ demo builds and launches on Linux, Windows, and macOS
- the reusable Slint contract in
src/stays compatible with both demo shells - the Rust demo remains aligned with the same
MMapView/MMapAdaptercontract on Linux
Near-term goals:
- Keep the reusable Slint API in
src/and thembgl-slinttarget stable enough for direct consumption - Keep the C++ backend as the authoritative cross-platform reference
Longer-term possibilities:
- an installable/exported package (
find_package(maplibre-native-slint)) so downstream apps do not needFetchContent - better packaging so users do not need to think about the C++ toolchain
- a lower-overhead rendering path that avoids GPU-to-CPU readback
These are goals, not promises. The current value of this repository is that it already demonstrates a real working integration.
- Run
git submodule update --init --recursive - Follow the platform-specific build guide for your OS
- On Linux and Windows with WebGPU, make sure LLVM/libclang is available for
bindgen
- Make sure your machine has network access for style and tile loading
- On Linux, ensure a graphical session is available if you are launching the desktop demo directly
- MapLibre Native Slack: #maplibre-native
- OSM US Slack invite: slack.openstreetmap.us
- MapLibre website: maplibre.org
Copyright (c) 2025 MapLibre contributors.
This project is licensed under the BSD 2-Clause License. See LICENSE.
This repository integrates multiple components with their own licenses:
- MapLibre Native: BSD
- Slint: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0