Skip to content
Mapping

Camera & movement

Four verbs, and which one fires is a statement about what changed. Every number on this page is measured from the shipping map (MapCanvas.client.vue) — change the map, change this page.

The four verbs

FlyA NEW SUBJECT in the same world — a search pick, a lot click.flyTo, zoom 18, flat, north-up, 1200 ms. The arc says "we went somewhere".
EaseThe SAME subject reframed — chrome moved, a panel opened, a mode reset.easeTo: 260 ms for padding changes, 600 ms for pitch/bearing resets and zoom floors.
FitAn AREA — a suburb, a city, a parcel's true bounds.Suburb 1400 ms · city 1600 ms capped at zoom 13 · parcel via cameraForBounds between 13.6 and 18, 900 ms.
JumpThe WORLD changed — switching council, the initial centre resolving.jumpTo, zoom 14.2, no animation. A flight across half a state is noise, not orientation.

Durations

A ladder, not a constant: the further the camera goes, the longer it takes — and nothing is instant except a world switch.

  • 260 ms — chrome reflow: the bottom sheet settling, a panel changing the padding.
  • 600–700 ms — mode resets: back to flat/north-up, lifting to a zoom floor.
  • 900–1200 ms — subject changes: framing a parcel, flying to a lot.
  • 1400–1600 ms — area fits: a suburb, a city, an LGA.

The rules

  • Every programmatic move lands flat and north-up (pitch 0, bearing 0). 2D is the working view; 3D is entered deliberately. The one exception: while a 3D envelope is up, the reframe owns tilt — forcing pitch 0 first paints a one-frame bounce.
  • One ease per gesture chain. MapLibre's easeTo stops the current animation, so uncoordinated calls truncate flights. A camera-target signal (cleared on moveend) coalesces a drawer settling and a report landing into ONE padded ease.
  • Skip the correcting fit when the interim frame already landed — under 0.25 zoom and 24 px apart, a second ease is a shimmer, not a correction.
  • No essential flag, ever. Under prefers-reduced-motion MapLibre collapses the flight to a jump — the map obeys the OS, and that is the wanted behaviour, not a loss.
  • A zoom promise is a floor, not a jump: picking a development type at city zoom lifts the camera just enough for the fabric to exist (zoomToAtLeast) — if the user can already see lots, their camera is left exactly where it was.
  • Fit padding is the chrome's geometry. Desktop parcel fits pad for the search stack (~400 px left) and the report panel (~436 px right), scaled down when padding approaches the viewport — cameraForBounds returns undefined past it. Phones pad symmetrically (24–28 px): the bottom sheet's height already rides in transform padding, and MapLibre ADDS transform padding to fit padding — pass it twice and the lot is shoved off-screen.

Navigate

Esc