Skip to main content

Desktop pitched maps

Shared cameras, layers, events and actual perspective scenes in the desktop console.

Development core ab68002 connects the desktop console to shared pitched Mercator maps. The same complete script below runs in embedded native QuickJS, browser main-thread maps and strict rendering Workers. Await queries; writes are chainable; flush confirms actual drawing. desktopPitchedCamera and desktopPitchedStyleRasterSources identify this development host. Global styleRasterPitchedSources remains false pending full query, legacy-entry and cross-entry audits.

Run with the GIS display CRS set to Mercator. Coordinates are longitude, latitude; longitude 181 preserves the explicit world copy. Pitch is 0–65 degrees; use logical zoom 0–24 for the supported scene range. Nonzero geographic pitch, free orbit and terrain surfaces reject explicitly. setPitch(0) exits the pitched view. The desktop display-CRS interface remains responsible for GIS reprojection; a shared projection call does not replace arbitrary data-coordinate conversion.

Copy the complete portable script into the desktop console. The desktop console needs no HTML or CSS. For an independent browser application, use the complete HTML/CSS/JavaScript example, including all button handlers.

// @gis-api 0.5-session
// @permissions ["project.read", "map.write"]
import { map } from 'sqsmap';
const checks=[];
function check(name,value) { if(!value) throw Error(name); checks.push(name); }
const capabilities=await map.sqs.getCapabilities();
check('actual shared pitched backend',capabilities.nativePitchedCamera === true || capabilities.webPitchedCamera === true || capabilities.desktopPitchedCamera === true);
map.setProjection({type:'mercator'});
map.jumpTo({center:[181,40],zoom:19,bearing:33,padding:{left:30,right:2,top:15,bottom:4}});
map.addSource('points',{type:'geojson',data:{type:'FeatureCollection',features:[
 {type:'Feature',id:7,properties:{radius:40,color:'#ff0000'},geometry:{type:'Point',coordinates:[181,40]}},
 {type:'Feature',id:8,properties:{radius:1,color:'#ff0000'},geometry:{type:'Point',coordinates:[181,-80]}},
 {type:'Feature',id:9,properties:{radius:4,color:'#0000ff'},geometry:{type:'Point',coordinates:[181.0002,40.0001]}}
]}});
map.addLayer({id:'dots',type:'circle',source:'points',paint:{'circle-color':['get','color'],'circle-radius':['get','radius']}});
await map.sqs.flush();
for(const pitch of [30,65]) {
 map.setPitch(pitch); await map.sqs.flush();
 check('pitch '+pitch,await map.getPitch()===pitch);
 const p=await map.project([181,40]);
 const state=await map.sqs.cameraState();
 check('padded point '+pitch,Math.abs(p.x-(state.viewport.width/2+14))<.01 && Math.abs(p.y-(state.viewport.height/2+5.5))<.01);
 const ll=await map.unproject(p);
 check('ground round trip '+pitch,Math.abs(ll.lng-181)<1e-6 && Math.abs(ll.lat-40)<1e-6);
 const hits=await map.queryRenderedFeatures([p.x+32,p.y]);
 check('original circle identity '+pitch,hits.length===1&&hits[0].id===7);
 check('radius expression '+pitch,hits[0].properties.radius===40);
}
export default {checks,pitch:await map.getPitch(),point:await map.project([181,40])};

The shared Rust core computes asymmetric padding, bearing, projection, ground unprojection, style circle radii and feature queries. Pointer dragging uses the shared ground-anchor solver to retain the position beneath the pointer. Wheel zoom anchors at the pointer. The existing common dragPan, scrollZoom, doubleClickZoom and keyboard controls apply. North reset and pitch changes also use the same checked camera and event path.

A caller style keeps its existing style loading, imagery transport, attribution and caching. Without a caller style, an internal scene draws without network access and is never exposed as a user style or source. setStyle(null) retains center, bearing, zoom, pitch and padding. Business layers share the perspective scene instead of being painted as a separate planar overlay.

flush({render:true}) waits for an actual GPU frame matching the current pose, business-layer revision and lighting. Normal preparation stays pending; real loading or drawing errors reject. Failed commands and cancelled requests do not wait for unavailable pixels. Pitched screenshots likewise accept only the current actual frame; this does not certify every streaming tile is downloaded.

Local Linux acceptance uses a real window, ScriptService, MapCommands, MapView and software Vulkan: eleven assertions from the same script, six actual pixel frames at 30/65 degrees and with imagery, style clearing, dragging and paint updates at an unchanged pose. Additional checks cover atomic rejection of 66 degrees, pose retention on clear, disabled dragging and returning to planar mode. The desktop offscreen scene currently draws at logical viewport density. High-DPI physical density, exact perspective line-width picking, full 3D/terrain/symbol queries and legacy entries remain under audit. External Windows/macOS machines, mobile devices, performance and formal releases need separate acceptance.

Related: web pitched maps, native pitched maps, camera API.