doxa-maps/library/scripts/posters/data/README.md
doxa-maps-88655c70 fd2077625a
Some checks are pending
build-gate / build (push) Waiting to run
feat(posters): capitals and major cities on the country maps
The Driver asked for map detail: "a typical map poster needs details on the
map that is not hard to see, but not so much that it becomes too complicated
— cities and capitals makes sense."

Natural Earth 1:10m, PUBLIC DOMAIN: no attribution to carry onto a printed
packet, vendored so a build is reproducible offline with no runtime
dependency. Trimmed at vendor time from 4.9 MB / 7,342 places to 170 KB /
2,573 (national + admin-1 capitals, plus cities >= 250k) because a poster
cannot legibly carry 7,342 dots and the packet is downloaded.

The layer is deliberately SUBORDINATE. It answers "where am I?"; the
people-group pins answer "who do I pray for?", and they keep the only
saturated colour on the sheet. Capitals are ringed dots (the cartographic
convention), cities plain dots — shape and value carry the rank so no extra
hue is spent. Reading order stays country > province > city > people group.

Three things had to be right, each found by measuring rather than by looking:

1. RANK BY RELEVANCE TO THE SUBJECT, not by global importance. Sorting by
   capital-rank then population is the obvious choice and is wrong: the
   neighbours are usually bigger. On the Laos sheet that sort spent the budget
   on 12 Vietnamese and 8 Thai cities and printed exactly ONE Laotian place
   while 12 more sat available — a poster of Laos labelled with other
   countries' cities. Subject countries now win the budget.

2. DERIVE THE SUBJECT FROM THE PINS, not from the zone. zone.adm0 exists only
   on generated city/country zones; the hand-authored lists carry a selector
   in SEVEN shapes (pg_slugs, country_code, country_codes, wagf_block,
   wagf_region, union, deaf_predicate) and the most common names no country at
   all. Reading zone.adm0 produced an empty set and the whole sort silently did
   nothing. The pins always know their own country.

3. AVOID THE PINS USING WHERE THEY ARE DRAWN. Two distinct errors here. Testing
   the label's ANCHOR is wrong for a right-aligned label, whose glyphs run
   leftward from it — so the box is tested, not the point. And the de-overlap
   relaxation MOVES badges after projection, so proj(pin.lng,pin.lat) is not
   where the badge lands; this block therefore runs AFTER layoutLabels and reads
   laid[].px/py. With the naive tests, 7 of 25 labels sat within 14px of a pin
   and Saravan landed 1.4px away while the check reported it clear. Now: 291
   labels across 16 posters, ZERO overlaps. A city that cannot fit clear of a
   pin is dropped — a missing city costs nothing, an obscured people group
   costs the poster its purpose.

⚠ ROADS WERE REQUESTED AND DELIBERATELY NOT SHIPPED. Natural Earth's 10m roads
layer was fetched and measured: ZERO features for LAO, MMR, KHM, VNM, THA, NPL,
BTN, TCD, NER, MLI, SOM, AFG, YEM, IDN, IND and CHN. Its coverage is essentially
USA/CAN/MEX. It would draw a dense network on a US map and nothing on every
country these packets are for — a broken-looking map exactly where it matters.
Real road coverage needs an OSM extract: a much larger dependency with an ODbL
attribution obligation, so it is carded rather than half-shipped. See
data/README.md.

Note: zone oceania-indonesia fails generation with a header-overflow error.
Verified pre-existing on a clean tree — unrelated to this change.
2026-09-24 02:21:03 +00:00

51 lines
2.2 KiB
Markdown

# Vendored map data
## `ne-places.json` — capitals and major cities
**Source:** Natural Earth 1:10m populated places (`ne_10m_populated_places_simple`)
**Licence:** **Public domain.** Natural Earth explicitly places its data in the public
domain: no attribution required, no notice to carry onto a printed packet.
**URL:** https://www.naturalearthdata.com/
### Why vendored rather than fetched
A build must be reproducible offline and must not add a runtime dependency — the
posters are generated token-free and the packets are printed and carried. Vendoring
also pins the data, so a poster regenerated next year looks like the one printed
today.
### How it was trimmed (4.9 MB → 170 KB, 7,342 → 2,573 places)
Kept:
- every national capital (`Admin-0 capital`, `Admin-0 capital alt`)
- every first-order administrative capital (`Admin-1 capital`, and the
`Admin-0/1 region capital` variants)
- ordinary populated places only where `pop_max >= 250000`
A poster cannot legibly carry 7,342 dots, and the packet is downloaded, so the
filter serves legibility and weight at once. Field names are single letters for the
same reason:
n name (ascii) c ISO3 country
k 0 national capital / 1 admin-1 capital / 2 city
p pop_max y latitude x longitude
To regenerate, fetch `ne_10m_populated_places_simple.geojson` from
`nvkelso/natural-earth-vector` and apply that filter.
## ⚠ Why there is no `ne-roads.json`
Roads were requested and **deliberately not shipped**. Natural Earth's 1:10m roads
layer was fetched (50 MB) and measured: it has **ZERO features** for
LAO MMR KHM VNM THA NPL BTN TCD NER MLI SOM AFG YEM IDN IND CHN
Its attributed coverage is essentially USA (7,417 segments), Canada (900) and
Mexico (897); 47,262 of 56,600 segments carry no country at all.
Shipping it would draw a dense road network on a United States map and **nothing**
on every country these packets are actually for — which reads as a broken map
precisely where it matters most. A roads layer needs a source with real coverage in
South/Southeast Asia and Africa (an OpenStreetMap extract), which is a much larger
dependency with an attribution obligation (ODbL). That is a separate piece of work,
carded rather than half-shipped.