Three distinct micro-artifacts all read as 'shadow spikes' in review;
each needed its own cure, pinned down by a material-null shader bisect
and pixel-level crops:
- sub-meter slits between abutting building sections collected shadow
as dark vertical hairs -> subtracted footprints dilate 0.5 m,
- quay humps (solved dz peaking at exactly 1.0 m) hung 1 px fascia
bands at their stub ends -> fascias only for decks above 1.0 m,
- the boolean weld left hair-thin shadow tendrils ATTACHED to the main
body in narrow passages, untouchable by per-ring filters -> a
morphological opening (0.5 m erode + dilate via OutlineOffset) on
the final shapes removes anything under ~1 m wide wherever it hides
and softens shadow corners as a bonus.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The spike fixes had over-corrected: dropping the translated-footprint
ring from the shadow union left the far side stitched only from edge
quads, and the 14-degree facing gate then erased the contribution of
grid-aligned walls (most of Amsterdam runs nearly parallel to the NW
sun) — shadows collapsed into sheared wedges and spikes. The union is
back to the full hull (footprint + translated footprint + connecting
quads, degenerate-only gate): thin near-parallel quads are interior to
the hull and cannot surface as spikes, while the winding normalization,
bevel fringe and aa-scaled sliver filter keep handling boolean dust.
Forest crown lattice: extend the shader-side zoom clamp to the
uniform's full range — freezing at 0.25 let the pattern swim against
the map past z18.
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>
Per-edge quad soup left hairline slivers welded to the shadow union
wherever a footprint edge ran near-parallel to the sun (needle pins at
building corners). Each ring now sweeps only its contiguous runs of
shadow-facing edges — one clean polygon per silhouette chain plus the
footprint, nothing degenerate to weld on.
Dark/Circuit themes stop baking sun-cast shadows (no sun at night);
baked AO keeps buildings grounded, and Circuit City's glow does the
depth work.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The unbounded screen-position nudge let whole roof fields align with
the sun on wide viewports and bloom out white; sheen now also fades out
toward regional zooms — it is a close-range material.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Circuit City (shiny.md showcase) ships as a built-in third theme slot on
MapView (style_circuit, theme_select 0/1/2, set_theme with the
keep-stale restyle so switching cross-fades per tile as rebakes land):
near-black ground, charcoal volumes with gloss 1.1 sheen, dark
reflective water, and every road an emissive amber filament weighted by
class. Emissive plumbing: MapRoadRule.emissive -> StrokePassStyle ->
PaintGroup/PaintFace -> road-union center faces carry MAT_ROUTE_GLOW +
strength in param1, and the shader pushes the line color white-hot
behind the route_glow gate. Gloss is now a theme value (ShinyConfig).
Street-tree canopy/trunk colors become theme-driven (tree_canopy /
tree_trunk fill rules) so dark themes get night trees. The example's
Layers panel grows Night/Circuit City rows behaving as radios.
Shadow geometry hardening from live review: silhouette simplification
floored at 0.35 units, and a needle filter drops hair-thin boolean
slivers (area/perimeter < 0.05) that read as dark pins at building
corners.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Difference output can wind hole rings like outers; un-normalized they
inverted the shadow fill into self-overlapping wedges (sharp corner
lines + striping). All boolean shadow output now goes through one
emit_shadow_shapes helper that clips, winding-normalizes and
tessellates.
Elevated road segments cast shadows: per-segment slab quads projected
by their per-vertex deck height (grounded stretches skip), dissolved,
minus building footprints, drawn as the same material-6 decals — the
overpass grounds itself like a building does.
Textured materials now fade back to plain 2D carto as the camera goes
top-down (cos(tilt) drives the blend in-shader, so dragging flat IS the
animation): flat water, flat green, Gouraud canopies, classic ring
trees. Shrub blobs anchor map-physically across the zoom range via a
wide-clamp zoom uniform and blend into the legacy rings at far zoom,
lattice-matched so they replace the circles at the same size/place.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A wall pixel N px up its quad carries the depth of ground N px behind
it, so the 0.40 shadow decal cut a dark band across building bases
whenever the camera rotation put the shadow behind the building on
screen. Walls, roofs, parapets and balls now sit at 0.50 — above every
ground decal, below lifted deck bumps — plus two more close-zoom FBM
octaves for water, deeper zoom anchoring (clamp 0.03), and grass
rebuilt as sharp blade speckle with traveling gust bands instead of a
domain-warped wavy surface.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shadow fixes from live review: subtract every grounded building
footprint from the per-tile shadow union (overhead the roof lift-depth
vanishes and a decal under a neighbor building blotched its roof/walls);
tree/stoplight contact discs get per-disc depth steps above the union
and are skipped entirely for trees already inside a building shadow
(stacked decals double-darkened and z-fought). Stoplights now cast
discs too. Fill micro-depth ladder rekeyed to paint-order position
(order_pos % 19) — the old feature_count % 16 tied every 16 features
and shimmered green-vs-gray in tilt mode.
Water rebuilt as a fractal slope FBM: value noise with analytic
derivatives over four rotated octaves, each shimmering in place on its
own drift phase, chopped into crests and lit with a Blinn-Phong sun
glint + fresnel sky term. Camera is part of the material — cos(tilt)
and a physical zoom factor (exp2(16 - view_zoom), clamped) gate the
drama so top-down/far views keep the flat 2D color, and high octaves
fade before going sub-pixel. Flow-vector advection was tried and
removed: interpolated per-vertex directions painted seams across big
polygons; the water now shimmers in place.
Green areas: wavy grass (aniso blade noise swaying on a traveling wave,
daisy speckles at close zoom); woods/cemetery pattern fills grow shaded
canopy blobs behind the foliage gate. A 20 Hz heartbeat animates water
and grass while they are visible; everything anchors map-physically via
the same zoom uniform.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Screenshot review at Rozengracht/Vondelpark/IJ passed: baked AO and
shadow geometry cost the GPU nothing, water/foliage are a few ALU on
minority pixels, and every toggle A/B-verified back to the classic
frame. Specular sheen defaults on only in the dark theme (it carries
the dark look); route glow stays opt-in.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two wide additive halo passes under the route casing/fill: premultiplied
rgb energy with alpha 0 makes the framebuffer blend pure additive, so
roads under the route brighten instead of being covered — the glow trick
without float targets or a bloom pass. Traveled-portion dimming scales
halo rgb (the alpha multiply is a no-op for additive). Behind the
route_glow theme toggle, stamped per frame.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shadows are polygons, not passes: each building's roof ring is projected
along the sun's ground direction by height * shadow_len, and footprint +
projection + silhouette quads dissolve into ONE per-tile union (i_overlay
chunked, the road-union lesson) so overlaps never double-darken. Emitted
as material-6 ground fills in the ICON pass — in a city almost all
ground is road surface, and anything earlier gets painted over by the
street passes — with micro-depth 0.40, above the whole grounded road
ladder but below lifted deck bumps. The decal bakes full-dark and the
shader scales it by the live shadow_alpha uniform, so time-of-day fades
don't need a rebake. LOD gates: 3D mode, z>=14, and skip shadows under
2 px at bake magnification. Trees get soft contact-shadow discs.
Terrain: horizon-march cast shadows in the hillshade worker (17-step
exponential stride, ~15 ms per 512px region), skipped automatically
when regional relief is under 150 m. Hillshade + march light from the
one SceneSun via a new per-request sun/flag channel to the worker.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One global light (draw/src/scene_sun.rs): SceneSun POD shared by the
tile bake, ball lighting and terrain hillshade, replacing three
hardcoded sun rigs. ShinyConfig carries every shiny.md toggle; it rides
CompiledMapTheme so bake-flag flips reuse the style-epoch restyle and
stale tiles stay drawable (MapView::update_shiny).
T1: shape-0 geometry now carries its surface normal in param1/2 and a
material id in param3 (walls/roofs/water/canopy/green) — channels were
free, no vertex-format growth. DrawMapVector dispatches per-material
pixel effects behind uniform gates that default off (legacy frame when
off): T4 water noise sheen + sun glint, T4b building specular sheen
with heading-rotation highlight sweep, T5 canopy clump noise + rim and
green-area patchiness.
T2 (first slice): wall vertical AO gradient (ground-contact darkening)
and roof-edge parapet AO strips, baked at zero GPU cost behind bake_ao.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Inhouse i_overlay 7.0.3 and its i_float/i_shape/i_key_sort/i_tree deps
(used by the map road union mesh under the widgets 'maps' feature) as
workspace-excluded path crates, stripped of tests/locks/registry crud.
i_float's no_std libm dependency is removed by switching it to std
float math, so the maps feature no longer pulls any external crates.
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>
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>
- 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>
Every lifted level part emits wall quads along its boundary rings: top
vertex rides the deck dz field (v=0), bottom stays grounded (v=1), same
x/y — flat mode degenerates them to nothing, tilt reveals the wall.
Darkened face color, drawn one zbias step under the face at a quarter
ladder step below. Decks read as volumes, ramp-displacement crescents are
closed, and underpasses look like underpasses.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- AA fringe coverage now rides per-vertex premultiplied color (inner =
face color, outer = transparent) with full shader coverage: the ramp
interpolates across the whole skirt at any magnification, where the
fwidth-normalized shader ramp pinned to one device pixel and left
magnified tilt-foreground stairs visible. Skirt sits half a ladder step
above its face so the up-screen half wins its depth tie.
- Straddling (partially lifted) rings stay visible in both level parts
but no longer join the grounded cover: a ramp segment spanning the
threshold was cutting the road underneath along its whole length —
the under-the-overpass hole at the benchmark interchange.
- /tmp/mp_start_cam boots the app at a saved viewport; the map draws its
own '@cam lon lat zoom rot tilt' readout bottom-right so any screenshot
is reproducible.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Opaque faces get boundary-straddling AA skirts (coverage 50% at the
edge, legacy convention); translucent faces ramp outward only and their
straddling rings pick one level part — premultiplied translucent color
must never paint over itself (double-blend darkened plaza boundaries).
- macos event loop: a foreign window class in the scroll-wheel path (the
screen-capture overlay's TUINSWindow) has no macos_window_ptr ivar —
skip instead of panicking. This was the random studio death whenever a
system screenshot overlay was active.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Runaway root cause, captured via self-sampling memory watchdog + boolean
input dumps: simplify_shape on 17-20k-ring soups (dense tiers at high
overzoom) spins in contour extraction for minutes while allocating
unboundedly (both i_overlay 4 and 7). Chunked dissolve (3000-ring chunks,
union of clean outlines) turns the captured hangs into 91/140 ms; the
full pan/tilt torture that blasted to 100 GB now holds 5-6 GB flat.
- i_overlay 4.5 -> 7.0.3 (API-compatible, booleans ~1.7x faster).
- Boolean input hygiene: 1/64-unit snap + degenerate ring drop.
- DzField: guard degenerate terminal-segment cap extension, clamp grid
walks (a NaN/huge coord can no longer explode cell insertion).
- AA fringe v1: miter skirts along boolean output rings, u 0.5->0 over
1px, emitted after each face at its ladder slot.
- Level-straddling rings join both grounded+lifted parts (transition
seams overlap instead of sharing an epsilon-fragile edge).
- Oneway arrows foreshorten with tilt (ground-plane glyphs).
- Debug: in-app memory watchdog (14 GB: sample own stacks -> abort),
MP_TILE_PROFILE via /tmp/mp_tile_profile, boolean repro test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Dense tiles carried 30-70 MB of fill buffer: thousands of park trees at
16x8 ball tessellation for ~14 px canopies, an AA fringe doubling roof
verts across every building (a lifted roof edge meets its own wall, not
the background), and sub-pixel footprint edges as wall quads. Screen-
adaptive canopy segments + aa=0 roofs + 1.2px wall edge collapse:
67.8 -> 26.0 MB worst measured tile. Also: DzField cap extension so
lifted way ends hold deck height through their round caps.
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>
Terrain gets real z in tilt mode: a displaced 288x216 surface mesh plus
per-vertex ground lift for all tile geometry (roads/fills/buildings/icons)
via vertex-stage sample_lod of a terrarium-packed elevation texture, with
labels riding the same ground through a lift-aware camera delta. Depth
domains rescale per frame to stay inside the -24 budget; road passes get
a relief-scaled clearance over the surface so cities keep correct
street-vs-building order. Regional zooms (<z14) drape landcover colors
into the hillshade (full-res MVT rasterization, treeline fade) instead of
lifting km-scale polygons that cannot follow relief.
Terrain build now covers EV-trip Europe (lat 43..58, lon -5..17, 8.8 GB
GLO-30 z6-12) with sign-safe Copernicus stems, transparent no-data, and
an Alpine rock/snow ramp. Terrain requests render 4096x3072 over ~3
viewports and only re-render on real movement.
Also: NOMADS GFS wind particle layer synced to the weather clock with 3D
altitude, rain cloud deck lift, stuck-tile fixes (expiring missing set,
decode-failure backoff, restyle placeholder purge), 78-degree tilt
ceiling, and park fill z-fight fix via widened micro-depth ranks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* PortalList: add `set_flow(cx, flow)` to switch a list between vertical and
horizontal layout flow at runtime. Much faster than using `script_apply_eval`,
and always fully correct because it updates the `vec_index` axis.
It also avoids a full ScriptReapply sequence, which is potentially expensive
across all of an app's widgets.
* AdaptiveView: add `active_variant()` getter so that widgets using AdaptiveView do not have to separately track which variant it should be in. Removes all ambiguity and possibility of divergence... finally!
* Also fixes long-standing TODO item in AdaptiveView about properly handling
weird window geom events, e.g., on macOS sometimes it spits out a 0-width
window update which is total b.s.
* DisplayContext: add `is_desktop_width()` helper.
* Window: ignore spurious zero-size window geom events.
- 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>
- transit routes draw as per-line colored strokes (stable ref-hash
palette) on white casings, labeled "Tram 7"/"Metro 52"; stops get
name labels (stations z13+, local z15+)
- districts layer: tiered admin boundaries (gemeente/wijk/buurt) and
centroid name labels staged by zoom, muted admin purple
- upside-down labels fixed structurally: post-placement invariant
re-places any glyph run that reads net-leftward (hairpin ramps fooled
every pre-placement chord heuristic); vertical dead band ±4°
- overlay charger pins hold collision priority over base charging_station
icons, which are suppressed while a charger overlay is active; pins
reserve their bubble box so POI text places beside them
- per-icon zoom floors: overlay pins use kW tier floors (8/10/12) —
micro floor 16.5 no longer hides them; 0.6 zoom grace; fail-open when
the icon_zoom uniform is unset; oneway arrows from z15
- rail z-fighting: stroke merge drops duplicate quantized segments from
forked ways (switches drew shared segments twice, shimmering in tilt)
- 3D mode: stoplights (pole + red/amber/green lights) and taller
ellipsoid trees; live_reload names its override files
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>
The snap: tilt does not commute with rotation. The placement maps world
points rotate-then-y-compress, so the true delta between the cached
camera (r0,t0) and now (r1,t1) is S(t1)*R(d)*S(1/t0) — a general 2x2
matrix, not the rotate+scale previously approximated. The shader takes
the full matrix; the pan shift pre-inverts through it so pans during
rotation land correctly. Between-frame tracking now converges on the
exact re-place result — no more rotate-snap in 2.5D.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- DrawRotatedText gains cam_cs/cam_sn/cam_tilt/cam_pivot uniforms: while
the camera rotates or tilts between re-places, ALL placed glyphs spin
and squash about the view pivot on the GPU — whole-quad transform, so
orientation follows position for free; the CPU per-frame rotated copy
is gone and the async re-place trues up with identity uniforms
- label plans carry a post-icon flag: in-pin digits' phase now also
hosts the charger brand text, which was drawn before the symbol pass
and hid BEHIND its own pin
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- every baked charger pin records its normalized position + known
attributes (name, operator, city, max_kw, evses, connectors) as a
PinHit in the tile; taps hit-test a billboard rect through the same
overlay camera markers use (rotation/tilt correct), emitting
MapViewAction::PinTapped ahead of the generic tap
- examples/map: bottom-left info card — operator title, "250 kW max",
bays/connectors, site name, city; hides on plain map tap. (The
search-engine enrichment of this card is deferred by request)
- zooming out from icon level no longer splatters the stale POI carpet:
a tile baked at z16+ hides its symbol pass below icon zoom while
low-bucket pins keep drawing
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Spinning in 2.5D detached labels from the map: the cached-plan reuse
was capped at 15 degrees and required equal tilt, so most rotation
frames drew stale untransformed placements until the next re-place.
Now ANY rotation/tilt delta (at equal zoom) redraws the cached glyphs
rigidly rotated about the pivot and y-compressed by the tilt ratio —
labels follow the camera best-effort and the async 120ms full re-place
trues them up, exactly the stale-tile philosophy of the dash shader.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rethink after the pin felt shaky: the kW text went through the label
placement machinery (map-space offsets, per-bucket relayout, rotation
rigid-redraw) while the badge was a zoom-constant billboard — parts
drifted, doubled and jumped. Now the whole pin is ONE composite in the
icon pass at a single anchor: tier-colored badge, white bolt with its
in-pin offset baked into the mesh, and the kW number as seven-segment
vector digit meshes composed at fixed screen-px offsets. Everything
billboards together; the label system is out of the loop (brand text
below the pin remains a normal label).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- POI/pin symbols get tilt depth 90 (was 0.04): a marker is UI-like and
must win against the ground plane and buildings under 3D — the pin
was slicing into the map surface. Oneway arrows stay ground-hugging
- during rotation gestures the cached-label rigid-rotate now exempts
pin-class glyph ranges: their billboard pins stay screen-aligned, so
spinning the kW text with the map read as doubled, garbled digits
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Ports the silero v5 16k branch to pure rust (minimal onnx-protobuf weight
extraction, hardcoded graph: stft-conv, 4x conv+relu, lstm cell, sigmoid
head), 512-sample chunks with 64-sample carried context. Validated against
onnxruntime to 2.3e-6 max diff (fixtures committed), ~425us/chunk release.
Model loads from repo-root silero_vad.onnx or MAKEPAD_VAD_MODEL. vad-test
bin for wav files. window_voice_input now gates packets on vad probability
(0.5 enter / 0.35 exit) and falls back to the rms gate when the model file
is missing — the log line says which gate is active.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The Tesla-pin refinement round:
- fast sites render the wide badge with the white bolt LEFT and the kW
number INSIDE the bubble (white pin-class text); street AC gets the
small badge; operator brand ("Tesla", "Fastned"…) reads under the
pin from z13, tier-colored
- overlay paths accept ?fast / ?slow charger-power filters and the
Layers panel splits EV chargers into fast and slow toggles
- draw order restructured: fills/casings/strokes → labels → icon pass →
pin-class text, so pins sit OVER street names while their own kW text
sits over the pins
- point labels for chargers/places/micro POIs straighten under
rotation/3D like addresses do — pins are billboards, their text now
matches
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The pass-3 gate hid ALL baked symbols below ICON_MIN_ZOOM — charger
pins were in the buffers from z9 but never drawn. Floor now tracks the
lowest icon class (z8.75). Stale high-bucket tiles may briefly splash
their POI carpet on deep zoom-out until the rebuild lands — acceptable
against pins missing entirely.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- charger sites render as 24px tier-colored pin badges (red/amber/blue)
with a white bolt centered in the body; sized-mesh support added so
one icon can break the 14px grid
- chargers take top icon-collision priority and their kW labels rank 8
(above street names) at font 1.0 — a site stays trackable from z9
road-trip zoom all the way in without popping out
- label extraction for chargers: >=50 kW label their power, Tesla
operators label "Supercharger {kW}"
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Tesla-GPS framing: charging power is first-class map data.
- icon zoom floors by max_kw: ultra-fast (>=150 kW) from z9, fast DC
(>=50) from z11, street AC posts z13 — the collision pass keeps
density sane
- icon color by tier: red ultra-fast, amber fast, blue AC
- labels from z13: "Supercharger 250 kW" for Tesla operators (red),
"{kw} kW" for other fast DC (amber); street AC stays unlabeled
- app layer toggles read app-tracked state (reading .active in the
changed() pass raced widget state — same class as the panel bug),
plus an overlays log line for future diagnosis
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Amsterdam vanished zoomed out: shortbread tags it kind=capital
(Haarlem state_capital) which fell into the everything-else z13.5+
bucket. Kinds normalize now (capital/state_capital -> city)
- population rides along in the label key: city text steps 1.2/1.4/1.65
at 150k/500k inhabitants so Amsterdam reads bigger than Purmerend,
and a log-population score tiebreak places big cities first
- global label pass no longer gated at z13 (committed logic; the gate
removal is what turned zoomed-out labels on at all)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The shortbread place_labels layer was never admitted, so zooming out
lost ALL labels (streets are the only other source and they fade with
length). Now: place points classify by kind and follow osm-carto's
placenames.mss gates (city z4-15.5 at 1.55x text, town z7+, village/
suburb z11.5+, quarter/hamlet/neighbourhood z13.5+), outranking every
other label source. Nature-reserve area labels also escape the z15
area-label gate — their tiles exist from z6 and the reserves are huge.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>