A Pencil Style for Maplibre
Day 9 of the #30DayMapChallenge is Analog. I have no artistic talent whatsoever so I decided to cheat a little and take this as a challenge to create a hand-drawn (analog) style map using digital tools.
A Journey from Positron to Hand-Drawn Charm
It is possible to create custom map styles for Maplibre with Maputnik. So using Maputnik I decided to try to transform the clean, modern aesthetic of OpenFreeMap's Positron style into something entirely different: a hand-drawn, pencil-sketch map.
Starting Point: The OpenFreeMap Positron Style
I began with the OpenFreeMap Positron style. This style is known for its light, minimalist design and clean lines and its subtle color gradients provide a perfect foundation to layer 'hand-drawn textures' and grayscale tones upon.
The Foundation: Shades of Gray
The first and most impactful change was to strip away all color. The Mapbox Pencil style, which served as my inspiration, relies on a monochromatic palette to emulate graphite. In Maputnik, I went through map layers that had a fill-color, line-color, or text-color and replaced them with various shades of gray, ranging from very light off-white (for paper backgrounds) to dark charcoal (for prominent features). This immediately set the mood for a sketched aesthetic.
The Heart of the Hand-Drawn Look: Custom Sprite Sheets
This is where the magic truly happens. Unlike traditional web maps that use solid colors, a hand-drawn map needs texture. MapLibre GL uses sprite sheets to manage custom icons and, crucially, tiling patterns.
What is a Sprite Sheet?
A sprite sheet is a single PNG image file that contains multiple smaller images (your patterns or icons). It's paired with a JSON file that acts as an index, telling the map the name, location, and dimensions of each individual image within the PNG. This is highly efficient for performance, as the map only downloads one large image and picks out what it needs.
1. Creating the Patterns
I needed two main patterns for my style:
pencil-wave: A roughly drawn, tiling wave pattern for water bodies.pencil-hatch: A subtle, semi-transparent cross-hatch or scribble pattern for building fills and other area features.
2. Building and Hosting the Sprite Sheet
Once my sprite-sheet was ready I manually created the corresponding spritesheet.json file:
{
"pencil-wave": {
"width": 128,
"height": 128,
"x": 0,
"y": 0,
"pixelRatio": 1
},
"pencil-hatch": {
"width": 128,
"height": 128,
"x": 128,
"y": 0,
"pixelRatio": 1
}
}
These two files (spritesheet.png and spritesheet.json) were then uploaded to GitHub.
3. Linking in Maputnik
In Maputnik's Style Settings (the gear icon), I set the Sprite URL to the base path without the extension: https://mapsmania.github.io/mapchallenge/data/spritesheet. MapLibre GL JS automatically appends .png and .json to find the respective files.
Applying the Textures: Water and Buildings
With the sprite sheet successfully linked, I could apply my custom textures to the map layers.
For Water: pencil-wave
I located the water layer in Maputnik. In its Paint Properties, I simply added:
"pattern": "pencil-wave"For Buildings: pencil-hatch
The building style required a bit more finesse to capture that "sketched outline" and "semi-transparent texture" effect. I adopted a multi-layer approach:
Pattern Layer: A
filllayer. Here, I set:JSON"pattern": "pencil-hatch"Outline Layer: A
linelayer on top, using a dark grayline-colorand aline-dasharray(e.g.,[2, 2, 8, 2]) to give the outlines a broken, hand-drawn quality, rather than perfectly sharp digital lines.



Comments