Adding a state
A new state is source YAML plus one registry row — no new rendering code.
The design goal: covering your state is data work, not engineering. Each
layer is one YAML file in sources/, and the map renders whatever the
registry declares. Every state we cover went in this way — Montana, the fifth,
took a day.
Pennsylvania, the sixth, is the one that tested the claim, because it is the
first eastern state and the first that is barely a draw state at all. The
layers went in as advertised. What did not generalize was everything around
them: the game-species vocabulary was western-only, the weather rasters
stopped at the 101st meridian, and the draw registry assumed a state whose
agency publishes draw statistics. The full internal runbook, including the
sweep of places a new state can go silently missing, is
docs/state-expansion.md in the repo.
The source YAML
A real one, sources/us/padus-co.yaml:
id: padus-co
name: "PAD-US 4.1 — Colorado (Fee)"
description: >
USGS Protected Areas Database of the U.S., v4.1, clipped to Colorado.
Fee layer = fee-simple ownership; the land-status base for hunters.
layer: public_lands
attribution: "USGS Gap Analysis Project, PAD-US 4.1"
license: public-domain
redistributable: true
cadence: annual
download:
url: "https://www.sciencebase.gov/catalog/file/get/6759abcfd34edfeb8710a004?name=PADUS4_1_State_CO_GDB_KMZ.zip"
archive: zip
dataset: "**/*.gdb"
normalize:
sql: |
SELECT
Unit_Nm AS unit_name,
Mang_Name AS manager,
Mang_Type AS manager_type,
Own_Name AS owner,
Own_Type AS owner_type,
Pub_Access AS access,
GAP_Sts AS gap_status
FROM PADUS4_1Fee_State_COThe pieces:
| Field | What it declares |
|---|---|
layer | The common schema this source maps into: public_lands, parcels, hunt_units, access_programs, trails, motorized, … |
license / redistributable | Recorded per source, enforced at publish — see licensing rules. |
cadence | How often the upstream refreshes, so re-runs are scheduled honestly. |
download | URL plus archive handling; ArcGIS feature services page through automatically. |
normalize.sql | The field mapping from the source's schema to the layer's common schema — this is where most per-source work lives. |
tile | Zoom range and tippecanoe flags. |
The registry row
The web app's layer registry (apps/web/src/map/engine.ts) declares which
datasets exist and how they group per state. A new state adds its metadata
(label and the unit term its hunters use — GMU, elk area, zone) and one row
per dataset:
{ id: 'padus-mt', kind: 'ownership', sourceLayer: 'public_lands' },Array order is draw order; there is no per-state rendering code.
What a full state looks like
The complete layer set for one state, using Colorado as the template:
padus-<st>— public lands (PAD-US state extract)<st>-parcels— parcels (statewide program, or per-county sources where no open statewide fabric exists)- a hunt-unit source from the state wildlife agency
- a walk-in access source, if the state publishes spatial data for it
osm-roads-<st>— roads (feeds landlocked)- trails (state inventory if one exists, OSM otherwise)
- MVUM roads + trails (national USFS service clipped to the state bbox)
- slope, aspect, and landlocked — derived, not downloaded
When sources fight back
Real lessons from the registry, all documented in the YAML they belong to:
- Restricted licenses — California's only statewide parcel fabric is a
licensed composite; it's ingested with
redistributable: falsefor local dev and excluded from published tiles, while county sources that publish owners openly (Mendocino, Humboldt) carry the layer. - Ancient TLS — one county's legacy server only offers cipher suites
modern clients refuse; the YAML documents a
curlpre-fetch into the pipeline's cache layout as the workaround. - No spatial data at all — California's SHARE walk-in program exists only as text in a license-draw UI. Nothing to ingest; the docs say so rather than fake it.