# Nedle geography, 2026-10-23-v1

The shipped JSON is a fixed snapshot downloaded on **23 October 2026**. The game uses the bundled files directly; it makes no data API calls at runtime. A data refresh must use a new version and must deliberately review the daily answer schedule.

## Assets and scope

| File | Contents |
| --- | --- |
| `dist/data/places.json` | 6,977 accepted populated places in the European Netherlands, including small villages and hamlets; exactly 150 eligible daily answers |
| `dist/data/map.json` | A dry-land GeoJSON FeatureCollection and 12 province GeoJSON features, in WGS84 longitude/latitude |
| `scripts/prepare-data.py` | Source acquisition, fixed source hashes, canonicalisation, answer selection, map preparation and consistency checks |

All place IDs are strings of the form `geonames:2747373`. IDs identify a particular settlement point, so homonymous places can remain separate. Every place has `name`, `aliases`, `province`, `municipality`, `lat`, `lon`, `population`, and `eligible`. `answerIds` contains 150 distinct IDs and equals the set of places with `eligible: true`. The eligible flag controls answer selection; every catalogue entry can be a guess.

There is **no minimum population for guesses**. Of the 6,977 accepted entries, 4,141 have a GeoNames population of zero, meaning unavailable/unrecorded rather than proof of no inhabitants. Caribbean Netherlands is outside this game's geographic scope.

## Place sources and names

1. [GeoNames Netherlands country dump](https://download.geonames.org/export/dump/NL.zip), downloaded 2026-10-23. [GeoNames source and licensing information](https://www.geonames.org/about.html), [feature-code definitions](https://www.geonames.org/export/codes.html), and [dump format](https://download.geonames.org/export/dump/readme.txt). Licence: **CC BY 4.0**. Attribution: *GeoNames geographical database*.
2. [CBS, Woonplaatsen in Nederland 2025, table 86097NED](https://www.cbs.nl/nl-nl/cijfers/detail/86097NED), via its public [OData API](https://opendata.cbs.nl/ODataApi/OData/86097NED). Licence: **CC BY 4.0**. Attribution: *Centraal Bureau voor de Statistiek (CBS)*. The table lists 2,501 official BAG woonplaatsen as of 1 January 2025 using the February 2025 BAG extract; it is a name/administrative registry, not a town population table.
3. [PDOK / Kadaster BRK Bestuurlijke Gebieden](https://api.pdok.nl/kadaster/brk-bestuurlijke-gebieden/ogc/v1), `gemeentegebied` collection. Licence: **CC BY 4.0**, as identified in the service metadata. Attribution: *Kadaster, via PDOK*. All 342 municipal polygons are used to assign the containing municipality and province to each settlement point. A very small boundary tolerance handles points on a quay or just across a detailed administrative edge.

The accepted GeoNames feature classes are PPL, PPLA, PPLA2, PPLG, PPLC, PPLL and PPLF. A PPLS record is included only when its name resolves to an actual BAG woonplaats. PPLX neighbourhoods and historical PPLH/PPLCH records are excluded. PPLG is deliberately included: it is GeoNames' code for **The Hague**.

Canonical labels use the official BAG spelling where the record identifies that woonplaats. Guess-only local centres retain their own names when a GeoNames alias instead refers to their containing town; Portengen, Lelystad-Haven, Leusden-Zuid and Noordwijk aan Zee are examples. Exact nearby duplicate place records are combined within 750 metres, retaining the stronger population record and its aliases. Real namesakes remain separate.

The catalogue includes GeoNames' alternate names, ASCII spellings and common Dutch aliases. The Hague's canonical label is **'s-Gravenhage**, with **Den Haag** and **The Hague** accepted. **'s-Hertogenbosch** accepts **Den Bosch**. Available Frisian forms are retained, including **Ljouwert**, **Snits**, **It Hearrenfean** and **De Jouwer**; BAG Frisian spellings are used where supplied by the registry. Province Friesland is consistently labelled **Fryslân**.

Two explicit city representations avoid making a district label a daily answer:

- **Almere** uses the central GeoNames Almere Stad point, renamed to the official BAG city label; Almere Stad remains an accepted alias. Its stored population remains the GeoNames point population.
- **Katwijk** uses the GeoNames Katwijk aan den Rijn point and the official BAG town name, with the historical centre name retained as an alias.

## Fixed answer selection

Every one of the 150 answers is validated against the CBS/BAG register by **official woonplaats name and containing municipality**. Candidate towns are ordered by their recorded GeoNames population. The roster is then curated to remove neighbourhoods, municipality-only/composite labels and obvious cases where a small village's large GeoNames value reflects an entire municipality. Zaanstad, Velsen-Zuid, Hoogvliet, Ypenburg, Scheveningen, Hoensbroek, Medemblik, Epe, Bergen (NH), Dalfsen, Geldermalsen, Wierden, Loon op Zand, Borssele, Steenbergen, Brummen, Geertruidenberg and Tubbergen are excluded from answers; their source records can still be guesses.

Houten, Cuijk and Katwijk are explicitly included because their GeoNames point populations are substantially understated or refer to only a historical centre. The remaining 147 slots are filled by descending recorded population after curation and duplicate-BAG removal. Sorting by stable IDs freezes the resulting `answerIds` order. The rules and all manual decisions are visible in `scripts/prepare-data.py`; the exact resulting roster is in `places.json`.

**This is a population-led selection of larger towns and cities, not an official current top-150 population ranking.** GeoNames population values have mixed reference dates, sometimes correspond to a municipality rather than the settlement, and can be very old. For example, Houten is recorded as 1,335 and Cuijk as 3,610. These source values are intentionally left intact rather than replaced by unsupported estimates. The population field is used for roster preparation and search ranking, not presented as current statistical evidence. BAG membership validates the place's identity, not its population or city status. A fresh, consistent population ranking would require an additional comparable settlement-level population source.

## Map sources and processing

- [PDOK / Kadaster `provinciegebied`](https://api.pdok.nl/kadaster/brk-bestuurlijke-gebieden/ogc/v1/collections/provinciegebied): **CC BY 4.0**. Provides the country outline used for clipping and all 12 provincial administrative boundaries.
- [Natural Earth 1:10m physical land v5.1.1](https://www.naturalearthdata.com/downloads/10m-physical-vectors/10m-land/): **public domain**. Supplies physical coastline and island geometry.
- [Natural Earth 1:10m lakes v5.0.0](https://www.naturalearthdata.com/downloads/10m-physical-vectors/10m-lakes/): **public domain**. Subtracted from the physical land mask, including the IJsselmeer/Markermeer and Lauwersmeer.

Administrative areas include large water surfaces. The map therefore intersects the national administrative geometry with Natural Earth's **physical land minus lakes**. Provincial features are clipped to the resulting dry-land mask, so drawing them cannot fill the IJsselmeer, Markermeer, North Sea or Wadden Sea as land. Mainland, Zeeland's islands, Texel, Vlieland, Terschelling, Ameland, Schiermonnikoog and the minor northern islands are retained.

Processing uses RD New (EPSG:28992) for a 65-metre topology-preserving simplification, removes tiny clipping fragments below 20,000 m², and then returns coordinates to **WGS84 (EPSG:4326), longitude first**, rounded to five decimals. GeoJSON rings follow the right-hand rule. The browser should apply its own Mercator display transform; these files are not preprojected. Province features are Polygon/MultiPolygon geometries suitable for faint outlines over the land layer.

Natural Earth's 1:10m source is intended for a national overview. Small canals, ponds, narrow rivers, tiny islands and later reclamations can be absent or generalised; this is not a navigation or cadastral map. Province edges near the shoreline combine the newer BRK administrative boundary with the generalised physical coast. These limitations do not affect the independent point coordinates used for distance and direction.

## Rebuild and verification

The JSON source manifests contain the exact download URLs, licence labels, download date, original byte SHA-256 and content SHA-256. The script's pinned content hashes ignore volatile OGC timestamps and ZIP container dates while covering the actual source records. A changed upstream dataset fails the build instead of silently changing an established puzzle. The original source files are cached in `/tmp/nedle-geography` during preparation and are not shipped to the browser. Because GeoNames and PDOK URLs are live exports, future exact rebuilds require that original cache if the live records have changed; the delivered JSON remains the durable fixed game snapshot.

Example setup and use:

```sh
python3 -m venv /tmp/nedle-geography/venv
/tmp/nedle-geography/venv/bin/pip install 'shapely>=2.1,<3' pyproj pyshp
/tmp/nedle-geography/venv/bin/python scripts/prepare-data.py
/tmp/nedle-geography/venv/bin/python scripts/prepare-data.py --verify
```

`curl` uses normal TLS certificate verification. No API keys are needed. Build dependencies are only for preparation; the deployed game is static.

Checks cover distinct place IDs; geographic bounds; 12 provinces; non-empty municipal context; exactly 150 distinct, resolvable answer IDs; equality between the roster and eligible flags; BAG names for every answer; Den Haag and Den Bosch aliases; explicit answer exclusions; valid GeoJSON; the five main Wadden islands; and water exclusion for IJsselmeer, Markermeer, Waddenzee and North Sea. A rendered overview was also inspected for coast, islands, lakes and province outlines.
