Turn OpenStreetMap data into portable, self-contained map packages for 2D, 3D, and offline applications.
map-zero builds normalized GeoPackage source data, vector PMTiles for OpenLayers, and Cesium 3D Tiles from one workflow. A package can also include external JSON styles, a manifest.json, and an optional portable ZIP. It runs without API keys, hosted map APIs, or external map infrastructure at runtime.
map-zero packages standard GIS and web formats into one directory. It is intended for local-first applications, offline deployments, static hosting, and projects that need both 2D and 3D map outputs from the same OpenStreetMap data.
Early alpha. The package layout and APIs are usable, but still evolving.
The easiest way to build a package is to select an area on a map:
npm install
node src/cli.js bbox-ui --output-root ./generatedOpen the printed local URL, draw or enter a bounding box, choose layers and outputs, then select Build map-zero. The UI downloads suitable OpenStreetMap data, builds the package, and can export PMTiles, 3D Tiles, and a ZIP in the same job.
Each map is a self-contained .mapzero package composed of standard files:
my-area.mapzero/
data.gpkg # normalized OpenStreetMap source data
manifest.json # package metadata and asset locations
tiles.pmtiles # optional vector tiles for 2D maps
3dtiles/ # optional Cesium 3D Tiles
styles/ # external JSON cartographic styles
data.gpkg is the source for dynamic MVT, PMTiles, and 3D Tiles. manifest.json connects the data, styles, and generated assets. Static consumers can use PMTiles and 3D Tiles without running the map-zero server.
OpenStreetMap
|
bbox or local OSM PBF
|
v
map-zero
|
+----------+----------+
| | |
v v v
GeoPackage PMTiles 3D Tiles
| | |
v v v
source/MVT OpenLayers Cesium
For a bounding box, bbox-ui and from-bbox use the same pipeline:
bbox
-> find suitable Geofabrik extracts
-> download or reuse cached OSM PBF files
-> build normalized GeoPackage data
-> export PMTiles and/or 3D Tiles
-> create a portable map-zero package and optional ZIP
from-bbox can combine smaller sibling extracts when a bbox crosses an administrative boundary, and can reuse a cached broader extract when appropriate. The default source cache is ~/.cache/map-zero/osm.
- Local-first: one folder per map, with data and generated assets kept together.
- No API keys or hosted map services are required to render exported map data at runtime.
- Static deployment is possible for exported PMTiles and 3D Tiles.
- GeoPackage remains available as a portable source container for inspection and dynamic MVT.
- The same package can feed OpenLayers in 2D and Cesium in 3D.
- Outputs use established formats: GeoPackage, MVT, PMTiles, 3D Tiles, and JSON.
Supported logical layers are roads, buildings, water, terrain, coastline, cliffs, landuse, railways, boundaries, pois, and aip. The older aviation name remains an alias for aip.
Use the non-interactive equivalent of the bbox UI when the area is already known:
node src/cli.js from-bbox \
--bbox -3.9,40.3,-3.5,40.6 \
--out ./madrid.mapzeroThis runs the same pipeline as bbox-ui. By default it exports PMTiles at zooms 8-16, 3D Tiles, and madrid.mapzero.zip. Use --no-pmtiles, --no-3dtiles, or --no-zip to omit an output; use --include-gpkg to retain the source GeoPackage in the ZIP.
Use build when an .osm.pbf extract is already available:
node src/cli.js build ./data/madrid.osm.pbf \
--out ./madrid.mapzerobuild infers the PBF extent and extracts all supported layers. Crop a larger input with --bbox:
node src/cli.js build ./data/spain.osm.pbf \
--bbox -3.9,40.3,-3.5,40.6 \
--out ./madrid.mapzeronode src/cli.js serve ./madrid.mapzero --port 8080 --openserve provides a local OpenLayers viewer, a Cesium viewer at /cesium, and a readonly HTTP API. It also generates MVT dynamically from data.gpkg when PMTiles are absent. It is useful for local inspection, but not required to deploy exported PMTiles or 3D Tiles.
# Static vector tiles
node src/cli.js pmtiles ./madrid.mapzero --minzoom 8 --maxzoom 16
# Cesium-ready 3D Tiles
node src/cli.js 3dtiles ./madrid.mapzero
# Portable ZIP; data.gpkg is excluded unless requested
node src/cli.js package ./madrid.mapzero --include-gpkg
# Write a bundled full preset or compact theme
node src/cli.js style ./madrid.mapzero --preset neon-dark
node src/cli.js style ./madrid.mapzero --theme neon-darkFor larger regional PMTiles exports, lower the maximum zoom or use more workers:
node src/cli.js pmtiles ./andalucia.mapzero --minzoom 8 --maxzoom 12 --workers 4The base build command writes data.gpkg, manifest.json, and the default style. Additional commands update the manifest as they add static assets:
madrid.mapzero/
data.gpkg # GeoPackage source data
manifest.json # layers, bbox, styles, tile asset metadata
styles/
neon-dark.json # default external style
tiles.pmtiles # written by `pmtiles` or `from-bbox`
3dtiles/
buildings/tileset.json # written by `3dtiles` or `from-bbox`
package writes madrid.mapzero.zip beside the folder. The archive includes the manifest, referenced styles, PMTiles, and 3D Tiles; it excludes data.gpkg by default because static OpenLayers and Cesium consumers do not need it.
PMTiles is a single static file served with HTTP range requests. It can be deployed to static hosting, object storage, nginx, or a CDN that supports range requests. 3D Tiles are likewise static files that Cesium can load from a normal web server.
Use @map-zero/ol to add a package to an existing OpenLayers map:
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import { addMapZeroToOpenLayers } from '@map-zero/ol';
const map = new Map({
target: 'map',
layers: [],
view: new View({ center: [0, 0], zoom: 12 })
});
const controller = await addMapZeroToOpenLayers(map, {
id: 'madrid',
manifestUrl: './madrid.mapzero/manifest.json'
});
controller.setVisible('buildings', false);The helper selects vector PMTiles when manifest.json provides them and otherwise uses dynamic MVT from the map-zero server. Geometry uses WebGLVectorTileLayer; labels use a separate OpenLayers text layer so their attribute data does not affect WebGL geometry buffers. An optional renderMode: 'raster-worker' path is available for worker-based raster rendering.
Use @map-zero/cesium to add exported 3D Tiles to an existing Cesium viewer:
import { Viewer } from 'cesium';
import { addMapZeroToCesium } from '@map-zero/cesium';
const viewer = new Viewer('cesiumContainer');
const controller = await addMapZeroToCesium(viewer, {
id: 'huelva',
manifestUrl: './huelva.mapzero/manifest.json',
style: 'default'
});
controller.setOpacity('buildings', 0.8);Buildings are extruded with height, building:levels * 3, or a configured fallback height. Roads, railways, boundaries, water, landuse, and AIP features can be exported as flat cartographic meshes. The helper leaves terrain, atmosphere, lighting, fog, and background under application control unless configured otherwise.
The optional Cesium context overlay rasterizes PMTiles in a module worker. It requires Worker, OffscreenCanvas, and createImageBitmap; there is no main-thread fallback.
See Cesium integration.
Styles are JSON files outside the GeoPackage, allowing the same data to be rendered differently without rebuilding source data or PMTiles. Use a bundled full preset with --preset, or a compact theme with --theme.
node src/cli.js style ./madrid.mapzero --preset neon-dark
node src/cli.js style ./madrid.mapzero --theme neon-darkMost users should edit compact theme JSON rather than full renderer-ready style presets. See styles and themes and cartography and POIs.
- Architecture
- Styles and themes
- Cartography and POIs
- OpenLayers integration
- Cesium integration
- HTTP API
- The package format and public APIs are still early alpha.
- Packages are readonly; editing OpenStreetMap data is not supported.
- PMTiles export is supported; MBTiles export is not.
- Cesium export focuses on extruded buildings and flat cartographic context layers. Labels, terrain clamping, advanced metadata, and regional LOD optimization are still future work.
- The built-in viewers load OpenLayers and Cesium from public CDNs. Map data, PMTiles, and 3D Tiles remain local to the package.
MIT