Create the layer. No network happens until it is added to a map; loading starts in onAdd.
See I3sPointCloudLayerOptions. Only id + url are required.
ReadonlyidA unique layer id.
ReadonlyrenderingEither "2d" or "3d". Defaults to "2d".
ReadonlytypeThe layer's type. Must be "custom".
Revert to the ungraded (full-daylight) look — the clearSun half of SunLightable (used when the
geo-sun system is disabled).
The dataset's attribution string, if any.
The attribution option, or undefined if none was set.
Which PointColorModes this dataset can actually serve. 'height' always can (position
is always there); the other three need their per-point attribute, and picking one the tiles do
not carry renders the cloud BLACK rather than failing — so a color-mode menu should be built
from this, not from the full mode list.
The available modes in menu order; empty until the first tile arrives (unknown, not "none"). Poll it, or build the picker from the first non-empty result.
The dataset's camera target [lng, lat] (degrees) — handy for driving your own flyTo.
[lng, lat] in degrees, or null until the root center is known.
The colour this layer draws a classification code in — the override when one is set, else the ASPRS default. What a swatch beside a class checkbox should show.
The LAS classification code.
sRGB [r, g, b], each channel 0-1.
The LAS classification codes present in the scene, each with a human label and
point count, sorted by code — the input a class show/hide UI needs. Prefers the
I3S statistics endpoint (authoritative full-dataset counts + the service's own
labels, available once fetched); falls back to a live histogram of resident
tiles (counts grow as the scene streams). Codes seen live but absent from stats
are still included. Empty when the dataset has no classification attribute.
Subscribe to onClassifications to react as this fills in.
The active colour ramp, or undefined when the built-in Turbo ramp is in use.
The dataset's geographic footprint as [west, south, east, north] in degrees, read from the
service document and normalised out of whatever CRS it was published in.
[west, south, east, north] in degrees, or null before the layer document resolves
— or after, when the service declared no extent (or one in a CRS the reader cannot invert).
Where getCenter answers "point the camera here", this answers "is this dataset on screen at all" — the question a caller holding several layers has to answer before deciding what to load, in what order, and which of them deserve resident memory.
The z range the streamed cloud actually spans, in world ENU meters — what colorMode: 'height'
auto-fits to. Seeds a height-ramp UI with real numbers instead of guesses.
[min, max] in meters, growing as the scene streams; null before the first tile.
MapLibre CustomLayerInterface hook — invoked when the layer is added with map.addLayer;
initializes GL resources and begins streaming.
MapLibre CustomLayerInterface hook — invoked when the layer is removed with map.removeLayer;
releases GL resources and stops streaming.
Pick the nearest visible point under a canvas pixel. Uses the last rendered frame's matrices (valid as long as the camera is settled).
Canvas X in CSS pixels, top-left origin (e.g. a MapLibre click event's e.point.x).
Canvas Y in CSS pixels, top-left origin (e.g. e.point.y).
The picked point as an I3sPickResult (lng/lat/height + any LAS attributes), or
null on a miss / before the first frame.
Resolve a canvas point to the 3D position of the nearest RENDERED point — the measurement tools' screen→scene primitive (PositionPickable). Exact by construction: the picked point's stored coordinates go through the layer's placement (which embeds the vertical-datum seat), no depth reconstruction.
Canvas X in CSS pixels, top-left origin.
Canvas Y in CSS pixels, top-left origin.
Snap radius in CSS pixels (default 0): the point nearest the cursor within the radius wins — clicks a few pixels off a sparse point still land on it.
The picked position (lng/lat degrees, height metres above the rendered ground
datum, plus the cross-layer-comparable depth01), or null on a miss.
Optional method called during a render frame to allow a layer to prepare resources or render into a texture.
The layer cannot make any assumptions about the current GL state and must bind a framebuffer before rendering.
Called during a render frame allowing the layer to draw into the GL context.
The layer can assume blending and depth state is set to allow the layer to properly blend and clip other layers. The layer cannot make any other assumptions about the current GL state.
If the layer needs to render to a texture, it should implement the prerender method
to do this and only use the render method for drawing directly into the main framebuffer.
The blend function is set to gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA). This expects
colors to be provided in premultiplied alpha form where the r, g and b values are already
multiplied by the a value. If you are unable to provide colors in premultiplied form you
may want to change the blend function to
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA).
Sample the height of the topmost point surface at each position — the on-nadir DSM for the volume /
elevation-profile tools. One overhead ortho pass over the points' bbox
(StreamingPointCloudRenderer.sampleDepthGrid); each cell's top point → a height above the
rendered ground datum (same frame as queryTerrainElevation). Sparse gaps read null.
lng/lat in degrees.
Optionalopts: SurfaceSampleOptionsOptional: gridPx sets the overhead pass's long-axis resolution (default 1024;
small values like 64 for cheap point probes).
Height per point, or null where no point covers the cell / the layer isn't ready.
Geometric-error point attenuation (Cesium PointCloudShading) — size points by their node's geometric error so coarse/far points stay dense.
on toggles attenuation; scale multiplies the geometric-error spacing
(Cesium geometricErrorScale); maxPx caps the attenuated diameter in pixels (Cesium
maximumAttenuation). Each is applied independently when set.
Resize the resident-memory budget live (the runtime equivalent of the budget ctor option).
Shrinking evicts far/out-of-view nodes down to the new ceiling on the next frame; growing lets
the far LOD refill.
New ceilings. maxPoints = resident-vertex cap; maxBytes = resident VRAM budget
in bytes. Each is applied independently when set.
Recolour one LAS classification code, leaving the rest of the palette untouched.
The LAS classification code (e.g. 2 = ground).
sRGB [r, g, b], each channel 0-1, or undefined to restore the ASPRS default.
Show or hide one LAS classification code, leaving the rest of the set untouched — the convenience over setHiddenClasses for wiring a per-class checkbox (toggle one, several, or none). Live; no re-decode/re-stream.
Replace this layer's clipping planes at runtime. Planes are geographic
(ClippingPlanesOptions) and survive re-anchors; null (or an empty or
disabled set) removes clipping and restores byte-identical rendering.
The new plane set, or null to clear.
Set the point colour mode live.
The PointColorMode (e.g. 'rgb', 'height', 'classification', 'intensity').
Replace the colour ramp used by the intensity and height colour modes.
Stops (or a bare colour list spaced evenly), or undefined for Turbo.
Switch the vertical-datum placement live (rigid vertical shift; no re-stream).
Toggle the DEBUG tile bounding-volume (OBB) wireframe overlay.
true to draw the OBB overlay, false to hide it.
Eye-dome lighting (Cesium/Potree EDL) — a screen-space pass that shades depth gaps so a
sparse cloud reads as a solid surface. on toggles; strength/radius tune.
Pin the colorMode: 'height' ramp floor/ceiling, in world ENU meters. By default the ramp
auto-fits to the streamed z range, which DRIFTS as tiles load and evict — pin it to stop the
colors shifting under the viewer, or to stretch a shallow range.
min / max in meters; pass null for either to go back to auto-fitting that
end. Seed the inputs from getHeightRange.
Replace the hidden-class set (LAS codes). Live GPU mask update — no re-stream.
The intensity → ramp mapping used by colorMode: 'intensity': t = i * scale + bias, where
i is the raw u16 intensity. The default scale of 1/65535 spans the full u16 range, so a
survey that only uses the low end of it comes out nearly black until the scale is raised.
scale multiplies the raw intensity; bias offsets the result. Each is applied
independently when set.
Set the LOD distance-falloff exponent live (1 = standard SSE / Cesium-matched cusp).
Fade the points over the basemap.
Opacity in [0, 1] (clamped); 0 = transparent, 1 = opaque.
Adjust point sizing: fixedPx > 0 = constant pixel size; else perspective
attenuation from pointRadiusM clamped to [minPx, maxPx].
Draw round (vs square) points — rounder reads better on a sparse cloud.
Toggle cascaded sun shadows (cast + self-shadow) at runtime. Part of @bitruvius/sdk-maplibre's
SunLightable, so atmo.setShadows(...) reaches this layer.
Adopt (or clear) the shared vector-drape atlas — satisfies the DrapeReceiver contract, so
enableVectorDrape drives this layer directly. Stashed until the renderer exists.
Grade the point cloud by the environment (day/night exposure + sun tint) — satisfies
@bitruvius/sdk-maplibre's SunLightable, so a GeoSunSystem drives it. Point clouds carry no
normals, so this is a color grade (no directional lighting / shadows).
Show/hide the layer without removing it (streaming continues).
true to show, false to hide.
Live streaming + render stats for a debug HUD / perf overlay.
The engine's I3sEngineStats plus drawn (points rendered last frame) and the active
colorMode, or null until the engine is up.
Streams an Esri I3S Point Cloud (PCSL) SceneServer and renders it georeferenced as GPU points — LEPCC decode in a worker pool by default, coloured by RGB, intensity, LAS classification or height, with eye-dome lighting and per-class show/hide. Takes a SceneServer (or
…/SceneServer/layers/{id}) URL; onlyidandurlare required, and no network happens untilmap.addLayerruns it.Mercator only, and WebGL2 only — on a WebGL1 context the layer goes inert and draws nothing. Geographic services (wkid 4326/4979) and every CRS the SDK's registry knows open by themselves; anything else throws unless you pass a I3sPointCloudLayerOptions.reproject hook. This is the LIDAR entry point — for I3S point FEATURES (trees, street furniture) use I3sPointLayer.
Example