OpenStreetMap logo OpenStreetMap

pnorman's Diary

Recent diary entries

Switching a style to glug

Posted by pnorman on 2 September 2025 in English.

Styles for vector tiles are typically written in the MapLibre GL style language. These definitions exist in JSON, which, for various reasons, is not a good language for humans to write in. Software called Charites preprocessed my Street Spirit style to improve readability. This helped a great deal and removed the two largest pain points: no comments and only one file.

Charites’ main features are:1

  1. letting you write in YAML instead of JSON,
  2. importing other YAML files into the main one,
  3. and the use of simple variables to allow common style constants to be set once.

I made use of the first two features, but I still found myself limited by them. I still faced issues where the project’s structure revolved around the styling language rather than what makes sense to a cartographer.

A good example of this was road layers. With Charites I had to have separate files for each layer, so I had separate files for each of the thirteen layers. With glug I was able to have one file for the twelve layers that drew the casings and fill, and one file for the road text layer. This kept related definitions in the same place, which makes everything more readable.

Expressions are essential for writing performant MapLibre GL styles. A simple expression example is filtering to only show labels of larger areas. A filter property such the one below does this.

{"filter":
[">=",
["get","way_area"],
['*', 750, 6126430366.1, ['^', 0.25, ["zoom"]]]
]}

This JSON doesn’t allow comments, so you have to hope it’s obvious from the text what is happening.[2]

Charites lets this be reformulated to YAML

filter:
  - '>='
  - [get, way_area]
  - ['*', 750, 6126430366.1, ['^', 0.25, [zoom]]] # Only show areas larger than 750 pixels at current zoom

It’s a bit better, but the comment shows a limitation of the language. Filtering by area is a very common task. It shouldn’t require a comment to explain the basic math. With glug this instead becomes

See full entry

Sprite Sheets

Posted by pnorman on 20 August 2025 in English.

Vector Tile styles require icons are served in a sprite sheet. This contains all of the icons in one file. Years ago there were a few options for these, none of them great. These days, there are three common options: spreet, @basemaps/sprites, and sprite-one. The first is written in Rust while the other two are written in Javascript.

All have the same basic functionality of turning a folder of SVGs into a json+png spritesheet, and doing so at multiple resolutions. Spreet has the additional option of de-duplicating icons. If two icons are identical it will only put one copy in the PNG and reference the same image twice.

I benchmarked all three options with two sets of sprites: all the SVGs from OpenStreetMap Carto, and the OpenStreetMap Americana icons. The former is 973 icons and the latter is 248 icons. These are larger than a typical set of icons but are a good test.

  Test spreet sprite-one @basemaps/sprites
osm-carto SVGs @1x pixels 4194304 4078074 8339456
osm-carto SVGs @1x bytes 513159 763531 837792
osm-carto SVGs @1x bytes after oxipng 474750 649894 706845
osm-carto SVGs @2x bytes 1442588 2176457 2411489
osm-carto SVGs @2x bytes after oxipng 1325707 1896784 2088729
osm-americana @1x pixels 128265 122400 151760
osm-americana @1x bytes 75749 91870 92066
osm-americana @1x bytes after oxipng 75497 84986 85828
osm-americana @2x bytes 136177 213876 210650
osm-americana @2x bytes after oxipng 132462 197687 194950

See full entry