Feature draw order for fills and lines
When a matching SDK reports commonPlanarLayerComposition:true, the shared Mercator view with zero pitch/roll and no terrain/extrusion combines media, backgrounds, labels, heat and supported static line/fill effects in complete layer order. This capability supersedes earlier media-combination exclusions only within that shared planar scope. Custom line animation, tilted/globe/terrain views and other unsupported material combinations retain their respective limits. Reordering and compatible diff preserve identities, caches, pending requests and fade clocks; material, geometry and texture budgets are validated before publication. See planar layer composition.
The new static-circle channel supports circle-sort-key, actual integer zoom in pitched Mercator/globe, stable ordering across grid bins and projective queries. The older08.55 fill/line 3D/globe restrictions below do not apply to that circle channel; seecircle styles. Historical24-check evidence keeps its original scope.
When the matching SDK provides commonLineGradients, its noncluster GeoJSON lineMetrics:true gradient channel supports the stable caps/joins, filtering/sorting and offset/translate described here. Historical solid/animation gradient rejection limits do not reject these combinations in the new gradient channel. Check matching capability and the gradient guide; other unsupported combinations still reject.
Shared planar fill-sort-key and line-sort-key are connected through commonLayerSortKeys. After layer filtering, the actual displayed features receive finite numeric keys and are drawn in stable ascending order: smaller keys draw first, larger keys draw later and cover them. Equal keys, including +0 and -0, retain source order. Sorting affects features within a layer; layer order stays unchanged.
Within each layer, queryRenderedFeatures returns the last drawn feature first, so larger keys come first and ties return in reverse source draw order. Original IDs, properties, source indices used by filters and logical MVT feature deduplication remain intact. Sorting does not renumber features. Existing geometry and opacity query rules still apply; this is not per-pixel material picking.
Copyable overlapping-fill example
Run this in an empty shared map. Both polygons use the same geometry. The red polygon has key 1 and the blue polygon key 2: the visible color is blue and the first queried ID is 2.
// @gis-api 0.5-session
// @permissions ["project.read", "map.write"]
import { map } from 'sqsmap';
const polygon = {type:'Polygon', coordinates:[[
[-0.01,-0.01],[0.01,-0.01],[0.01,0.01],[-0.01,0.01],[-0.01,-0.01]
]]};
map.addSource('ordered-source', {type:'geojson', data:{
type:'FeatureCollection', features:[
{type:'Feature',id:1,properties:{rank:1,color:'#ff0000'},geometry:polygon},
{type:'Feature',id:2,properties:{rank:2,color:'#0000ff'},geometry:polygon}
]
}});
map.addLayer({id:'ordered-fill',type:'fill',source:'ordered-source',
layout:{'fill-sort-key':['get','rank']},
paint:{'fill-color':['get','color'],'fill-opacity':1}
});
map.jumpTo({center:[0,0],zoom:12});
await map.sqs.flush({render:true});
const hits = await map.queryRenderedFeatures(undefined, {layers:['ordered-fill']});
export default {firstId:hits[0]?.id, ids:hits.map(feature => feature.id)};
Set or clear sorting on an existing shared line layer. Replace route with its actual layer ID; source property rank must contain finite numbers:
map.setLayoutProperty('route','line-sort-key',['number',['get','rank'],0]);
await map.sqs.flush({render:true});
map.setLayoutProperty('route','line-sort-key',null);
await map.sqs.flush({render:true});
Expressions and transactions
Keys support existing property expressions, global-state, type assertions, lexical let / var and lazy branches. Numeric strings are not coerced. An evaluated nonnumeric or nonfinite result rejects the entire candidate. Layout rejects feature-state. Sort keys reject interpolate; zoom is allowed only as the input of a top-level step, optionally wrapped in outer let, and uses integer floor(zoom). A zoom-dependent layout requires an explicit planar Web Mercator projection; other planes and globe reject it.
map.setLayoutProperty('ordered-fill','fill-sort-key',
['let','base',['number',['get','rank'],0],
['step',['zoom'],['var','base'],12,
['number',['global-state','topRank'],['var','base']]]]);
await map.sqs.flush({render:true});
Each expression allows at most 32 levels, 1024 structural nodes and 8192 evaluation steps. A candidate allows at most 100000 displayed features and an estimated 2000000 structural nodes, counting expression nodes across actual displayed features. Existing geometry and material budgets remain. Source, global-state, layout and camera changes validate the complete candidate before publication. Failure preserves the old source, global values, camera, frame and source/layer instance identities. Unread branches do not trigger dynamic-result errors.
Current support covers shared planar solid-color, RGBA-pattern and SDF-pattern fills, plus ordinary lines, dashed lines and explicit solid-line cap/join topology. Explicit topology combined with dashes still rejects. Sorting with animation, gradients, 3D, globe or media scenes rejects explicitly. The independent URL-basemap compiler, other sort types, mobile devices and formal release remain separate work.
The same 24-check portable script and complete HTML cover sorting, property/global/integer-zoom changes, failed-candidate recovery and queries. Core acceptance covers actual MVT mapping, holes, lines across grid cells, mixed geometry and translucent drawing. Local native, browser main-thread and Worker evidence does not establish device acceptance.