Find the shadiest walking route across Valencia — including which side of the street to walk on.
In a Valencian July the sunny pavement and the shaded one are different weather. This works out which is which, for any date and time, and routes you along the shade.
Building shadows are computed from real footprints and heights, and the router searches a graph where every street has a left and a right pavement as separate places you can be. Crossing the road costs you, so it only happens when the shade is worth it.
Edge cost is:
(length + crossing_penalty) × (1 + α × sun_exposure)
where α is the shade-preference slider. At α = 0 you get the plain shortest path; at α = 1 a sunny metre costs the same as two shaded ones. It runs A* twice — once at α = 0, once at your α — so you can see the trade-off.
Because every edge costs at least its own length, straight-line distance to the target never overestimates the remaining cost, so A* returns the exact optimum, not an approximation.
Nothing is computed on a server. There is no server.
Build (occasional) Browser (every query)
────────────────── ─────────────────────
Catastro buildingpart.gml ─┐
├─→ 5.5 MB ──→ load once, decode
OSM extract ─ osmium ──────┘ artifact ↓
shadows for the corridor
↓
A* ×2, lazy sun sampling
↓
draw
The whole city — 277,651 sidewalk nodes, 436,804 edges and 196,676 building parts — is baked offline into one 5.5 MB gzipped file. The browser fetches it once and does everything else locally: no API keys, no routing service, no per-request cost. Hosting is a static file on a CDN.
An earlier version fetched OpenStreetMap live via Overpass on every query and built the graph in the browser. It was slow and it failed outright much of the time. Moving that offline fixed three things at once:
| Live Overpass | Precomputed | |
|---|---|---|
| Graph connectivity | 1,303 components, largest 43% | largest 93.4% |
| Building heights | 56% a hardcoded 8 m guess | 99.8% real floor counts |
| Network calls per query | 1 (often failing) | 0 |
The connectivity number is the interesting one. A sidewalk graph shatters because left/right pavement chains get offset away from the centreline they share a junction with — so the router would snap your start point onto an isolated two-node stub and correctly report "no route". Offline there's time to detect that and weld components within 12 m of each other.
brew install osmium-tool
cd build && npm install && makeDownloads ~170 MB of source data and produces data/valencia.json.gz. A couple of minutes; rerun quarterly.
On macOS the Makefile points
curlat Homebrew's CA bundle — the system one lacks the Spanish FNMT root that the Cadastre's certificate chains to.
python3 -m http.server 8000Then open http://localhost:8000 — the app expects data/valencia.json.gz to exist.
| Source | Licence | |
|---|---|---|
| Building footprints and heights | Spanish Cadastre (INSPIRE buildingpart) |
Free reuse, attribution to Dirección General del Catastro |
| Walkable street network | OpenStreetMap via Geofabrik | ODbL |
| Sun position | SunCalc 1.9.0 | BSD-2-Clause |
| Map tiles | OpenStreetMap | Tile usage policy |
Use buildingpart, not building — in the building layer numberOfFloorsAboveGround is nil, and the spec is explicit that the figure only exists on BuildingPart. Parts are what you want anyway: a tower on a retail podium is two prisms with different heights, which a single footprint cannot express.
Why the Cadastre rather than OSM heights? Measured across central Valencia, 8 of 5,978 OSM buildings carried an explicit height tag and 44% had building:levels — leaving 56% of the city casting a shadow computed from a guess. The Cadastre has floor counts for 99.8% of 214,368 parts.
- Shadows are flat convex hulls, not a 3D raytrace: no roof shapes, no terrain, no shadow interaction.
- Height is floors × 3 m. The Cadastre publishes no true above-ground height in metres, so this is better coverage, not better precision.
- No tree canopy — a significant shade source in Valencia.
- One sun position for the whole view (fine at city scale).
- Pavement offsets are synthesised from road width, not surveyed sidewalk geometry.
- Valencia only. Anywhere outside the precomputed bounding box has no data.
Code is MIT. The data it builds from is not mine to relicense — see the table above.
