Pass 4 collects relation jobs, bbox-scans them against the RAM stores,
sorts by NL-spiral distance and publishes store/spool-frontier.txt (key
of the first unfinished relation; spool flushed before every publish).
pbf-base slices a LIVE store behind that gate (--bbox only, torn-tail-
tolerant block reads, pid-scoped sort chunks so concurrent slices never
clobber shared edge blocks), and mapfleet claims block per cell on the
frontier instead of waiting for the whole spool.
Pass-granular resume: passes 2/3 stamp exact spool block lengths +
counters + stats; a restart rolls the spool back to the newest stamp
and reruns only the remaining passes (unit tests + crash drill).
Weave fixes from the Luxembourg end-to-end smoke run: bake outputs land
via temp+rename so the ledger name never exists half-written, and
transmux verification now checks the union of ALL sources with first-
source-wins ownership (it compared source 0 alone and failed every
multi-source weave).
Also: pass-4 worker clamp 12→14, dead paged NodeStore/WayStore and
emit_lines/emit_polygons deleted (flat stores/prepare_* replaced them),
mapfleet --pbf + startup chunk sweep + end-of-spiral drain and final
weave, world-build.sh refreshes the -run binary copies.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
prepare_polygons clipped the FULL ring (and holes) against every tile in
the bbox: a continent-scale boundary relation (millions of points x
millions of tiles) pinned one core for hours at the planet spool's tail.
Halves clip once per split and recurse (geojson-vt scheme); per-tile
output is geometrically identical (equivalence test: same tiles, equal
areas, identical interior vertices — direct's zero-area boundary spikes
are collapsed, which is strictly cleaner).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
libs/mbtile_reader gains the .mkmap consumer: root.mkidx parse (Hilbert
tile ids, root ranges -> brotli leaf directories -> shard/offset/len),
positioned shard reads, same get_metadata/get_tile_decoded surface as
MbtilesReader; TileArchiveReader sniffs the path so mbtiles_path can
point at either. Index format v2 drops JSON: the metadata section is now
varint KV like the leaves (writer + reader; no serde in the container).
Loader, zoom-range probe and the headless harness go through the enum;
bridge-dz/overlay sidecars stay mbtiles. Harness parity via shards:
worst AMS rz16 164.7ms, z12 native 51.3ms — identical to mbtiles. App
repointed to local/maps/europe-base-br.mkmap (111 shards + root.mkidx,
the exact bytes a CDN would serve).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
In-app at z15 every tile ran the 460ms runtime cascade (buckets were
14+16 only); NL smoke: worst rz15 key 600 -> 53ms. Europe final cut
rerunning with 14,15,16.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Overnight run 2026-08-01: 9,380,390 tiles z2-14 in 3.2h, faces bake 1h
(+8GB, worker-side brotli q10), transmux to 99 shards all <510MB.
App repointed to europe-base-br-faces.mbtiles. nl-bridge-dz verified
byte-identical against the new base (deterministic feature indices).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- The boolean union cascade (59-77% of heavy tile builds) is now baked
per (tile, bucket 14/15/16) as additive field 101: cascade output made
deterministic (1/64 grid snap, canonical ring order, sorted tiers) and
bit-reproducible; renderer consumes guarded by structure signature +
coordinate checksum with runtime fallback; MAKEPAD_NO_BAKED_FACES=1.
Roundtrip bit-identical on all keys x buckets x dz configs. New
tools/map_bake producer (worker-pool incl. worker-side brotli).
- z14 streets merging never ran (early-out at DETAIL_ZOOM): fixed —
1957->1285 ways (-34%), payload -20MB, cascade input shrunk at source.
- Slow-tile log now prints per-stage ms + a ready-to-paste headless repro
command; harness honors archive/detail/dz/overlay/rz/3D envs.
- Worst AMS tile: 2-3s cold -> 175ms rz16 (61ms native); NL bake data
882MB at 60ms threshold; Europe needs threshold 150ms + 2 buckets to
fit shard budget (+2-4GB est).
- App -> nl-base-br3-faces archive; bridge-dz rebake required (joins
fail closed against br3 feature indices).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- bridge-dz baked for the entire Netherlands (17026 tiles, 29MB):
AHN-refined over the 8 Amsterdam sheet pairs, solver-only elsewhere.
Baked as 4 north-south strips with 2-tile overlap — the full-bbox
global solve peaked past 60GB RSS — merged with the new mbtiles-merge
subcommand (later input wins on overlaps, block-major write order).
Route app bridge_dz path ams -> nl.
- audio_unit: the new VoiceInput (VoiceProcessingIO) kind takes the input
setup/handler paths (set_input_handler panicked and aborted the app);
VPIO capture forced mono on every platform.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The junction-plaza dz field ingested road ways at the shared 6-unit
(~56 m) reach, and DzField holds full dz until radius-1.5 — so a 1 m
bridge hump raised half of Weesperplein and sheared the square over
its grounded surroundings (worst at high zoom where 1 m is ~43 px of
lift). DzField segments now carry per-source radii: plaza RING sources
keep the wide reach (quay slabs need it across their interior), while
road ways lift the plaza only across their own deck width. Diagnosed
via bake probes + an SVG dump of the paint buffers and a lift-zero
shader bisect; the dz archives themselves are clean and tapered (the
morning stairfix is not implicated).
Shadow geometry hardening from live review: facing gate widened to
0.25 (near-parallel edges swept hair-thin spikes), sliver filter
scales with the AA fringe, and deck shadows clamp their projected
height (solver outliers turned one segment into a canal-spanning
slab) and skip implausible dz outright. Probe tests document the
Weesperplein window and the dz A/B across archives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Steps shed height within the staircase (0.6 grade) instead of ramping
30m into the street grid. Surface ways under a deck clear from ground
level instead of reading back their own inherited ramp lift, which
pumped decks up every constraint round. Adds Duivendrecht probe tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove the legacy flat-road fallback and A/B harness, keep patterned non-road strokes on their dedicated path, and make solid roads use the geometry/boolean mesh pipeline unconditionally. Reconcile bridge, link, and padded-tile elevation continuations generically in the tile baker and renderer.
The persistent artifacts were four distinct data bugs, found via the
dump_base_dz_at forensic test:
- Dual carriageways: two parallel ways whose ribbons merge in 2D but
solved to different heights -> a height step down the merged surface.
New solver pass: each way vertex adopts the max height of PARALLEL
ways within its own half-width (parallel_max sampler, own line
excluded); duals equalize, frontage streets are out of reach.
- Stacked grabs: a way split sitting under a parallel deck sampled the
deck overhead (no direction/distance gate can reject 2D-coincident
stacked ways). Isolated lifted runs under 25 m arc are zeroed —
measured in arc, not vertices, so short 2-vertex bridge ways survive
(zeroing those broke the Gooiseweg viaduct: fixed).
- The final coincident-vertex consensus TELEPORTED heights through
chance-coincident vertices of stacked ways; it now only reconciles
values already within 1 m (its actual job: unifying overlap copies).
- Post-consensus values had no ramps behind them (consensus ran after
blending): grade blend + hold re-runs after it, plus interior zero-run
interpolation (<120 m) for sampling holes; endpoint fallback keeps a
relaxed direction gate instead of none.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Junction consensus raised a merging way's endpoint to deck height but the
8%/m grade decay started immediately, dropping ~2 m across the visible
gore: every slip road attached below its deck with a ledge along the
merge. The grade blend now holds the junction height for the first 12 m
of the path before decaying, so merges are level through the gore and
descend after.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Split ways duplicate a carriageway with an OFFSET centerline through
gores — the twin failed the direction/median gates and baked a lower
fallback height: two overlapping deck slabs at slightly different
heights, swapping mid-deck (the persistent 'road break'). Rejected
all-zero line paths now resample the field ungated with a tight cap
(2.5u, median <= 2u, 60% hit rate) — a gore twin sits within a lane of
the accepted profile and inherits it; frontage streets stay rejected.
Also: seam_probe forensic test (casing-buffer vertex dump + cross-tile
band compare) that located this; memory watchdog removed at user
request (runaway fixed and verified earlier).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Annotation now runs ONCE over every base tile in global coordinates —
junction consensus and a final exact consensus over coincident vertices
(largest |dz|) unify the overlap clip copies adjacent tiles both render.
DzField terminal cap extension skips endpoints on the tile clip bounds:
holding a cut height flat while the neighbor tile interpolates the ramp
mismatched the overlap band. Reduces (not yet eliminates) the doubled
slab at tile seams on ramping decks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Per-tile solves (even with 1-ring context) reached slightly different
heights for the same way on each side of a z14 seam; both tiles then
rendered their clipped copy of the deck in the overlap band at different
heights — visible steps and doubled slabs mid-deck. solve_tile is now
solve_bbox: one graph over every decoded tile (integer-grid node dedup
chains fragments across seams), one AHN pass, one constraint solve, one
global field pair; bridge_dz features bin per source tile and the
annotator samples the global field with per-tile offsets. Bonus: the
Amsterdam bake drops from ~2 min to 21 s (graph built once, not 193x).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- One continuous surface face per group ((surface − grounded cover) ∪
lifted): no more overlapping level twins micro-diverging at grazing
tilt (the lens endcaps). Tunnels stay a separate early-painted face.
- Tier-transition joints (bridge/approach style splits from the layer
rank bias) become FLUSH butt joints — but only at collinear
continuations; forks and T-junctions keep round caps. No cap discs, no
wall quads across a joint (suppressed within half_width of the joint).
- Walls/fascia unconditional again (~1.4 m band, clamped at ground): the
field-probe seam filters false-positived on every low deck through the
field's edge fade and stripped the thickness the whole look lives on.
- Baker: cross-tile boundary consensus on base_dz — every tile solves
with 1-ring context, so the same way baked slightly different heights
across a tile seam (visible mid-deck steps at z14 edges); boundary
vertices now unify to the largest-|dz| across tiles (153 paths).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Baker: tunnel sink solve (downward mirror of the lift solve): 5.5 m
clearance at every 2D crossing with a surface way, 30 m hold, grade
ramps, portals pinned to the surface at shared nodes. Tunnel ways get
their own SolvedField (never mixed with the surface field) and the
annotator runs a negative sampling pass for paths with no deck lift;
base_dz now carries signed dm values (195 tiles, +2 tunnel-only).
- Renderer: third level in the cascade — sunk parts with their own cover,
painting before ALL surface content; sunk faces displace down through
the existing signed-lift shader path. Tunnels with baked negative dz
join the union as solid sunk roads in 3D bakes (tunnel tag stripped for
styling); flat bakes keep carto dashes. Tunnel ways stay out of the
stroke/arrow corridors so surface streets above a tunnel line cannot
inherit the sink.
- Deck walls become fascia bands (~1.4 m below the deck edge, clamped at
ground): underpasses are OPEN — you can see through them.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Two-cover cascade: grounded content subtracts grounded cover, lifted
subtracts lifted — a deck cuts its own casing (no more cap outlines
bleeding through on bridges) but never the road running underneath;
ramp feet still cut streets. Group parts dissolve to clean outlines
(simplify_shape) before any cross-group op.
- Depth ladder by slot (per face, per stroke rank) instead of per event:
coarser, safer separation between coplanar overlaps.
- DzField sampling gated by active-area bbox per face; corridor bbox
prefilter for interleaved strokes.
- Byte-budget tile cache eviction (1.2 GB) + pending-upload queue cap
(384 MB): 3D building bakes run 30-70 MB of fill buffer per tile and a
count-capped cache alone reached tens of GB.
- MP_TILE_PROFILE stage clock + headless union_perf_probe test with the
live theme mirrored (probe_compiled_theme): rz17 tile build 1.4s -> 0.9-1.0s.
- Revert baker lateral clearance: the constraint cascaded through solver
rounds and lifted the whole network; needs a bounded formulation.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Union faces and legacy strokes merge into one rank-ordered paint sequence
(plazas, casings, centers) — cycle lanes and park paths draw above the
surfaces they ride, higher tiers still cover both; flat = buffer order,
tilt = same order via the param5 ladder.
- Joint coverage: bevel wedges at gentle bends, discs at corners/ends;
union ways get the same chaikin smoothing as legacy strokes (dz-aware).
- Per-tier DzField (nearest-way-wins, grounded ways at 0) + crack-free
midpoint face subdivision replace the narrow runtime corridors: decks
lift edge-to-edge, casings stay attached, no tents or shards.
- Lifted rings no longer subtract from lower groups: roads continue
underneath decks (paint order hides them flat, real depth when tilted).
- Lift-aware tilt depth: deck depth margin scales with lift so water and
ground at the display position can't depth-win over a bridge.
- Baker: tapered lateral clearance for elevated ways running beside
lower-layer roads (ribbon widths overlap without centerline crossings);
connected ways exempt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bridge elevation (bridge.md M1+M2): tools/map_tiles bridge-bake solves
per-vertex road/rail dz over the OSM graph (crossing clearance, grade
ramps, deck holds, junction consensus) with AHN DSM-DTM measured deck
profiles (BigTIFF reader in geodata, WGS84->RD), baked as bridge_dz +
per-base-tile base_dz (L/F/P join to exact renderer geometry). Renderer
joins dz through parse into TileWay.dz; strokes/arrows/fills lift off
their own profiles; tunnels never deck.
Road overlay unifier: painter's algorithm as geometry — per-way segment
rects + vertex discs, i_overlay top-down subtraction cascade into
DISJOINT faces (overlay_paint_groups), triangulated once; flat render is
pixel-equal to paint order (proven 0-diff on the abstract unit case) and
tilt cannot reorder it. Legacy strokes interleave by rank; plazas join
the cascade at true alpha. @roads 0/1 A/B toggle, @abtest headless
CPU-raster diff harness (1.50% vs 2D reference on the Raampoort tile),
@cam debug camera, bridge_eval.sh aerial-vs-render loop.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- rain radar layer: pure-Rust KNMI HDF5 reader (superblock v0 walk,
single-chunk deflate datasets, byte-exact vs h5py), ellipsoidal polar
stereographic reprojection (20 m vs product corners), bilinear value
sampling -> smooth banded isolines, textured quad overlay through the
overlay camera, 25-frame nowcast animation; RadarSync polls at most
once per 4 min through a disk-persisted gate and caches frames on disk
- makepad-geodata + makepad-tesla crates join the workspace (overlay
builders, radar sync, NL open-data layers; transit routes now z7-14)
- Europe major-roads routing graph: nav-build --major-roads does a
ways-first scan (5.7M ways / 46M nodes / 194 s / 971 MB) and the app
falls back to it when a route leaves the regional graph — Amsterdam to
Paris routes offline (501.8 km)
- 3D flying markers: chargers/POIs/stops ride thin stalks with DYNAMIC
height (each pin clears its own building +8 m); labels, kW text,
brand and tap zones all consume the baked per-marker lift; stalks and
buildings grow together on the 2D->3D transition (per-tile flat->3D
fade heights, no replay on zoom regens)
- markers depth-honest (small bias, buildings occlude them); phong-lit
canopy/light spheres matching the buildings' NW sun; buildings tint by
BAG age in 3D; district area tints (rank 60, alpha .32); transit line
labels + stop names; follow-mode is an explicit attach/detach toggle;
rotation release schedules the label re-place (no stuck upside-down
labels after a fast spin)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Tesla-style droplet pins anchored at the tail tip (rotate around the
exact site point in tilted views); red exclusively Tesla, amber DC,
blue AC; Tesla pins show stall count, others peak kW
- in-pin text through the normal text renderer: billboard-anchored
glyphs (anchor scales with the map, glyph size constant), exempt from
label collision/repeat culling, no halo
- upright camera-delta labels: straightened labels (place names, POIs,
brands, pin text) translate with the rotation gesture but stay
horizontal — no more rotate-then-snap on regen
- per-icon zoom floors baked in vertex param4 + live icon_zoom uniform:
stale deeper-bucket tiles never flash markers on zoom-out (param4 is
lift-height only for non-icon shapes — icons stay on the ground)
- motorway exit labels (street_labels_points): carto-red name + ref
- 2D/3D mode: tilt gesture syncs app state (TiltChanged action), tilt
release near-flat settles to exact 0, mode flip re-bakes tiles
(extrusions appear/disappear without a zoom nudge)
- Simple 3D Buildings: building:part volumes with min_height bases;
outlines containing parts flatten to footprints; famous buildings
with tourism=attraction extrude instead of dying as attraction fills
- little 3D trees in tilt mode: crossed trunk quads + sphere-slice
ball canopy (architecture-model proportions)
- searchdb/mbtiles support work: reach-based distance ranking, direct
tile lookup + writer ordering
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Relations reference ways randomly across the extract; the 128-group
WayStore LRU crawled Europe's pass 4 at ~260 relations/s (5+ hours).
Now: FlatWayStore decodes the whole relation-member way store into RAM
next to FlatNodeStore, assembler workers resolve and prepare features
(new prepare_point completes the set), a single writer owns the spool,
and the ordered consumer only parses members/tags. NH pass 4 3.9s ->
1.3s, per-layer feature counts identical.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Projected grid values are <= 2^26 at zoom 14, so i32 is exact; decode
hard-errors on out-of-range rather than ever truncating (no swimming
roads). NH output identical feature counts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Europe's ways arrive in creation order, i.e. spatially random: any node
cache that fits in a fraction of the store loses. The store is only
13.8GB compressed, so FlatNodeStore decodes ALL of it once (parallel,
~a minute for Europe) and resolver workers share it lock-free via Arc —
no cache, no eviction, no zlib on the hot path. NH pass 3: 5.6s -> 3.5s;
feature counts unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>