wasserkarte

CLAUDE.md

Guidance for Claude Code (and humans) working in this repository.

What this is

A curated dataset of 523 German waters (rivers, lakes, canals, coastal waters, 3 seas) organised as a hydrological family tree — every water points to the water it drains into — plus a static site that shows that tree next to a map, and an A0 print poster.

Commands

make check        # validate data/waters — run after every data edit
make fix          # rewrite data/waters canonically (moves records to the right file, key order)
make site         # dist/index.html, dist/gewaesser.json, build/poster.html
make geometry     # recompute drawn courses (stdlib only) — run after changing coordinates,
                  #   parents, canal routes or manual courses; commit data/generated/geometry.json
make hydro        # data/generated/hydro.json from HydroRIVERS (needs pyshp; ~68 MB download on first run)
make smoke        # headless-browser test of dist/index.html (needs `npm ci`)
make poster       # dist/gewaesserstammbaum-a0.pdf (downloads fonts on first run)
make screenshots  # docs/img/*.png
make serve        # http://localhost:8000
make geo          # FULL rebuild (base trace hydro geometry): needs `pip install -r requirements-geo.txt`

Tier 1 (check fix site csv geometry) needs only the Python ≥ 3.10 standard library (output is identical on 3.10–3.13). Tier 2 (smoke poster screenshots) needs Node ≥ 18 and npm ci && npx playwright install chromium. Tier 3 (sources base trace hydro geo) needs the heavy geo stack and network access to raw.githubusercontent.com and data.hydrosheds.org.

Layout

data/waters/*.json       CANONICAL records, one per line, grouped by river system (hand-edited)
data/geometry/*.json     hand-maintained geometry inputs: canal routes, manual courses, via points, config
data/generated/*.json    pipeline outputs, COMMITTED so tiers 1–2 work without the geo stack
schema/waters.schema.json
scripts/                 pipeline (see docs/PIPELINE.md); common.py holds paths + helpers
web/*.template.html      page and poster templates: __DATA__ and  are filled by build_site.py
docs/                    DATA_MODEL.md, PIPELINE.md, img/
raw/ build/ dist/        git-ignored

Which file a record lives in is derived from its ancestry (common.file_for): the order-1 system (rhein, elbe, donau, weser, ems, oder, maas) or nordsee_weitere / ostsee_weitere. Don’t place records by hand — add them anywhere and run make fix.

Data conventions (enforced by scripts/validate.py)

How the map geometry is decided

scripts/build_geometry.py, first match wins, recorded as geometry.json["src"]:

  1. kanal — data/geometry/canal_routes.json (documented waypoints, drawn as straight segments)
  2. hydro — data/generated/hydro.json, courses matched in the HydroRIVERS network (HydroSHEDS, 15 arc-second) by trace_hydrosheds.py: a downstream walk from the documented source, cut at the documented mouth (Elbe gets its estuary tail from manual_courses.json)
  3. gshhs — data/generated/traced.json, fallback for rivers HydroRIVERS cannot match: courses matched in the GSHHG/WDBII network by trace_rivers.py (Rhein gets its Alpenrhein head from manual_courses.json)
  4. ne — Natural Earth line (ne_rivers.json via config.json:ne_aliases) and/or a manual course
  5. schema — source → own tributaries’ mouths → mouth; 2-point courses become an S-curve scaled by sinuosity. Drawn lighter/thinner on purpose — the map must not pretend to be more accurate than it is.

Then mouths are snapped onto the parent’s drawn course and everything is clipped to the drawing box. make geometry is deterministic; CI fails if the committed geometry.json is stale.

To fix a wrong course: for a hydro course first check the documented source and mouth coordinates against de.wikipedia — the walk starts at the source, so a wrong coordinate picks the wrong reach; build/hydro_report.json explains every match and rejection (then make hydro geometry). For a gshhs course prefer adding forced waypoints to data/geometry/via_points.json and re-running make trace (tier 3); otherwise add a hand-drawn chain to manual_courses.json (used only when the river is not traced). Canals: edit canal_routes.json, keep the drawn length within ~75–125 % of length_km (the validator warns otherwise).

Verifying changes

Gotchas

Known issues / backlog