https://github.com/jonathanlurie/basemapkit
Basemaps for Protomaps / pmtiles
https://github.com/jonathanlurie/basemapkit
basemaps map maplibre protomaps
Last synced: 9 months ago
JSON representation
Basemaps for Protomaps / pmtiles
- Host: GitHub
- URL: https://github.com/jonathanlurie/basemapkit
- Owner: jonathanlurie
- Created: 2025-06-18T20:12:57.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2025-10-01T20:58:41.000Z (9 months ago)
- Last Synced: 2025-10-01T22:27:05.249Z (9 months ago)
- Topics: basemaps, map, maplibre, protomaps
- Language: TypeScript
- Homepage: https://s.jnth.io/s/basemapkit
- Size: 43.5 MB
- Stars: 55
- Watchers: 1
- Forks: 1
- Open Issues: 2
-
Metadata Files:
- Readme: readme.md
Awesome Lists containing this project
README
Basemaps for Maplibre GL JS + Protomaps
**Basemapkit** generates customizable styles compatible with **Maplibre GL JS** that relies on the **Protomaps** Planet schemas when it comes to [vector layers and feature properties](https://docs.protomaps.com/basemaps/layers). You can download your own PMtiles copy of the planet on the official [Protomaps build page](https://maps.protomaps.com/builds/).
| | | |
| :----------------: | :------: | ----: |
|  |  |  |
|  | |  |
|  |  |  |
|  |  |  |

## Getting started 👷
### Install
On an existing ES project:
```bash
npm install basemapkit
```
### Add some style
The following example instantiates a Maplibre `Map`, then initializes the Protomaps protocol and then generates a style with Basemapkit:
```ts
import "maplibre-gl/dist/maplibre-gl.css";
import maplibregl from "maplibre-gl";
import { Protocol } from "pmtiles";
import { getStyle, getStyleList } from "basemapkit";
// Adds the Protomaps protocol:
maplibregl.addProtocol("pmtiles", new Protocol().tile);
// Build the Basemapkit style
const style = getStyle(
// One of the main syle:
"avenue",
{
// URL to the pmtiles
pmtiles: "https://my-s3-bucket.com/planet.pmtiles",
// URL to the sprites (for POIs)
sprite: "https://raw.githubusercontent.com/jonathanlurie/phosphor-mlgl-sprite/refs/heads/main/sprite/phosphor-diecut",
// URL to the glyphs (for labels)
glyphs: "https://protomaps.github.io/basemaps-assets/fonts/{fontstack}/{range}.pbf";
// Language (you can ommit to use the platform language)
lang: "en",
});
// Instantiate the Map:
const map = new maplibregl.Map({
container: "map",
center: [0, 0],
zoom: 3,
// Add the Basemapkit style:
style,
});
```
If using a traditional `tile.json` and `z/x/y` tiles instead of http-range-requesting a `pmtiles` file, then replace the option `pmtiles` by `tilejson`, as in the example below:
```ts
const style = getStyle(
// One of the main syle:
"avenue",
{
// URL to the tile.json
tilejson: "https://example.com/tile.json",
// URL to the sprites (for POIs)
sprite: "https://raw.githubusercontent.com/jonathanlurie/phosphor-mlgl-sprite/refs/heads/main/sprite/phosphor-diecut",
// URL to the glyphs (for labels)
glyphs: "https://protomaps.github.io/basemaps-assets/fonts/{fontstack}/{range}.pbf";
// Language (you can ommit to use the platform language)
lang: "en",
});
```
This can get particularly handy when using the [Protomaps CLI](https://docs.protomaps.com/pmtiles/cli) or [Martin](https://martin.maplibre.org/) to serve `z/x/y` vector tiles.
## Language 📣
Basemakit styles are compatible with Protomaps languages properties and uses [`@protomaps/basemaps`](https://docs.protomaps.com/basemaps/flavors) under the hood.
The only addition from **Basemapkit** is the capability to detect the end user's platform language, so if the `lang` option is omitted, it will automatically use the language set by the user at the browser or OS level.
Here is the list of supported languages:
```ts
"ar" | "cs" | "bg" | "da" | "de" | "el" | "en" | "es" | "et" | "fa" | "fi" | "fr" | "ga" | "he" | "hi" | "hr" | "hu" | "id" | "it" | "ja" | "ko" | "lt" | "lv" | "ne" | "nl" | "no" | "mr" | "mt" | "pl" | "pt" | "ro" | "ru" | "sk" | "sl" | "sv" | "tr" | "uk" | "ur" | "vi" | "zh-Hans" | "zh-Hant"
```
## Terrain 🏔️
Basemapkit can feature hillshading and/or terrain bumps when a terrain tileset is provided. The terrain tiles can be encoded as `"mapbox"` (default) or `"terrarium"`, in either PNG or WebP format. Then, the terrain tileset can be packed as *pmtiles* (``options.terrain.pmtiles`) or left as individual tiles, using a *tiles.json* as entry point (`options.terrain.tilejson`).
| | | | | |
| :----------------: | :------: | :----: | :------: | :----: |
|  |  |  |  |  |

Here is how to add hillshading but keep the terrain flat. Those settings are actually the default when the terrain tiles are provided.
```ts
const style = getStyle(
"avenue",
{
pmtiles: "",
sprite: "...",
glyphs: "...";
lang: "...",
/**
* The terrain options:
*/
terrain: {
/**
* The public URL of a pmtiles files for raster terrain, encoded on RGB channels of either PNG or WebP. To use if sourcing tiles directly with
* range-request using the `pmtiles`'s protocol. Alternatively, the option `tileJson` can be used and will take precedence.
*/
pmtiles: "https://my-s3-bucket.com/terrain.pmtiles";
/**
* Enable or disable the hillshading. Enabled by default if one of the source options `terrain.pmtiles` or `terrain.tilejson` is provided.
* It cannot be enabled if none of the source option is provided.
*/
hillshading: true,
/**
* The terrain exaggeration is disabled by default, making the terrain flat even if one of the source options `terrain.pmtiles` or `terrain.tilejson` is provided.
* A value of `1` produces at-scale realistic terrain elevation.
* It cannot be enabled if none of the source option is provided.
*/
exaggeration: 0,
/**
* Encoding of the terrain raster data. Can be "mapbox" or "terrarium". Default: "mapbox"
*/
encoding: "mapbox",
}
});
```
Alternatively, if the terrain tiles are refered to with a `tiles.json`:
```ts
const style = getStyle(
"avenue",
{
pmtiles: "",
sprite: "...",
glyphs: "...";
lang: "...",
/**
* The terrain options:
*/
terrain: {
/**
* The public URL to a tile JSON file for raster terrain tiles, encoded on RGB channels of either PNG or WebP. To use if classic z/x/y MVT tiles are served through
* Maplibre's Martin or the pmtiles CLI. Will take precedence on the option `pmtiles` if both are provided.
*/
tilejson: "https://example.com/terrain-tile.json";
}
});
```
## POIs and labels 📍
There are options to hide the points of interests and labels. By default, both are shown, meaning the options goes like this:
```ts
getStyle(
"avenue",
{
pmtiles: "...",
sprite: "...",
glyphs: "...",
hidePOIs: false,
hideLabels: false,
});
```
So by default, London looks like this:

But POIs can be hidden by doing this:
```ts
getStyle(
"avenue",
{
pmtiles: "...",
sprite: "...",
glyphs: "...",
hidePOIs: true,
hideLabels: false,
});
```
Then the same locations looks like this:

Alternatively, the labels can be hidden, this includes POIs' labels, so only POIs' icons will be shown by doing this:
```ts
getStyle(
"avenue",
{
pmtiles: "...",
sprite: "...",
glyphs: "...",
hidePOIs: false,
hideLabels: true,
});
```
here is how it looks like:

And finally, both labels and POIs can be hidden, resulting in a somewhat mysterious map:
```ts
getStyle(
"avenue",
{
pmtiles: "...",
sprite: "...",
glyphs: "...",
hidePOIs: true,
hideLabels: true,
});
```

Note that the corresponding layers are removed from the style and not just made invisible. If hiding POIs or label, the options `sprite` and `glyph` are unnecessary.
## Getting creative with `buildStyle()`
In addition to language and hiding POIs/labels, Basmapkit exposes some methods to modify the colors of the original style (`avenue`) to create *presets*. When the style is generated with some non-default `colorEdit`, a brand new Maplibre style is created and can be directly injected into a Maplibre `Map` instance's `.setStyle()` method, or even written as a static json file.
```ts
buildStyle({
pmtiles: "...",
sprite: "...",
glyphs: "...",
terrain: {...},
hidePOIs: false,
hideLabels: false,
// At the moment, "avenue" is the only style to start from
baseStyleName: "avenue",
colorEdit: {
// Invert the colors:
negate: false,
// In the range [-1, 1]:
brightness: 0,
// In the range [-1, 1]:
brightnessShift: 0,
// In the range [-1, 1]:
exposure: 0,
contrast: [
// intensity in the range [-1, 1]:
0,
// Midpoint in [0, 255]
127
],
// Rotate around the hue wheel, in range [0, 360]
hueRotation: 0,
// In the range [-1, 1]
// with -1 being gray levels and 1 being extra boosted colors
saturation: 0,
// Color blending with a multiply method
multiplyColor: [
// Color to multiply with
"#ff0000",
// blending factor in [0, 1]
// with 0 being the original color and 1 being the the color above
0
],
// Linear color blending
mixColor: [
// Color to blend with
"#ff0000",
// blending factor in [0, 1]
// with 0 being the original color and 1 being the the color above
0
]
}
}
);
```
For instance, let's create a TMNT toxic N.Y.C. kind of map:
```json
{
"baseStyleName": "avenue",
"lang": "en",
"hidePOIs": true,
"hideLabels": false,
"colorEdit": {
"negate": true,
"brightness": 0.4,
"brightnessShift": 0,
"exposure": 0.8,
"contrast": [
0.4,
160
],
"hueRotation": 80,
"saturation": 0.12,
"multiplyColor": [
"#ff00ff",
0.6
],
"mixColor": [
"#00ff00",
0.3
]
}
}
```
And here is the result:

You can live play with these on [basemapkit.jnth.io](https://s.jnth.io/s/basemapkit) and selecting the style `🖌️ custom 🎨`.
And from this "color editor" were created the built-in styles available below...
## Style presets available
Some custom `colorEdit` recipes are already built in Basemapkit and can be accessed directly from the `getStyle()` function.
### `avenue` ⤵️
This one is the default, with all the `colorEdit` options set to default:
```ts
// Create the style
const style = getStyle("avenue", options);
```





### `avenue-pop` ⤵️
```ts
// Create the style
const style = getStyle("avenue-pop", options);
```





### `avenue-night` ⤵️
```ts
// Create the style
const style = getStyle("avenue-night", options);
```





### `avenue-bright` ⤵️
```ts
// Create the style
const style = getStyle("avenue-bright", options);
```





### `avenue-saturated` ⤵️
```ts
// Create the style
const style = getStyle("avenue-saturated", options);
```





### `avenue-warm` ⤵️
```ts
// Create the style
const style = getStyle("avenue-warm", options);
```





### `avenue-vintage` ⤵️
```ts
// Create the style
const style = getStyle("avenue-vintage", options);
```





### `avenue-bnw` ⤵️
```ts
// Create the style
const style = getStyle("avenue-bnw", options);
```





### `avenue-blueprint` ⤵️
```ts
// Create the style
const style = getStyle("avenue-blueprint", options);
```




