PrivatecontrolsPrivaterangePrivategammaPrivateopacityPrivateabsorptionPrivateambientPrivateshadePrivatespecularPrivateshininessPrivatealphaPrivatephysicalThe knob group a material="physical" mesh layer shows IN PLACE of the five
sliders above (spec MESH_PHYSICAL_MATERIALS_SPEC.md §4): one live slider per
numeric knob in PHYSICAL_MESH_KNOBS, built once, plus read-only rows for the
colour knobs and the cutout, rebuilt per render from the layer's authored attrs.
PrivatephysicalPrivaterefractThe physical block's "Refract data" switch (spec §3.4 Phase 3).
PrivatephysicalPrivateblendPrivatelayerPrivatecolormapPrivatelabelPrivatelabelPrivatelod"Active level" dropdown for lod_group layers. Shown only when
the primary selected layer is an lod_group; hidden otherwise.
Options: auto plus one lock to level <n> entry per child
(1-based label; the option value stays 0-based for the registry's
lockLevel API).
PrivatelodStatus span next to the dropdown showing the currently-rendering
level (e.g. "L3/5", 1-based to match the data-monitor chip). Kept
live by a per-frame callback (layers-lod-status) registered by
the panel in buildPanel(), so it tracks auto-selection swaps driven
by camera motion — not only render() state changes.
PrivatelastLast text written to lodLevelStatus. The per-frame callback compares against this and only touches the DOM when the readout actually changes, so a static scene costs a string compare per frame rather than a DOM write. Reset in dispose().
PrivatecontrolsPrivateeventsTracks every event listener attached during build() so dispose() can tear them all down with a single call (the panel-wide listener-tracking pattern).
PrivatedepsTrue while a user-driven control interaction is applying state — the panel's state-change subscription skips control re-renders meanwhile.
Tear down the widgets + listeners so a subsequent build() starts fresh. Mirrors the panel's clear(): the EventGroup is re-instantiated (not left disposed) and the cached LOD readout text is reset so the fresh panel writes its first readout unconditionally.
Build the control widgets into container (the panel's controls div).
PrivategetLook up the LOD-group registry for the currently-loaded scene.
Lazy lookup via the SceneLoaderManager (the layers panel can't
import scene/ directly without violating the data → ui layer
direction; the SceneLoaderManager hands us the loader's registry
field). Returns null when no scene is loaded or the loader
was created without a registry factory wired up.
PrivaterenderPopulate the lod-level dropdown's options for the given child count.
Update controls to reflect the primary selected layer's values
PrivatesyncShow the Absorption (κ) slider only when it can do something: the
primary selection's mode is volumetric. All three geometry types
implement the volumetric math (gsplats phase 1, points phase 3,
lines phase 4), so the mode alone decides. Called from render() and
the blend-dropdown change handler (mode switches must reveal/hide
it immediately).
PrivatesyncShow the five mesh appearance sliders only when they can do something.
All five are type-gated. The four lighting controls are additionally hidden when
the material resolves to shading="none", where their uniforms are compiled out.
alphaCutoff instead carries a mode gate ON TOP: the cutout only exists in
opaque, so in any other mesh mode the threshold is read by no branch of the
fragment shader.
The gate is on the MESH-RESOLVED mode, so a mesh in a volumetric-inherited/selected
mode (which a mesh resolves back to opaque) still shows its active cutout slider.
A GROUP layer over meshes deliberately does NOT get these. Unlike opacity and gamma, they do not compose along the ancestry (a shade floor is not a multiplicative attr), so a group control would have to mean "set all descendants", which is a different verb from every other control in this panel.
PrivatesetThe four lighting sliders, and the cutoff on its own narrower gate.
PrivatesetSwap the house-only generic controls (Gamma, Blend) for the physical controls, and back.
PrivatedisposeTear down the physical knob group (sliders own DOM + listeners).
PrivatebuildThe "Refract data" switch (spec §3.4 Phase 3), after the knob sliders: a glass that draws after — and refracts — the emissive data behind it. Rides the same knob record and apply path as the sliders, so Reset restores it the same way.
PrivatebuildOne live slider for a physical knob, from its table spec: the track spans the
spec's slider domain (a log track for a length spanning decades, its top stop
meaning ∞ where the spec says so), and a drag follows the mesh-appearance
pattern — map the slider value into material space, mutate every selected
layer's record, then push each through the apply engine.
PrivatesyncGrey out the knobs that change nothing in the current state of their siblings,
with the reason as hover text (physicalKnobInertReason). Measured, not
guessed: on a metal the whole glass family is inert, and a clearcoat roughness
without clearcoat is too — a live slider that does nothing reads as broken.
PrivaterenderSeat the physical sliders on primary's live knob record and rebuild the
read-only rows beneath them. sheen_color, attenuation_color and
alpha_cutoff appear only when authored — their defaults are the material's own
business, and a colour picker is not a slider.
PrivateisTrue when primary is a kind=partition layer wrapping one or more
nested lod_groups, so the "Active level" dropdown broadcasts to them.
PrivatecomputeCompute the "Active level" readout text for the primary-selected
layer, or null when no LOD readout applies (non-LOD layer, or the
lod_group registry isn't populated yet). 1-based ("L3/5") to match
the data-monitor chip (data-loading-monitor/templates/scene-graph.ts) and the
dropdown labels. Reads the live active level straight from the
registry, so it is correct on any frame — including auto-selection
swaps driven by camera motion.
PrivatesetWrite the LOD readout, skipping the DOM touch when the text is unchanged. Lets the per-frame callback run every frame at the cost of a string compare on a static scene rather than a DOM write.
Per-frame: keep the LOD readout in sync with the live active level
chosen by the auto-selector. Cheap — early-returns when the panel is
hidden or the primary layer has no LOD readout, and setLodStatusText
skips the DOM write unless the text actually changed. A null text
(non-LOD layer / registry not ready) leaves whatever render()
last set in place rather than clobbering it.
Mesh-only appearance sliders (spec §6.2). Hidden for every other geometry type — mesh is the only SHADED type, so a shade floor and a falloff exponent have nothing to act on elsewhere.
alphaCutoffis gated more narrowly still: only inopaque, the one mode that applies the cutout.