PrivatecontainerPrivaterootPrivatecameraPrivatecontextClose handle of the open context menu, if any.
PrivateaudioThe sound layer, for sound rows (null before wiring / in tests).
PrivatescenePrivateanimationPrivatestatePrivateapplyScene-application engine: recomposes + pushes attrs to materials. Constructed with ACCESSORS for rootGroup/sceneGraph (both reassigned in initFromScene), never captured values — see the stale-capture pitfall.
PrivatecontrolsThe controls section (sliders/selects/LOD readout) below the list.
PrivatepanelPrivatelistPrivatefilterLive filter over layer names; only rendered when the scene has many layers.
PrivatefilterPrivatenoPrivatefilterPrivatevisiblePrivateeventsTracks every event listener attached during buildPanel/renderList so clear()/dispose() can tear them all down with a single call. Without this, listeners attached to detached DOM nodes hold closures referencing the panel until the GC reclaims the subtree — fragile, hard to test, and inconsistent with the rest of the viewer's listener-tracking pattern. (The controls section's listeners are tracked by LayerControls' own group.)
PrivaterowPrivatefailedFailed-load provider (paths + per-path reason), injected by the app after
initFromScene (see core/app/dataset/load-dataset.ts). The SAME provider
the data monitor uses — reads the loader's live failure set. Null before a
scene loads and after dispose.
PrivatepickLate-bound accessor to the current PickingSystem's markDirty, injected by
the app. Kept as a callback (not a captured PickingSystem) so it survives the
per-dataset picking re-creation. Null before wiring / in tests.
PrivatelastCheap change-detector for the failed set (JSON of sorted [path, reason]
pairs), mirroring DataMonitor's lastFailedLoadsSignature: the per-frame refresh
only touches the DOM when the signature changes. null is the reset
sentinel — no real signature (not even the empty-set '') can equal it, so
the first comparison after setFailedLoadsProvider / renderList always
falls through and re-applies (an empty set then correctly clears badges).
PrivateunsubscribePrivateresizePrivate Static ReadonlyFILTER_Scenes with more layers than this get the live name filter.
Expose layer state for external consumers (e.g., colormap legend).
Initialize the panel from a loaded scene. Must be called after the scene is loaded and rootGroup is available.
Reset every layer's parameters — visibility, display range, gamma, opacity, blending mode, colormap, and the mesh shading values (Ambient, Shade falloff, Specular, Shininess, Alpha cutoff) — back to their authored defaults.
Re-derives the default state from the scene graph (the same walk
initFromScene uses) and pushes every parameter through the regular
apply paths, so the materials, the row list, and the controls all agree.
No-op before a scene loads or when the scene exposes no layers.
Inject the shared failed-loads provider so per-row error badges can surface
a node whose loader threw (corrupt data / network failure). The app wires
the SAME provider the data monitor uses, after initFromScene. Resets the
change signature and applies the current failure set immediately so a scene
that already had failures at load lights up its rows without waiting for a
frame. Passing null (dispose) clears the provider and removes any badges
(the null reset sentinel forces the following pass through the gate even
when the resulting failed set is empty).
Inject the per-layer camera framer (the app wires SceneManager.fitCameraToObject, same late-binding pattern as the failed-loads provider). Null disables the "Frame camera" menu item.
Inject a callback that marks the GPU pick buffer dirty (PickingSystem.markDirty). Late-bound so it survives per-dataset picking re-creation.
Inject the sound layer for sound rows (eye = mute, slider = gain).
Re-send current layer visibility after a sound scene has attached.
PrivateapplyVisibility, for pixels AND sound: the scene object toggles as before, and the sound layer mutes the node (or, for a group, every sound under it). Every visibility path in the panel routes through here.
PrivateopenRoute a secondary gesture at target (right-click or touch long-press) to
the eye / row / header menu. Right-clicking an unselected row selects it
first (Finder/napari convention); an already-selected row keeps the
current multi-selection.
PrivateopenOpen the eye / row / header menu. layerPath is null for the header
menu. The opener gets aria-expanded while the menu is up; focus returns
to it on close (the utility handles both via onClose/focus-restore).
PrivatebuildPrivatebuildPrivatebuildPrivateapplyPush every layer's current state.visible into the scene objects.
PrivatesoloPrivatesetPrivateinvertPrivateresetReset ONE layer to its authored state. Re-derives the LayerInfo with a throwaway LayerStateManager over the kept scene graph (deliberately not factoring the private walkSceneGraph derivation — this reuses it verbatim, so reset can never drift from load), applies it through the state manager (which preserves selection and clears any solo capture — a direct Object.assign here would rewrite visibility behind the capture's back), and patches only this row (renderList would drop focus and reset the failed-loads signature).
Stable per-layer appearance summary for the embedder API
(LuxarApp.getLayers()). Copies, in panel display order.
Programmatic per-layer appearance patch (LuxarApp.setLayer()). Each
field takes the SAME route the panel's own control does — state-manager
setter (clamping, persistence, change notification) then the apply
engine — so a remote controller can never put the row, the material and
the stored state out of step with one another. Only the fields present
in patch are touched.
PrivaterefreshSync one row's eye icon + hidden class to the live state (no rebuild).
PrivatesetSet one layer's colormap with the fail-closed contract the dropdown uses (layer-controls): re-default the window on off↔on flips BEFORE applying, and if the C1 guard rejects the palette on every leaf, drop it and restore the identity window rather than leaving contradictory state.
PrivatesetSet one layer's blending mode (resolved per type, explicit ownership).
PrivateapplyCopy the source layer's appearance to every other layer, type-gated: display window clamped into each target's data bounds, gamma verbatim, blending resolved per target type, colormap only where supported. Order matters: the colormap copy runs LAST, so a target whose colormap mode flips gets that mode's re-defaulted window (via setLayerColormap) rather than the copied one — a window is only meaningful within one mode, so carrying it across the flip would mis-scale the new value. Deliberately NOT copied: mesh-only knobs, volumetric-only absorption, layer order, and opacity/visibility — those are per-layer compositing choices, not "appearance" (copying opacity would flatten a scene the user balanced layer-by-layer, while copying order would collapse every layer into one band).
PrivateclearPrivatebuildPrivaterenderBuild the full list of layer rows (called once on init, not on every state change)
PrivateapplyApply the live name filter to the rows (case-insensitive substring). Hidden rows keep their DOM (state indices stay valid) and are skipped by the listbox arrow navigation.
PrivateisTrue when the row for a path is hidden by the live filter.
PrivateupdateUpdate selection highlights and visibility classes without rebuilding DOM
PrivateupdatePatch each row's load-failure badge from the injected provider's failed set.
A layer is in error if its own path failed OR any descendant leaf failed
(failedPath === layer.path || failedPath.startsWith(layer.path + '/')), so
a failure inside a kind=lod/kind=partition group lights up the group's row.
Signature-gated so unchanged frames touch no DOM; the signature folds in
each path's reason (JSON of sorted [path, reason] pairs — unambiguous
even when a reason contains : or |) so a changed reason for a
still-failing path re-triggers the refresh instead of stranding a stale
tooltip.
PrivateapplyAdd / update / remove a single row's error badge + --error class. The
badge is a warning glyph with an accessible label naming the reason; the
row's own aria-label is left untouched so the base "name (type)" reading
is preserved.
PrivatedescribeTooltip text for a failing row. Prefers the provider's per-path reason
(loader error.message / classified kind); falls back to a clear generic
message. Appends the descendant-failure count when more than one leaf under
the row failed.
PrivatebuildThe sound row's gain slider; owns its pointer and arrow keys so neither selects the row.
PrivatecreatePrivaterepositionReposition the rendering controls (.luxar-gui) so it sits below the
layers panel when visible, or resets to its default position when hidden.
Privaterequest
Late-bound per-layer camera framing (SceneManager.fitCameraToObject).