Skip to main content

Planar solid-line distance softness

line-blur attenuates inward while preserving caps and one opacity composite

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 core implementation has been completed and pushed, with capability commonLineBlurSolid. The same 27 script checks and actual pixels passed native/main/Worker acceptance. Matching development SDK 0.3.0-dev.3da09ace passed member size/SHA, Linux/Android/JNI and 22 recent portable-script checks. Formal release, devices and other combinations remain pending. line-blur defaults to 0 and accepts a finite nonnegative CSS number up to 16; line-width retains its existing limit of 24. Property, paint feature-state/global-state, type, lexical/lazy and continuous-zoom expressions are supported. Entirely zero-blur layers use the previous solid/topology paths and budgets.

Nonzero blur attenuates inward using actual outline distance, with denominator blur CSS length plus one physical pixel expressed in CSS units. It does not expand an outer Gaussian glow. Thin-line centers may also fade as blur increases. Butt/square transverse end edges only clip coverage and do not seed attenuation. Square extension sides remain soft and use the same distance profile as straight segments of the same width. Round ends soften radially. Joins use true outlines; this independent implementation is not claimed to be pixel-identical to MapLibre.

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();
map.addSource('route',{type:'geojson',data:{type:'Feature',id:1,
  properties:{blur:4},geometry:{type:'LineString',
    coordinates:[[116.38,39.9],[116.4,39.9],[116.4,39.92]]}}});
map.addLayer({id:'route',type:'line',source:'route',
  layout:{'line-cap':'round','line-join':'miter'},paint:{
    'line-color':'#0060ff','line-width':8,'line-opacity':0.5,
    'line-blur':['coalesce',['feature-state','blur'],['get','blur']]
}});
await map.sqs.flush({render:true});
map.setFeatureState({source:'route',id:1},{blur:8});
await map.sqs.flush({render:true});

Positive blur first forms real mesh coverage union per original feature, then composites color and line-opacity once. Adjacent corner triangles do not blend translucent color repeatedly. All three caps/joins, stable closed LineStrings, Polygon rings and admitted offset/translate combinations reuse real topology. Original IDs, filtering/sorting and mixed zero/nonzero interleaving are preserved. Queries conservatively hit the actual outer envelope, including faint edges; they do not pick by pixel alpha.

The current scope accepts stable geometry without nonadjacent mesh interior overlaps. Self-crossings, overlapping parts within an original feature, degenerate or unstable short segments and cases without a stable true outline reject explicitly. Valid internal T seams in round caps are split into subedges and paired away; partial shared seams between distinct parts still reject. Leaves of one original feature with different resolved RGBA, including opacity, or blur values also reject. Positive blur does not support positive gaps, line-pattern, dash/gradient/animation/pitch3D/globe/media combinations. Zero blur retains the corresponding previous paths and restrictions.

Actual budgets are cumulative across unchanged resident and candidate blur channels: at most 256 drawable records, including zero-blur records in mixed layers. Consecutive original source groups with positive blur share one mask, with at most 256 total true outline edges per group. ROI physical pixels multiplied by soft outline edges allow at most 100 million distance comparisons. Endpoint scans, edge splitting/pairing and stability checks share a cumulative two-million limit. Generated vertices, including ROI composite vertices, allow at most one million, and combined actual extrusion including AA is limited to 2048 CSS pixels. Each frame uses at most 256 render passes and 512 draws.

Targets are conservatively estimated at 64 bytes per physical pixel plus three 256-byte-aligned row-padding allowances. Targets, geometry, outline textures and uniforms share a 512 MiB limit. Physical dimensions include DPR. MVT retains the full-map 64-tile limit and conservative unknown width/offset/join and ordinary-AA bounds; blur itself does not enlarge the outer envelope. Source/state/global/paint/camera/viewport/DPR/projection candidates validate before commit. Failure preserves previous data, display, resource queues and instance identities. Unselected future branches remain lazy and reject only when an over-budget branch is actually entered.

The core passed five focused CPU tests, one serial actual GPU case and a targeted WASM check. The same 27 script checks and actual pixels passed native/main/Worker acceptance. GPU evidence covers inward softness, thin centers, single-alpha L corners, all three caps, square extension attenuation, DPR/rotation/offset/translate, mixed ordering, conservative queries and rollback. The 64-tile MVT and candidate-DPR failures also preserve previous state. The shared script and complete HTML passed matching native/main/Worker acceptance. Matching development SDK 0.3.0-dev.3da09ace passed member size/SHA, Linux/Android/JNI and 22 recent portable-script checks. Formal release, devices and other combinations remain pending. Device/mobile/iOS, external-platform acceptance, complete combinations, MVT cross-tile continuity and formal release remain pending.

This acceptance uses an sRGB target for native headless readback and a UNORM target for MapView. RGB samples are normalized according to target encoding before comparison in sRGB; alpha is unchanged. Raw RGB bytes from different encodings are not treated as different softness profiles.

Semantics reference the official MapLibre line-blur specification, implemented independently by SqsMap.