A MapLibre GL JS plugin for visualizing Overture Maps PMTiles themes. It adds a collapsible map control with a release selector and per-theme visibility and opacity controls, rendering an "x-ray" style overlay similar to explore.overturemaps.org. A React wrapper and a GeoLibre Desktop plugin bundle are included.
- All six Overture themes - Addresses, base, buildings, divisions, places, and transportation, each loaded from the official Overture PMTiles distribution
- Dynamic releases - Fetches the latest Overture release list at runtime, with a dropdown to switch releases and an option to pin one
- Theme controls - Checkbox, color swatch, and opacity slider per theme
- Feature inspection - Click any rendered Overture feature to see its properties in a popup (can be disabled)
- Dark and light mode - The control UI follows
prefers-color-schemeby default and can be forced light or dark - Small-screen friendly - The panel stays within the viewport and scrolls vertically when space is tight
- TypeScript Support - Full TypeScript support with exported type definitions
- React Integration - React wrapper component and custom hook
- GeoLibre Bundle Output - Builds a zip with root
plugin.json, bundled ESM, and CSS for GeoLibre Desktop - Modern Build Setup - Vite-based library and GeoLibre bundle builds
- Testing - Vitest setup with React Testing Library
- CI/CD Ready - GitHub Actions for npm publishing, GitHub Pages, and Docker
npm install maplibre-gl-overture-mapsmaplibre-gl (>=3.0.0) is a peer dependency. The pmtiles package is bundled as a regular dependency, and the control registers the pmtiles:// protocol with MapLibre automatically when added to a map.
import maplibregl from "maplibre-gl";
import { OvertureMapsControl } from "maplibre-gl-overture-maps";
import "maplibre-gl-overture-maps/style.css";
const map = new maplibregl.Map({
container: "map",
style: "https://tiles.openfreemap.org/styles/positron",
center: [-74.006, 40.7128],
zoom: 14,
});
map.on("load", () => {
const control = new OvertureMapsControl({
collapsed: false,
visibleThemes: ["buildings", "transportation", "places"],
});
map.addControl(control, "top-right");
});import { useEffect, useRef, useState } from "react";
import maplibregl, { Map } from "maplibre-gl";
import {
OvertureMapsControlReact,
useOvertureMapsState,
} from "maplibre-gl-overture-maps/react";
import "maplibre-gl-overture-maps/style.css";
function App() {
const mapContainer = useRef<HTMLDivElement>(null);
const [map, setMap] = useState<Map | null>(null);
const { state, toggle } = useOvertureMapsState();
useEffect(() => {
if (!mapContainer.current) return;
const mapInstance = new maplibregl.Map({
container: mapContainer.current,
style: "https://tiles.openfreemap.org/styles/positron",
center: [-74.006, 40.7128],
zoom: 14,
});
mapInstance.on("load", () => setMap(mapInstance));
return () => mapInstance.remove();
}, []);
return (
<div style={{ width: "100%", height: "100vh" }}>
<div ref={mapContainer} style={{ width: "100%", height: "100%" }} />
{map && (
<OvertureMapsControlReact
map={map}
collapsed={state.collapsed}
onStateChange={(newState) => console.log(newState)}
/>
)}
</div>
);
}Each theme is a separate PMTiles archive from the official distribution at https://overturemaps-extras-us-west-2.s3.us-west-2.amazonaws.com/tiles/<RELEASE>/<THEME>.pmtiles.
| Theme | Source layers | Default color | Notes |
|---|---|---|---|
addresses |
address |
#e6194b |
Points appear at z14+ |
base |
land, land_cover, land_use, water, bathymetry, infrastructure |
#3cb44b |
|
buildings |
building, building_part |
#f58231 |
|
divisions |
division_area, division_boundary, division |
#911eb4 |
|
places |
place |
#4363d8 |
Points appear at z14+ |
transportation |
segment, connector |
#f032e6 |
The main control class implementing MapLibre's IControl interface.
| Option | Type | Default | Description |
|---|---|---|---|
collapsed |
boolean |
true |
Whether the panel starts collapsed (showing only the 29x29 toggle button) |
position |
string |
'top-right' |
Control position on the map |
title |
string |
'Overture Maps' |
Title displayed in the header |
panelWidth |
number |
300 |
Width of the dropdown panel in pixels |
className |
string |
'' |
Custom CSS class name |
theme |
'light' | 'dark' | 'auto' |
'auto' |
UI color scheme; 'auto' follows prefers-color-scheme |
release |
string |
latest | Pin a specific Overture release (e.g. '2026-05-20.0') |
releasesUrl |
string |
Overture labs releases.json | Endpoint listing available releases |
tilesBaseUrl |
string |
Official Overture S3 tiles URL | Base URL of the PMTiles distribution |
inspect |
boolean |
true |
Click a rendered feature to open a properties popup |
visibleThemes |
OvertureTheme[] |
['buildings', 'transportation', 'places'] |
Themes that start visible |
themeColors |
Partial<Record<OvertureTheme, string>> |
x-ray palette | Per-theme color overrides |
themeOpacity |
Partial<Record<OvertureTheme, number>> |
0.8 |
Per-theme initial opacity (0..1) |
toggle()/expand()/collapse()- Control the panelgetState()/setState(state)- Read or update the statesetRelease(release)- Switch the active Overture releasesetThemeVisible(theme, visible)- Show or hide a themesetThemeOpacity(theme, opacity)- Set a theme's opacity (0..1)refreshReleases()- Re-fetch the release liston(event, handler)/off(event, handler)- Manage event handlersgetMap()/getContainer()- Access the map and container
collapse/expand- Panel visibility changesstatechange- Any state changereleasechange- The active release changedthemechange- A theme's visibility or opacity changederror- The release list could not be loaded (a fallback release is used)
React wrapper component for OvertureMapsControl.
All OvertureMapsControl options plus:
| Prop | Type | Description |
|---|---|---|
map |
Map |
MapLibre GL map instance (required) |
onStateChange |
function |
Callback fired when state changes |
Custom React hook for managing control state.
const {
state, // Current state
setState, // Update entire state
setCollapsed, // Set collapsed state
setPanelWidth, // Set panel width
setRelease, // Set the active release
setThemeVisible, // Set a theme's visibility
setThemeOpacity, // Set a theme's opacity
reset, // Reset to initial state
toggle, // Toggle collapsed state
} = useOvertureMapsState(initialState);OvertureMapsControlOptions, OvertureMapsState, OvertureThemeState, OvertureMapsControlReactProps, OvertureMapsEvent, OvertureMapsEventHandler, OvertureTheme, OvertureGeometry, OvertureLayerDef, ThemeDefinition, ControlColorScheme, and ReleasesResponse are exported from both entry points (React-specific types from /react).
Helpers are also exported: THEMES, THEME_IDS, buildLayerSpecs, layerIdsForTheme, sourceIdForTheme, tileUrlForTheme, fetchReleases, ensurePmtilesProtocol, and more.
The control UI uses CSS custom properties and follows the browser's prefers-color-scheme by default. Set the theme option to 'light' or 'dark' to force a scheme:
const control = new OvertureMapsControl({ theme: "dark" });GeoLibre Desktop loads external plugins from an app data plugins/ directory. The zip must contain plugin.json at the root, plus a bundled ESM entry and optional CSS file.
npm install
npm run package:geolibreThis creates:
geolibre-plugin/maplibre-gl-overture-maps-0.1.0.zip
The generated zip contains:
plugin.json
dist/index.js
dist/style.css
Copy the zip into GeoLibre Desktop's app data plugins/ directory and restart GeoLibre. On Linux with the default app identifier, that directory is usually:
~/.local/share/org.geolibre.desktop/plugins/
For the GeoLibre web app, serve the unpacked plugin with CORS enabled:
npm run package:geolibre
npm run serve:geolibre -- 8000Then add this manifest URL in GeoLibre Settings > Plugins:
http://localhost:8000/plugin.json
Using python -m http.server for this cross-origin web app case is not enough
because it does not send Access-Control-Allow-Origin.
# Clone the repository
git clone https://github.com/opengeos/maplibre-gl-overture-maps.git
cd maplibre-gl-overture-maps
# Install dependencies
npm install
# Start development server
npm run dev| Script | Description |
|---|---|
npm run dev |
Start development server |
npm run build |
Build the library and GeoLibre bundle |
npm run build:lib |
Build the standalone MapLibre library |
npm run build:geolibre |
Build the GeoLibre ESM and CSS bundle |
npm run package:geolibre |
Build and zip the GeoLibre plugin bundle |
npm run build:examples |
Build examples for deployment |
npm run test |
Run tests |
npm run test:ui |
Run tests with UI |
npm run test:coverage |
Run tests with coverage |
npm run lint |
Lint the code |
npm run format |
Format the code |
maplibre-gl-overture-maps/
├── geolibre-plugin/
│ └── plugin.json # GeoLibre external plugin manifest
├── scripts/
│ └── package-geolibre-plugin.mjs
├── src/
│ ├── index.ts # Main entry point
│ ├── geolibre.ts # GeoLibre plugin wrapper entry point
│ ├── react.ts # React entry point
│ ├── index.css # Root styles
│ └── lib/
│ ├── core/ # Control, themes, releases, types
│ ├── hooks/ # React hooks
│ ├── utils/ # Utility functions
│ └── styles/ # Component styles
├── tests/ # Test files
├── examples/ # Example applications
│ ├── basic/ # Vanilla TypeScript example
│ └── react/ # React example
└── .github/workflows/ # CI/CD workflows
The examples can be run using Docker. The image is automatically built and published to GitHub Container Registry.
# Pull the latest image
docker pull ghcr.io/opengeos/maplibre-gl-overture-maps:latest
# Run the container
docker run -p 8080:80 ghcr.io/opengeos/maplibre-gl-overture-maps:latestThen open http://localhost:8080/maplibre-gl-overture-maps/ in your browser to view the examples.
# Build the image
docker build -t maplibre-gl-overture-maps .
# Run the container
docker run -p 8080:80 maplibre-gl-overture-maps| Tag | Description |
|---|---|
latest |
Latest release |
x.y.z |
Specific version (e.g., 1.0.0) |
x.y |
Minor version (e.g., 1.0) |
- Overture tiles are designed for x-ray inspection, not as a production basemap. See the Overture tiles docs.
- The
addressesandplacesthemes only contain features at zoom 14 and above. - If the release list cannot be fetched (e.g. offline), the control falls back to a known release and emits an
errorevent; pin a release with thereleaseoption to skip the fetch dependency.
MIT License - see LICENSE for details.