Create the layer. No network happens until it is added to a map; loading starts in onAdd.
See I3sBuildingLayerOptions. Only id + url are required.
ReadonlyidA unique layer id.
ReadonlyrenderingEither "2d" or "3d". Defaults to "2d".
ReadonlytypeThe layer's type. Must be "custom".
The distinct filterable BIM attribute fields across all sublayers (e.g. for a filter dropdown).
numeric distinguishes BldgLevel<=2 from Discipline='Architectural' in the value formatting.
Revert to the default (no-sun) lighting — the clearSun half of SunLightable (used when the
geo-sun system is disabled). Clearing lastSun also gates off the cast-shadow pass.
Sample DISTINCT values of field from currently-resident tiles (to populate a value dropdown).
Capped at max; reuses the per-node attribute-column cache.
The dataset's attribution string, if any.
The attribution option, or undefined if none was set.
The building's parsed tree (for a discipline/sublayer UI), or null until loaded.
The building's camera target [lng, lat] (degrees) — handy for driving your own flyTo.
[lng, lat] in degrees, or null until the building's anchor is known.
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.
Resolve a canvas point to the 3D geographic position of the frontmost rendered BSL surface —
the screen→scene primitive behind measurement and slice placement (all visible sublayers are
queried in one GPU pick pass, exactly the merged set render() draws).
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.
Snap radius in CSS pixels (default 0 = exact pixel): the nearest mesh hit within the radius wins, so a click slightly off an edge still lands on the mesh.
The picked position (lng/lat degrees, height metres above the rendered ground datum,
plus the cross-layer-comparable depth01), or null on a miss / before the first frame.
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.
Nearest obstruction distance per height row through a forward corridor — ONE synthetic forward-looking orthographic pick pass over the walker's cross-section, merged across the visible sublayers. The ObstructionProbeable contract; see it for why an overhead height probe cannot tell a doorway from a wall.
DOOR LEAVES AND RAILINGS ARE EXCLUDED — see DOOR_SUBLAYER_RE and
RAILING_SUBLAYER_RE. Both are modelled as solid geometry filling the very opening a
walker has to use (a leaf across the doorway, a rail overhanging the treads of the flight), so
a probe that honoured them refuses every door and every staircase in the building. Matched by
sublayer ROLE (a name test), because the discipline names differ between services; everything
else visible counts, glazing included.
The corridor; see ObstructionProbeOptions.
Distance in metres per row (index 0 = lowest), NaN where clear, null when this
layer cannot answer.
Working-set load fraction (0–1) across every VISIBLE sublayer: drawn tiles over drawn plus still-pending. 1 once the current view is fully resolved.
The fraction, or 0 before any sublayer is open.
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 building's topmost rendered surface at each position — ONE synthetic
top-down orthographic pick pass over the stations' bbox, then a per-station grid lookup (the
"buildings" line on an elevation profile; the surface probe behind first-person navigation).
The SurfaceSampleable contract, like the mesh layers.
All VISIBLE sublayers are sampled in one merged pass — exactly the set render() draws, so
sublayers hidden via I3sBuildingLayer.setSublayerVisible (including the auto-hidden
Overview shell) contribute nothing. Samples the currently-RESIDENT tiles; positions in
unloaded areas return null. Note: individual features hidden by an attribute filter
(I3sBuildingLayer.setFilter) still count as surface — the overhead pick pass, like
I3sBuildingLayer.pickPosition, does not evaluate per-feature styles.
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), marginM the padding around the stations, and
maxHeightM a CUT so the reading is the highest surface BELOW it rather than the topmost —
the difference between "the roof of this building" and "the floor I am standing on", and the
reason a walker can read one storey of a BSL at all (see SurfaceSampleOptions.maxHeightM).
Height in metres above the rendered ground datum per point, or null where this
layer has no surface.
Toggle the DEBUG tile bounding-volume (OBB) wireframe overlay live (placement QA).
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.
Filter the building by a BSL SQL predicate over per-feature BIM attributes — e.g.
"Discipline='Architectural'", "BldgLevel<=2", "Category IN ('Walls','Doors')". Features
that DON'T match are hidden (mode:'hide', default) or dimmed to a dark ghost
(mode:'xray'). Compiled once; evaluated per feature only on change; the GPU pays one texture
lookup at draw time.
A BSL SQL predicate string, or null / '' to clear the filter (show everything).
Optionalopts: { mode?: "hide" | "xray" }Filter display mode. mode:'hide' (default) removes non-matching features;
mode:'xray' dims them so the surrounding context stays legible. Omit to keep the current mode.
A promise that resolves once every resident tile has been re-styled.
X-ray DIMS; it does not make anything see-through. The per-feature style carries an alpha, but the building draws in the opaque pass (written unblended), so that alpha lands as a darkening multiply on the colour instead of compositing what is behind — the excluded parts read as a dark ghost of the model, still legible as context. Documented as-is rather than as-intended: the see-through version needs a blended pass (mesh KNOWN-GAPS §2), which this layer does not have.
Fade the whole building over the basemap (all sublayers together).
0 (invisible) – 1 (opaque); clamped.
Toggle cast shadows at runtime (the setShadows half of SunLightable).
true to cast shadows (needs a sun via I3sBuildingLayer.setSunState),
false to disable.
Adopt (or clear) the shared vector-drape atlas — satisfies the DrapeReceiver contract, so
enableVectorDrape drives this layer directly. Stashed until the renderer exists.
Show/hide one BIM sublayer by id (re-renders without re-streaming).
The sublayer id (from I3sBuildingLayer.getBuilding's sublayer tree).
true to show, false to hide.
Show/hide the whole building without removing the layer.
true to show, false to hide.
Wireframe render mode for the whole building (a BIM structure view). Edges come from the mesh triangles in-shader (no extra geometry); applies to the I3S PAA (non-indexed) sublayers these BSLs use — enable the I3sBuildingLayerOptions.wireframe option to make it work on Draco-served sublayers too.
0 = off (solid), 1 = edges drawn over the solid, 2 = wireframe only.
Aggregate streaming stats across visible sublayers — drive a debug HUD / load indicator from it.
Counts of sublayers (total) and visible sublayers, plus tile totals across the
visible ones: rendered (drawn this frame), resident (in VRAM), loading (decoding),
inFlight (network), queued (waiting to load) and resident bytes.
Every renderable sublayer with the state this layer ACTUALLY applied, and — when one is not
drawn — why. Built for a sublayer show/hide UI: BslSublayer.visibility alone is the service's
declared flag, which is only one of the three reasons a sublayer can be off, so a checklist
seeded from it claims sublayers are on that the layer is correctly hiding.
Distinguishing them matters: a service-hidden discipline and a user-hidden one look identical on screen, and reading "the publisher switched this off" as "the SDK lost my geometry" is how a correctly-rendered BSL gets reported as broken.
One entry per renderable leaf in tree order (including non-3DObject leaves, which
report opened: false / hiddenReason: 'not-renderable'). Empty until the building
document has loaded — poll, or call it from your onLoad.
Streams an Esri I3S Building Scene Layer (BSL) — a BIM model published as a tree of discipline sublayers (Walls / Doors / Floors / …) — and draws every renderable
3DObjectsublayer through one shared renderer, one anchor and one decoder pool in a single pass. On load it applies the service's own default view: the detailed disciplines, minus the coarseOverviewshell and minus any leaf the publisher switched off (I3sBuildingLayer.sublayerStates reports what is drawn and why). 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. This is the modern I3S 1.7+
nodePagespath: a legacy 1.4–1.6 BSL has no sublayers it can open and reports that through I3sBuildingLayerOptions.onError. For an IntegratedMesh or 3DObject scene layer use I3sMeshLayer instead.Example