Uniform planar line patterns
A matching development SDK with commonLineSymbols also supports shared planar line symbols, including true per-glyph curved geometry, target ownership, joint icon/text groups and shared budgets. Earlier point-only scope and pending line-symbol notes below are superseded for this bounded subset. Complex shaping, tilted/globe/terrain placement and complete road stitching remain pending.
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 connected implementation scope: commonLinePatternsUniform covers uniform RGBA line-pattern on shared planar Web Mercator lines. Each layer selects one image using strings, image/coalesce, global-state, explicit uniform object get/has, lexical/lazy branches and top-level integer-zoom step. This page demonstrates uniform selection. For per-feature selection check commonLinePatternsPerFeature and read per-feature patterns; paint feature-state selection is a SqsMap shared extension. Existing property/state/global and continuous-zoom expressions still control line-width and line-opacity; filtering and line-sort-key remain.
The complete image height maps to actual line-width. The along-line period is line-width×imageWidth/imageHeight. A32×8 image repeats every32 CSS pixels at width8 and every16 at width4. pixelRatio and display DPR do not independently shrink that aspect-derived period or stroke width. Width0 paints nothing. RGBA image colors multiply line-opacity; line-color does not tint them. Transparent pixels reveal lower map layers.
import { map } from 'sqsmap';
map.setStyle(null);
await map.sqs.flush();
map.setProjection({type:'mercator'});
map.jumpTo({center:[116.4,39.9],zoom:13,pitch:0});
await map.sqs.flush();
const rgba=[];
for(let y=0;y<8;y++) for(let x=0;x<32;x++)
rgba.push(...(x<16 ? [0,80,255,255] : [0,0,0,0]));
map.addImage('route-stripe',
{width:32,height:8,data:new Uint8Array(rgba)}, {pixelRatio:2});
map.addSource('route',{type:'geojson',data:{type:'Feature',id:1,
properties:{width:8},geometry:{type:'LineString',
coordinates:[[116.38,39.9],[116.42,39.9]]}}});
map.addLayer({id:'route',type:'line',source:'route',paint:{
'line-width':['coalesce',['feature-state','width'],['get','width']],
'line-opacity':1,
'line-pattern':['image','route-stripe']
}});
await map.sqs.flush({render:true});
map.setFeatureState({source:'route',id:1},{width:4});
await map.sqs.flush({render:true});
Image width must be a power of two from2 to512, height1..512, with pixelRatio following the image-registration finite-positive-number rules. Only RGBA images are connected; selecting SDF rejects. Missing images hide the line and produce styleimagemissing for actual visible demand. Adding the image restores rendering; coalesce can select an available fallback. Set line-pattern to null to restore the existing solid-line path. Each path starts at phase0; closed loops can have a texture seam at that origin. MVT starts each decoded tile path at phase0; cross-tile phase unification and stitching are not connected. Zoom crossfading is not provided.
The initial scope uses default butt ends and stable miter paths. Explicit caps/joins, reversals, miter greater than2, unstable short segments or self-crossings, nonzero offset/translate/gap and dash/gradient/animation/pitch/3D/globe/media combinations reject explicitly. Queries retain conservative width-envelope hits and original IDs, including transparent pattern pixels; they are not per-pixel picking.
Static patterns and existing animations jointly allow32 layers,4096 paths,100000 actual generated vertices and256MiB, with a ten-million CSS-pixel cumulative-distance precision budget. The two paths do not each receive a separate allowance. Geometry candidates allow at most two million nonadjacent-segment intersection checks. Existing expression/display-node and full-map64-tile MVT candidate budgets remain. Unknown neighboring features use width24/miter2 bounds. Invalid source/image/state/global/camera candidates preserve previous state, display, queues and identities.
The same public script and complete HTML check blue/green RGBA coverage, transparent stripes revealing a red lower layer, aspect-derived periods at two widths, zero width, image/state/zoom changes and rollback. The original CPU/GPU core8c1d76af passed four new CPU cases, one existing budget regression and one final serial actual GPU case; all19 original source hashes remain unchanged. Browser acceptance found a WASM missing-image guard excluding line-pattern; core9274437e fixes it and rebuilds both core/application WASM. The same34-check script now passes actual missing-image events and RGBA pixels on Linux, browser main thread and Worker. Devices, external platforms, mobile/iOS, complete styles and formal release remain pending. See SDK acceptance for matching versions and archive SHA.
Semantics reference the official MapLibre line-pattern specification. Vertical image mapping and aspect-derived repetition follow current public GL JS behavior; historical implementations can differ. The SqsMap engine is independently implemented without porting MapLibre code.
Historical34-check evidence keeps core9274437e. Its two rejection assertions for property/state selection are superseded by the later per-feature capability, and are not requirements for the current version. Use matching SDK capability and the complete per-feature contract.
The current public script replaces the two old rejection assertions with support checks. Optional state image names first fall back to properties; the same34 checks pass current native/main/Worker, and its public HTML runs directly. Historical original script and acceptance keep their original versions.