Extending Massif
The CartoCSS project is meant to be a base. A child project extends it and restates only
what it changes, so a new Massif release is picked up by replacing the base files and leaving
yours alone. Both CartoCSS flavours (plain and icon font) take a child; the compiled ones do not,
since they carry no CartoCSS any more — compile your child instead
(massif-style css2xml mine.json mine.xml, style CLI).
A child is a <name>.json beside project.json, loaded like a variant (name: 'mine'):
{
"extends": "./project.json",
"styles": ["mine-colors.mss", "variables.mss", "style.mss", "mine-rules.mss"],
"styleparameters": {
"variant": { "default": "streets", "values": { "streets": "streets", "outdoor": "outdoor", "topo": "topo", "hybrid": "hybrid", "eink": "eink" } },
"poiStyle": { "default": "plain", "values": { "badge": "badge", "plain": "plain" } },
"track_min_zoom": 13
}
}
Three things it can do:
- Colours and fonts — a stylesheet listed before
variables.mssredeclares a variable:@motorway,@water,@wood,@font_medium... The compiler keeps the first declaration of a variable, so yours wins. The names are listed invariables.mss. - Rules — a stylesheet listed after
style.mssadds rules. A new attachment (#landcover[class = 'wood']::mine_pattern { … }) draws with its layer, over the base, without touching it. - Defaults —
styleparametersmerge key by key: set a parameter's default, or declare a new one for your own rules.stylesdoes not merge; it is restated whole.
A layer is replaced by moving the base one out of reach through its parameter and drawing your
own: track_min_zoom: 24 hides Massif's tracks, a rule after style.mss draws them your way.
POIs are one template, %poi, drawn into one attachment, ::poi, so a child widens a class —
draws it where the base's rank ladder does not yet — or narrows one, with a rule of its own:
#poi[zoom >= 15][class = 'bakery']::poi {
@extend %poi;
shield-placement-priority: (30000000 + (((([param::poi-boost-[subclass]]) ?? (0)) != 0) ? (([param::poi-boost-[subclass]]) ?? (0)) : (([param::poi-boost-[class]]) ?? (0))));
}
#poi[zoom < 17][class = 'pharmacy']::poi { display: none; }
The term after 30000000 is the one every base POI rule adds, so an app's poi-boost-<class> still
reaches a rule that states its own priority. To only re-rank a class, set poi-boost-<class> instead
of writing a rule (style README).
The bus and tram stops' zooms are project constants, moved with no rule at all:
"constants": { "poi_bus_minzoom": 15, "poi_bus_label_minzoom": 16, "poi_tram_minzoom": 16,
"poi_tram_label_minzoom": 16, "poi_pt_shelter_minzoom": 15 }
So are the rank ladder's: poi_rank10_minzoom (14), poi_rank30_minzoom (15),
poi_rank30_label_minzoom (16), poi_rank70_minzoom (16), poi_rank_all_minzoom (17).
How the template, the attachment and display compile: CartoCSS templates.
The OpenStreetMap example
osm.json ships in both CartoCSS flavours: Massif re-skinned with OpenStreetMap Carto's colours, as
Alpimaps' OSM style has them. Load it as name: 'osm'. Its
three files:
osm-colors.mss(beforevariables.mss) — the palette redeclared: OSM Carto's road colours, some ramped over zoom as OSM Carto ramps them (a variable may hold an expression:@primary: linear([view::zoom], (11, #f3ba5c), (12, #fcd6a4));), its water, woods, landuse and buildings.osm-rules.mss(afterstyle.mss) — what the palette cannot say: tracks as a brown line under white dashes bytracktype, OSM Carto's textures over woods, scrub, wetland and rock, and the POIs above (bakeries early, pharmacies late).osm.json— the defaults: POIs as bare glyphs (poiStyle: plain), Massif's tracks out of reach (track_min_zoom: 24), roads outlined and widened at low zoom as OSM Carto does (road_osm_low: 1), tunnels plain until z13 (tunnel_min_zoom: 13), bus stops from z15, named from z16, and public-transport shelters from z15 (constants).
custom.json is the smaller example: two colours, one rule, a new parameter.
Two limits. A variable names a value: two palette entries with the same colour share one name, and redeclaring it changes both. And a child changes the CartoCSS only.
The MapLibre side
MapLibre has no child styles. The MapLibre variants are generated by
styles/massif/build.py from
a Python palette and layer modules: a MapLibre variant of your own is a fork of that folder — edit
palette.py, run python3 build.py — or a JSON patch over a published style.