Offline tiles were built from Protomaps' own basemap schema, needing a completely separate hand-tuned theme (protomaps-themes-base + OFFLINE_THEME) from the online Liberty style's ONLINE_STYLE_PATCH — the two could never be made to match exactly no matter how much either side got tuned (today's session found and fixed several mismatches: building opacity, park boundaries, road casings, road widths). Offline.pmtiles is now built with Planetiler's default OpenMapTiles profile against Geofabrik per-country OSM extracts (osmium-merged when more than one country is selected), the same vector schema Liberty already expects. offlineStyle() now clones the same Liberty JSON (vendored as a local snapshot for reliability with no internet) and applies the identical ONLINE_STYLE_PATCH, just repointed at local PMTiles/glyphs/sprite — one palette instead of two, correct on both sides by construction. Also vendors Liberty's icon sprite for the first time (offline had none before), adds Java/osmium-tool/planetiler.jar to the Docker image, and removes the now-unused protomaps-themes-base dependency and the theme-comparison debug page that found today's bugs.
360 lines
17 KiB
Plaintext
360 lines
17 KiB
Plaintext
= National Park Service mapping resources
|
||
:toc:
|
||
:toclevels: 2
|
||
|
||
A reference for what's out there in the National Park Service's mapping
|
||
ecosystem: what this app has actually adopted, what was investigated and
|
||
deliberately skipped, and the licensing/provenance details behind each.
|
||
Kept as a knowledge base since NPS's tooling has repeatedly turned out to
|
||
be a better source than reinventing something from scratch — worth
|
||
checking here before searching from zero next time.
|
||
|
||
== What this app actually uses
|
||
|
||
[cols="1,2,1"]
|
||
|===
|
||
| What | Where | License
|
||
|
||
| `symbol-library` (map category icons, POI badge glyphs)
|
||
| `public/js/icons.js`'s `POI_ICONS`/`PARK4NIGHT_TAGS`
|
||
| CC0 (public domain)
|
||
|
||
| `home-button` (the "Home" map control)
|
||
| `public/vendor/npmap-home-button/`
|
||
| MIT (per `package.json`); the whole `npmap5-plugins` repo is separately
|
||
public domain as a US government work
|
||
|
||
| Park Tiles color palette (shared offline + online basemap theme)
|
||
| `public/js/map.js`'s `ONLINE_STYLE_PATCH`
|
||
| Colors only — see <<park-tiles>> for why the actual tile service isn't used
|
||
|
||
| `overview` (top-right minimap/inset control)
|
||
| `public/vendor/npmap-overview/`
|
||
| MIT (per that branch's `package.json`); same public-domain repo as above
|
||
|===
|
||
|
||
See `docs/third-party-notices.adoc` for the formal vendored-library
|
||
notice and `docs/architecture.adoc` for how each is wired in.
|
||
|
||
== npmap5-plugins
|
||
|
||
https://github.com/nationalparkservice/npmap5-plugins — a monorepo of
|
||
MapLibre GL JS plugins built for NPS's current (v5) map stack. Live
|
||
demos: https://nationalparkservice.github.io/npmap5-plugins. More
|
||
examples/screenshots: issue
|
||
https://github.com/nationalparkservice/npmap5-plugins/issues/7[#7].
|
||
|
||
=== On `main` (stable, what we've pulled from)
|
||
|
||
[cols="1,3"]
|
||
|===
|
||
| Plugin | What it is
|
||
|
||
| `symbol-library`
|
||
| The icon set — see above. Confirmed by the maintainer
|
||
(issue https://github.com/nationalparkservice/npmap5-plugins/issues/4[#4])
|
||
to be the designated replacement for the older standalone
|
||
`nationalparkservice/symbol-library` repo, with a much larger
|
||
vocabulary (300+ icons vs. the ~200 in the old repo).
|
||
|
||
| `home-button`
|
||
| Adopted, see above.
|
||
|
||
| `svg-icons`
|
||
| *Considered, not adopted.* Solves the same "recolor an icon at
|
||
render time" problem we hit and fixed ourselves this session (see
|
||
`docs/architecture.adoc`'s note on `_registerCategoryGlyphs` — SDF
|
||
images need an actual distance field, not a plain antialiased
|
||
raster, or edges blur). Its approach is more general (lazy,
|
||
on-demand recoloring via a `styleimagemissing` listener and a
|
||
query-string-encoded `icon-image` id, vs. our upfront
|
||
per-distinct-color registration) but swapping in ~800 lines of
|
||
unfamiliar third-party logic for something already working and
|
||
understood wasn't a clear win — no bug it would fix, no capability
|
||
we're missing.
|
||
|
||
| `interactivity`
|
||
| Not investigated in depth — "makes interactivity easier with
|
||
MapLibre GL JS". Our own click/hover handling (`gpx.js`) is already
|
||
small and specific to this app's needs.
|
||
|
||
| `maplibre-gl-vector-text-protocol`
|
||
| Loads KML/GPX/TopoJSON/OSM directly into MapLibre client-side. Not
|
||
a fit: our GPX/FIT handling is server-side
|
||
(`lib/maptool/gpx.rb`/`fit.rb`) specifically so we can compute
|
||
track stats, POI category styling, clustering, etc. — a generic
|
||
client-side loader wouldn't give us any of that.
|
||
|
||
| `markdown-handlebars`
|
||
| *Considered, not adopted.* Renders Markdown-with-`{{handlebars}}`
|
||
as HTML. Our waypoint popup content isn't Markdown — it's
|
||
park4night's own semi-structured text format (`formatDescription`
|
||
in `gpx.js` parses `Label: value` lines and turns Services/
|
||
Activities into icon tags) — a generic templater would replace the
|
||
wrong layer of that logic, and would mean trusting a new,
|
||
unaudited HTML-rendering path for untrusted (uploaded-file) content
|
||
in place of our already-reviewed escaping.
|
||
|
||
| `source-arcgis-rest`, `source-wms`
|
||
| Add ArcGIS REST / WMS raster layers as MapLibre sources. No current
|
||
need — we don't have an ArcGIS or WMS data source to point at. `wms`
|
||
explicitly noted by the user as maybe useful in the future.
|
||
|===
|
||
|
||
=== On unmerged feature branches (less vetted — not on `main` yet)
|
||
|
||
`overview` (branch `maplibre-gl-overview`) has since been adopted —
|
||
see "What this app actually uses" above and
|
||
`docs/architecture.adoc`'s control-stack section. Live demo (as
|
||
upstream ships it, unpatched):
|
||
https://raw.githack.com/nationalparkservice/npmap5-plugins/maplibre-gl-overview/examples/index.html.
|
||
Note: MapLibre GL JS has no first-party minimap of its own — this
|
||
isn't more "official" than any other third-party minimap plugin, just
|
||
NPS-flavored.
|
||
|
||
[cols="1,3"]
|
||
|===
|
||
| Plugin | What it is
|
||
|
||
| `carto` (branch `maplibre-gl-carto-source`)
|
||
| Adds a vector-tile source backed by Carto.com-hosted data. Only
|
||
useful if we actually have a Carto-hosted dataset to point at — we
|
||
don't right now.
|
||
|
||
| `wms` (branch `maplibre-gl-wms-source`)
|
||
| WMS raster layer source. Noted by the user as possibly handy later;
|
||
no current use case.
|
||
|===
|
||
|
||
=== Pending upstream: symbol artwork revisions
|
||
|
||
https://github.com/nationalparkservice/symbol-library/pull/226 ("npmap-hfc
|
||
standardization 2024") — a large (169-file), still-*open*/unmerged artwork
|
||
revision pass on the *old* standalone repo, open since January 2024. Of the
|
||
icons this app actually uses, three have revised artwork proposed there:
|
||
|
||
* `bicycle-trail` (our `sport_cycling`/`vtt`)
|
||
* `campground` (our `tourism_camp_site`)
|
||
* `pets-on-leash` (our `animaux`)
|
||
|
||
Plus filename-only renames (e.g. `motor-bike-trail` → `motorbike-trail`,
|
||
`sea-plane` → `seaplane`) and a handful of new icons not relevant to our
|
||
current `PARK4NIGHT_TAGS` mapping (`e-bike`, `foraging-gathering`,
|
||
`seaplane`, `toilet`, `windmill`). Deliberately *not* pulled in — it's an
|
||
unmerged draft, could still change. Worth revisiting once it lands on
|
||
`main` in whichever repo ends up canonical.
|
||
|
||
[[park-tiles]]
|
||
== Park Tiles (the NPS basemap theme)
|
||
|
||
https://www.nps.gov/maps/web/tools/park-tiles/ — the data and cartography
|
||
system behind NPS's own web maps. Documentation:
|
||
https://www.nps.gov/maps/web/tools/npmapjs/index.html (the wider NPMap
|
||
code library docs), legend:
|
||
https://www.nps.gov/maps/web/tools/park-tiles/legend/index.html, symbols:
|
||
https://www.nps.gov/maps/web/tools/park-tiles/pictographic-symbols/index.html.
|
||
|
||
=== Design lineage
|
||
|
||
Explicitly traces back to the National Park Service's iconic print
|
||
brochure maps produced at the Harpers Ferry Center — the Park Tiles team
|
||
consulted HFC cartographers directly, adapting the same visual language
|
||
for digital display. This is also the design lineage behind the
|
||
`Unigrid` system (Massimo Vignelli's 1970s NPS brochure/signage
|
||
template), one of the most respected government design programs.
|
||
|
||
=== The four style variants
|
||
|
||
* *Standard* — the default; used in the NPS mobile app and most of
|
||
nps.gov.
|
||
* *Aerial* — integrates an imagery underlay.
|
||
* *Slate* — dark grey, lets overlay data stand out; also deliberately
|
||
chosen to work well for low-vision users with inverted browser color
|
||
settings.
|
||
* *Light* — another neutral choice for data-overlay contexts.
|
||
|
||
=== Why we can't use the actual tile service
|
||
|
||
Their basemap data pipeline blends NPS's own enterprise GIS data
|
||
(roads/trails/buildings/parking/POIs/boundaries) with USGS/Census federal
|
||
data and, for context outside park boundaries (streets, coastlines,
|
||
buildings, terrain/hillshade), **OpenStreetMap data pre-processed by
|
||
Mapbox as part of their commercial Atlas service** — a paid,
|
||
non-sublicensable data license scoped to NPS's own use. Separately, the
|
||
cartography is explicitly designed for park visitors (trailhead/park-unit
|
||
labeling prioritized), not general-purpose worldwide mapping. Both are
|
||
why this app uses OpenFreeMap Liberty as its actual basemap, not Park
|
||
Tiles — see `docs/architecture.adoc`'s "Offline maps" section.
|
||
|
||
Recreating the *color choices* is a different matter — not the kind of
|
||
thing a data license restricts — and is what `ONLINE_STYLE_PATCH` in
|
||
`public/js/map.js` actually does (see `docs/architecture.adoc`).
|
||
|
||
=== Public style JSON (source for the real colors we did pull)
|
||
|
||
Of Park Tiles' four variants, only *Imagery* is served from a plain,
|
||
unauthenticated URL:
|
||
|
||
https://www.nps.gov/lib/npmap.js/style/ck72fwp2642dv07o7tbqinvz4.json
|
||
|
||
("Park Tiles 4 Imagery", 129 layers — a genuine Mapbox/MapLibre style
|
||
spec, found via `npmap.js`'s own bundled `baselayers.json` config.)
|
||
*Standard*, *Slate*, and *Light* resolve through Mapbox Studio's private
|
||
Styles API using an access token instead (`style_id`s below) — visible in
|
||
`npmap.js`'s own bundle, but not something to fetch using someone else's
|
||
embedded credentials, even when technically reachable:
|
||
|
||
[cols="1,1"]
|
||
|===
|
||
| Variant | Mapbox Studio `style_id`
|
||
|
||
| Standard
|
||
| `ck58pyquo009v01p99xebegr9`
|
||
|
||
| Slate
|
||
| `ck5cpvc2e0avf01p9zaw4co8o`
|
||
|
||
| Light
|
||
| `ck5cpia2u0auf01p9vbugvcpv`
|
||
|===
|
||
|
||
Colors actually pulled from the Imagery style JSON and used in
|
||
`ONLINE_STYLE_PATCH`: background (`hsl(40, 37%, 97%)`, a warm cream), the
|
||
park/protected-area green (`#b3e378`), the two road-importance tiers
|
||
(`#fdefbe`/`#fef7dd`), and the park-boundary line color (`#546619`, dark
|
||
olive). The rest of `ONLINE_STYLE_PATCH` extends that same warm/olive
|
||
family by eye rather than from a sourced value.
|
||
|
||
=== Legend / cartographic hierarchy
|
||
|
||
The legend page documents NPS's own road/trail classification standard
|
||
(primary/secondary/local/4WD/private/service roads; conventional/paved/
|
||
boardwalk trails; public/private buildings), each shown across all four
|
||
variants. Keyed to NPS's internal "NPS geospatial data standard for
|
||
roads," not OSM's `highway=*` tagging scheme — informative as design
|
||
reference, not directly portable onto our OSM-derived data without
|
||
reinterpreting the mapping ourselves.
|
||
|
||
== Typography & editorial standards
|
||
|
||
Part of the NPS graphic identity, alongside Park Tiles — noted for
|
||
completeness, but not adoptable and not directly relevant to this app's
|
||
own work (a map viewer, not a publisher of NPS-branded content):
|
||
|
||
* *Typefaces*: the standards specify two — *NPS Rawlinson* (licensed to
|
||
NPS by its creator, Terminal Design) and *Frutiger* (licensed from
|
||
Adobe Systems). Both proprietary/commercially licensed, unlike the
|
||
fonts this app already vendors (Noto Sans, SIL OFL — see
|
||
`docs/third-party-notices.adoc`) — not something to pull in.
|
||
* *A genuinely open alternative*: https://github.com/national-park-service/fonts
|
||
— despite the org name, its own `DISCLAIMER.md` is explicit that this
|
||
is an **independent, unofficial** project, "not affiliated with,
|
||
endorsed by, or sponsored by" NPS, and that its six typefaces (NPS
|
||
2026, Redwood Serif, Campmate Script, NPS Symbols, Sequoia Sans,
|
||
Switchback) are original works "inspired by" public-lands signage —
|
||
explicitly *not* reproductions of Rawlinson or anything NPS actually
|
||
owns. SIL OFL 1.1 licensed, same family of license as the fonts this
|
||
app already vendors. Unlike Rawlinson/Frutiger above, this one's
|
||
actually usable if the NPS-inspired look is ever wanted in this app's
|
||
own UI chrome (currently plain system fonts, `public/css/style.css`) —
|
||
no current use case, but no licensing blocker either, worth
|
||
remembering if that comes up.
|
||
* *Another open alternative, for display use*: https://nationalparktypeface.com[National Park]
|
||
— a separate, unrelated project (Ben Hoepner, Andrea Herstowski, Jeremy
|
||
Shellhorn / DO Studio), also SIL OFL licensed, also original ("inspired
|
||
by" park signage, not a Rawlinson reproduction). Ships as variable
|
||
`.ttf`, `.woff`/`.woff2`, and `.otf` — self-hostable via `@font-face`
|
||
the same way. Where it differs from Sequoia Sans above: it's a
|
||
router-carved-signage *display* face (the chunky all-caps look of
|
||
actual trailhead signs), not a general body/UI sans — best fit would be
|
||
a wordmark/heading use (e.g. the topbar's "MAPTOOL" text) alongside a
|
||
more legible sans for body copy, not a full typeface swap. Now used for
|
||
exactly that: `.topbar__brand` only (`public/css/style.css`), Bold
|
||
weight vendored under `public/vendor/national-park-typeface/` — see
|
||
`docs/third-party-notices.adoc`. Body copy elsewhere still plain system
|
||
fonts, unchanged.
|
||
* *Hawaiian typography*: NPS Rawlinson includes vowels with Hawaiian
|
||
macrons (ā, ē, ī, ō, ū) and the okina (ʻ); the regular weight of
|
||
Frutiger doesn't, so NPS uses a separate "HFrutiger" weight for
|
||
Hawaiian-language text in official materials.
|
||
* *Editorial style guide*:
|
||
https://www.nps.gov/subjects/hfc/hfc-editorial-style-guide.htm — HFC's
|
||
writing/terminology conventions (capitalization, place names,
|
||
Spanish-language guidance, disability language, etc.), built on top of
|
||
the Chicago Manual of Style, AP Stylebook, and GPO Style Manual. A
|
||
content style guide for NPS's own written materials, not a design/code
|
||
resource — included here only because it was shared alongside the
|
||
typography notes above.
|
||
|
||
== NPMap4 (the older, Leaflet-based generation)
|
||
|
||
https://www.nps.gov/lib/npmap.js/4.2.1/ — predecessor to npmap5,
|
||
Leaflet-based, MIT-licensed. Superseded but still live, and currently
|
||
*more feature-complete* than npmap5: v4 is one large, mature framework
|
||
(~87k lines, years of accumulated features — baselayer presets, a
|
||
geocoder, popups, etc. all in one package), while npmap5 is a
|
||
still-in-progress rewrite split into small, independently-versioned
|
||
plugins (several still at `0.0.1-x`, pre-1.0), a few of which (`overview`,
|
||
`carto`, `wms`) aren't even merged to `main` yet — see above. v5 is the
|
||
direction NPS is migrating to, not (yet) a feature-for-feature
|
||
replacement; expect this gap to close over time, not to stay this way.
|
||
Three things worth noting from v4:
|
||
|
||
* *`infoboxControl`* — example:
|
||
https://www.nps.gov/lib/npmap.js/4.2.1/examples/basic/infobox.html. A
|
||
generic "click anything, show every raw property in a table" debug
|
||
view, kept separate from a dataset's own curated popup. *Adopted* — not
|
||
the code (Leaflet, not portable) but the concept: this app now has the
|
||
same thing as an Alt+click handler (see `docs/architecture.adoc`'s
|
||
"Debug inspector" section), showing `queryRenderedFeatures` results —
|
||
base map OSM tags included, not just this app's own layers.
|
||
* *Geocoder control* — example:
|
||
https://www.nps.gov/lib/npmap.js/4.2.1/examples/controls/geocoder-control.html.
|
||
Config is `geocoderControl: { searchPlaces: true }`: a search box that
|
||
resolves NPS park units by name/unit code, or a street address, or
|
||
raw coordinates, and jumps the map there. The concept (type a
|
||
place/address/coordinates, jump to it) is genuinely transferable and
|
||
not NPS-specific — could be built for this app with any geocoder (e.g.
|
||
OSM's free Nominatim), independent of anything NPS. Not implemented;
|
||
noted as a candidate feature if wanted later.
|
||
* Confirmed *not* a source for basemap tiles we could use — same
|
||
`nps-parkTiles*` naming and same underlying Mapbox Atlas-licensed data
|
||
pipeline as npmap5's Park Tiles (see <<park-tiles>>).
|
||
|
||
== Data tooling (not adopted)
|
||
|
||
https://github.com/nationalparkservice/national-dataset-query — a
|
||
Node.js *CLI tool*, not a browser library (different category from
|
||
everything else in this doc): pulls data from ArcGIS/ESRI REST endpoints
|
||
and converts it to GeoJSON/GeoJSONSeq/GeoPackage. Would only be relevant
|
||
if we ever wanted to bake a specific ArcGIS-hosted dataset into an
|
||
offline extract — the same role `data/offline.pmtiles` already plays for
|
||
OSM-derived data, just a different source. No current need, and unlike
|
||
everything else in this doc (CC0, BSD, MIT, public domain) this repo has
|
||
**no `LICENSE` file at all** — its terms are genuinely unclear, so treat
|
||
that as a blocker too, not just "no use case yet."
|
||
|
||
=== NPS Data API (developer.nps.gov)
|
||
|
||
A separate thing from the tile/Park Tiles service above — a general
|
||
government open-data API (parks, alerts, campgrounds, places, ... —
|
||
official docs: https://www.nps.gov/subjects/developer/api-documentation.htm,
|
||
a JS-rendered Swagger UI that doesn't render via a plain fetch; a free
|
||
API key from that same page is required to call it). No current use
|
||
case (this app isn't NPS-park-specific — park4night POIs and personal
|
||
GPX/FIT tracks, not NPS units), but it's the legitimate, non-Mapbox-Atlas
|
||
government data source behind it, worth remembering if a "show nearby
|
||
NPS park info/alerts" feature ever comes up — the `wms`/`source-arcgis-rest`
|
||
npmap5-plugins entries above would be the MapLibre-side plumbing for it.
|
||
Two hobby projects (both MIT, not NPS-affiliated, not directly reusable
|
||
as libraries — noted only as real-world examples of consuming this API)
|
||
turned up while looking at this:
|
||
|
||
* https://github.com/carlknutson/nps-changes-site — a React/Leaflet
|
||
explorer for all NPS sites, most fields sourced from this API
|
||
(supplemented by manual/AI-assisted research for fields the API
|
||
doesn't have), data refreshed daily via GitHub Actions rather than
|
||
called live.
|
||
* https://github.com/seankelliher/us-national-parks-alerts — a
|
||
Vue + Express directory of park alerts, pulled live through this API.
|