Outreach project around the Mapa de la Isla de Mallorca by Cardinal Antoni Despuig, engraved 1785 (high-resolution original from the Biblioteca Virtual de Defensa, CC BY 4.0).
The repository holds two applications — a public website and an internal curation tool — plus the data pipeline that feeds them.
The published site: town pages (1785 census + cartela text + clean vignette + locator
map), a filterable/sortable table of the ~2,515 curated toponyms, an interactive Mapa
(geographic layer + deep-zoom of the engraving), and statistics ("the 1785 map" vs "our
reading process"). Catalan UI; cartela texts kept in
their original period spelling. It is self-contained: it only reads the versioned
JSON under web/src/data/, never the pipeline internals.
cd web
npm install
npm run data # build src/data/*.json from the per-sheet pipeline output
npm run vinetes # town vignettes (needs data/jpg/, local-only)
npm run hero # homepage hero crop
npm run map # DZI tiles for the engraving deep-zoom on /mapa (slow; only when the master changes)
npm run sheets # per-quadrant DZIs for the "El gravat" tab (slow; only when the master changes)
npm run dev # http://localhost:4330
npm run build # → web/dist (prebuild runs data + vinetes + hero)Deploy = Cloudflare Workers (Static Assets) (build locally because the source images
are not in git): npm run deploy (= build + wrangler deploy, config in web/wrangler.toml).
Live at https://mapa-despuig.cloudflare-d82.workers.dev.
A local, single-file web app used to hand-curate the toponyms quadrant by quadrant. It is not part of the deployed website and is intentionally not documented inside it. Three views over the same data:
- Taula — an editable grid (fast bulk edits: reading, tipus/ordre, NGIB pick, verdict).
- Fitxes — one toponym at a time with the engraving crop, the nearby NGIB candidates, and a map (click a point to associate its NGIB form).
- Mapa — all toponyms on a geographic layer, coloured by confidence.
All hand edits persist to a single overlay per sheet — data/toponims/<q>/curation.json,
one record per toponym id, e.g. { "graf": "...", "tipus": [...], "ordre": [...], "ngib": "...", "verdict": "ok|pick|none|trash" }. Picks are stored as pending until the sheet
is baked.
nix-shell -p nodejs --run 'node scripts/toponims/review-server.mjs' # http://localhost:4400After a curation round, bake the changed sheet(s) and regenerate the website data:
nix-shell scripts/toponims/shell.nix --run 'python3 scripts/toponims/mapkurator/bake.py <q>'
cd web && npm run dataThe data engine behind both apps. The map is worked quadrant by quadrant
(NW/NE/SE/SW): GCPs from hand-marked dots → mapKurator spotter (GPU) → Approach-B vision
reading → assemble → per-sheet georeference (+ dense refinement from confirmed matches) →
NGIB gazetteer match. Quality is recorded on two orthogonal axes: confidence
(decision) and human review (review).
Full reproducible recipe: scripts/toponims/mapkurator/PER-SHEET.md.
Spotter setup: scripts/toponims/mapkurator/README.md
— a slim multi-stage GPU image (~5.8 GB; the custom adet._C op is baked in).
Per-sheet outputs live in data/toponims/<q>/ (versioned); the gazetteer and large
image/tile assets are local-only (regenerable). node/python3 come from the nix
shells (nix-shell -p nodejs --run …, scripts/toponims/{,mapkurator/}shell.nix).