**Note** from Bead: Incident Viewer Epic 4 · [canonical source](https://redfish.acequia.io/guerin/.agents/be9c3efd-ed6e-440e-9e88-653db538931d/2026-06-14/notes/04-layer-tree-ux.md) · session 2026-06-14 · discussion: Talk: Incident Viewer Epic 4
Stephen's directives, implemented in `lib/layer-tree.js` (+ `.d.ts`) and `index.ts`. Shipped commit `3cb7b06`, chunk `index-LJ4-Yjhn.js`, live on both hosts. The conventions are now the cross-app standard — hatched into bead **geospatial-ux-ui** `f80f1929`.
## Changes 1. **Removed the gear-panel Opacity slider.** It was misplaced ("doesn't make sense over there") and only affected the FMV layer. Image opacity is now driven per-layer from the layer-tree. 2. **Tree-driven, multiplicative opacity.** `effectiveOpacity(node)` = node opacity × every ancestor folder's opacity (a **collection's opacity multiplies its children**). Applied: FMV (per-item, via the current clip), TOA raster (per-item, own material), cameras/perimeters/origin (collection-level — one shared material per layer, so per-item there isn't separable; noted). 3. **Fixed checkbox → visibility.** `walkLeaves()` returned **ids**, but `syncVisibilityFromTree` treated them as **nodes** (`leaf.ivKind`), so the sync was a silent no-op — checkboxes didn't actually hide layers. `walkLeaves()` now returns leaf NODES. Verified: ticking the origin row flips `__misb.origins()[0].hidden`. 4. **Fly-to + set-time-span affordances, with touch parity.** - Per-row icons: **⌖ Fly to (h)** and **◴ Set time-span (t)** — on items AND folders. - A **folder** resolves to the UNION of its descendant items: bounding area for fly-to, `[min,max]` extent for time-span. - The same actions live in the **context menu** (right-click / long-press → the app's rich menu; the tree emits a `context` event, the app owns the menu). 5. **Keys** (`h` was never FMV-only — it's "go to any spatial item"): `h` = fly-to/look-at the selected spatial node (folder = union); `t` = set time-span of the selected node; AIR7 **track-follow moved to `Shift+T`**.
## IRHS location (Stephen's question) The `imagery-irhs` items ARE georeferenced. STAC geometry = an axis-aligned bbox Polygon (coarse); the **KMZ carries the precise georeference** — `<GroundOverlay><LatLonBox>` (e.g. N 34.289279 / S 34.182359 / E -118.713203 / W -118.798221, rotation 0) wrapping a GCP-warped PNG. The viewer does **not** drape the IRHS collection yet (no render feature; it's already typed `raster` in the tree, anticipating it). Drape = `LatLonBox` + PNG → textured quad (same machinery as the TOA raster). **Candidate next ship.**
## Verify / caveats CDP on the built dist: 0 exceptions, 136 row-affordances over 68 rows, `#opacity` gone, checkbox→hidden works. Opacity for FMV is the solid replacement of the old slider; TOA/cameras/perimeters/origin set their material `.albedo` alpha (same runtime pattern as `capMat.albedo`) — visually confirm the raster/marker fades in a real session and tune if a layer doesn't honour it.