Skip to main content

Synchronous camera snapshots and legacy APIs

The current development SDK uses shared Rust camera math for viewState() and screenToLngLat(x,y), reading the most recently observed camera snapshot (frame, camera event or command acknowledgement). Mercator supports 0–65° pitch, bearing, asymmetric padding, explicit date-line world copies and CSS pixels. Geographic remains planar. These methods do not wait for newly submitted writes or certify resource readiness or completed animation.

map.jumpTo({center:[181,40],zoom:19,bearing:33,pitch:65,
  padding:{left:30,right:2,top:15,bottom:4}});
await map.flush({render:true}); // standalone browser SDK
const state=map.viewState();
const screen=await map.project([181.0002,40.0001]);
const location=map.screenToLngLat(screen.x,screen.y);
console.log(state.pitch,state.zoom,state.bounds,state.metersPerPixel,location);

viewState() returns independent center/bounds arrays, with actual projection, zoom, bearing, pitch and visible-ground bbox. metersPerPixel matches default scaleAt() at the viewport center in that snapshot: horizontal ground metres per CSS pixel, using the sphere-local approximation and radius 6371008.8 m. DPR does not change this logical unit. An invalid ground intersection gives NaN rather than a fabricated scale. Globe retains its existing spherical state and ray math, without substituting Mercator.

screenToLngLat returns [NaN,NaN] for sky rays or invalid pixel input. Standard asynchronous unproject retains explicit errors. Invalid camera context and missing matching capabilities still throw. Portable scripts should prefer MapLibre-shaped map.project/unproject/getPitch/getZoom/getBounds and map.sqs.getScaleAt, confirming a drawn frame with map.sqs.flush({render:true}) after writes. A synchronous snapshot itself cannot certify rendering; flush({render:false}) only acknowledges application.

Strict render Worker maps initialize the matching WASM CPU module in the main realm for synchronous reads, without a second map or GPU renderer. This adds one WASM instance's memory; main-thread maps reuse the existing module. Custom older bindings retain the zero-pitch fallback; nonzero pitch without the shared reader fails explicitly with CAPABILITY_UNAVAILABLE.

The low-level WASM export cameraSnapshotReadJSON(snapshot,method,args) accepts JSON strings. Snapshot and args each have a 64 KiB budget; method has a 64-byte budget. Context consists of camera/projection/viewport, using logical pixels. Supported reads are standard getters, project/unproject/cameraForBounds, sqs.scaleAt/sqs.cameraState, aggregate viewState and screenToLngLat with null for no ground intersection. Writes fail with CAPABILITY_UNAVAILABLE, invalid context with INVALID_ARGUMENT, and exceeded budgets with RESOURCE_LIMIT. The reader cannot certify rendering and does not access network, GPU, clocks or mutable sessions.

Legacy argument-free fit() uses common bounds fitting in pitched Mercator, retaining pitch, bearing and padding. It uses visible business layers, or all business layers when all are hidden. setBearing uses common validation, camera events and animation interruption; invalid values preserve state. The web compatibility map.camera.state now reports actual pitch/mode/zoom/ground bounds/scale instead of hardcoded 2D values. Legacy pick/select, complete 3D/terrain/symbol queries and exact perspective line widths remain pending; use queryRenderedFeatures for supported pitched feature queries.

The complete running acceptance page includes sources, styles and every action. Local main-thread/strict Worker, DPR 1/2 and 0/30/65° reads plus eight actual GPU pixel frames are verified. Software GPU and local production preview do not constitute external-machine, mobile-device or formal release acceptance.