Plan — bring the firewatch cameras into the incident-viewer → "cloud sculpting" (Firewatch Camera Grid)

**Artifact** from Bead: Firewatch Camera Grid · [canonical source](https://redfish.acequia.io/guerin/.agents/65783732-7907-4a36-983a-3b015e75e80b/2026-06-13/artifacts/plan-cameras-into-incident-viewer.md) · session 2026-06-13 · discussion: Talk: Firewatch Camera Grid

**Bead:** firewatch-camera-grid (65783732) authors this plan. **Executes against:** the incident-viewer repo (`Documents/src/incident-viewer/`) + bead `cbf8b027` (cross-bead; viewer ships land there, logged there). **Method:** epic-step, build+CDP+deploy per step.

## Vision (Stephen, 2026-06-13) Fuse the 10 Sandy AlertWildfire cameras into the incident-viewer's 3D. Stand **at the convergence of where the cameras point**, look where **pixel values are frame-differencing the most** (the moving smoke), **tie the cameras together to establish depth**, and **"airbrush" point-cloud density** from the projective textures — **cloud sculpting**. The airbrush is **dual**: a **volume MAKER inside the silhouette** (where a camera sees smoke, add density along its rays) and a **volume ERASER in the inverse silhouette** (where a camera sees clear/see-through, carve density away). Projective textures give the smoke its **color**; the maker/eraser carving gives its **form**. This is multi-view **space carving / tomographic visual-hull** driven by frame-difference saliency, made interactive — and it's well-posed even with ~6 effective cameras *because the eraser is so constraining*: any clear ray deletes a huge swath of false volume.

## What the incident-viewer already gives us (reuse inventory) - **Posed camera billboard** — the Sandy 15801 timelapse billboard (`camFramesFeature` / `buildCamCard`): catalog-driven, shows the frame nearest the master playhead, re-orients by archived az. → generalize to all 10. - **Projective texturing** — the FMV `Projector` / `updateProjector` (projects a frame onto terrain/cap from a pose, with the attitude chain). → repoint at fixed PTZ cameras. - **Camera markers + az wedges** — the floated glyph + `buildWedgeMesh` (just fixed). **Attitude-convention fix already shipped** (boresight matches to 0.15°). - **Master clock + scrub**, ToA fire-progression layer, perimeters (S3), terrain/ECEF (`ecefDeltaModel`), `geo.heightAt` ray context, the `__misb` debug surface + CDP harness.

## Dependencies - **Calibration sidecars** (note 05 §1: city-light/ridgeline render-and-compare + citizen star-finding) — needed for *accurate* projection + carving. Can bootstrap on the telemetry prior + the shipped attitude fix; tighten with calibration. - **FOV from zoom** transfer fn (note 05: 0–40 → 62.5°…2.5° hFOV) → projector frustum. - **Frame fetch perf** — the SW cache (note 06) matters once we pull many frames across cameras × time. - Camera data: the firewatch manifest `cameras-sandy.json` + per-cam telemetry (already built/online); 9 of 10 cams need timelapse assets added to the STAC (15801 already has them) OR the viewer reads the firewatch manifest directly.

## Phases ### Phase A — cameras as posed sources in the viewer (the bridge) - **A1** Generalize the 15801 timelapse billboard to **all 10** Sandy cams (catalog-driven from the firewatch manifest/STAC): each a posed billboard showing its frame nearest the master playhead, re-oriented by per-frame az. *Reuse `camFramesFeature`; mostly data-wiring.* **MVP, low risk.** - **A2** Camera-as-**projector**: project each cam's current frame onto terrain from its pose (telemetry+calibration az/el, FOV from zoom). *Reuse the FMV `Projector`; repoint + multi-instance.* Risk: multiple projectors + blending; start with 1–2. ### Phase B — saliency (frame-differencing → silhouette) - **B1** Per-camera temporal **frame-difference** (current vs prior frame[s]) in a WebGL/canvas pass → a **motion/saliency mask** = the smoke **silhouette**; its complement = the **inverse silhouette** (clear/see-through). *New; in-browser.* - **B2** Modulate the projective texture by saliency — project the moving smoke brightly, fade static terrain ("look where it's differencing the most"). ### Phase C — dual-airbrush space carving → density volume (the core) - **C1** A voxel/point density grid over the fire airspace (anchored at the **triangulated fire base**, note 04). Per camera, per frame: **MAKER** — add saliency-weighted density along rays **inside** the silhouette; **ERASER** — carve density along rays in the **inverse** silhouette. Accumulate across cameras → the saliency-weighted **visual hull** of the plume. *New; the heart of it. The eraser makes it tractable with few cams.* - **C2** Color the surviving density from the **projective textures** (form from carving, color from projection); render as point cloud / splat / volume in the scene. - **C3** **Manual airbrush** = the same mechanic by hand: paint maker/eraser strokes on a camera frame → back-project as add/erase along rays (this *is* the annotation→GIS raster-paint of note 05 §2.5, in 3D). Human + auto share one brush. ### Phase D — the vantage + sculpting UX - **D1** "At the center of the cameras": a view position at the **convergence centroid** of the cameras' look-rays (triangulation), orbiting the plume; the projective textures wrap the scene around you. - **D2** Sculpting controls: brush size/strength, maker/eraser toggle, threshold/clean, time-coherence (freeze-on-scrub / relax-on-settle per the smoke-sim directive). Tie to master clock + ToA + perimeters as the stage.

## Ordering + MVP path `A1 (10 billboards, scrubbed) → A2 (projectors) → B1/B2 (frame-diff saliency) → C1 (dual-airbrush carve) → C2 (color+render) → C3 (manual brush) → D (vantage+sculpt UX)`. **Smallest visible win:** A1 — all 10 cameras as posed billboards scrubbing on the master clock inside the incident-viewer (the wall, in 3D, on the real terrain). Each later phase is independently demoable.

## Risks / unknowns - **Calibration accuracy** gates projection + carving (few-degree error smears the hull) — bootstrap on prior, tighten with note-05 §1. - **Time sync**: frames are minutes apart + unsynchronized across cams → carve at coarse reconstruction instants; the eraser tolerates this better than additive-only. - **Grazing/long-range geometry** → poor depth conditioning along the line of sight; the multi-camera eraser is the mitigation. - **Perf**: N projectors + a frame-diff pass + a voxel accumulate per frame — budget GPU; the SW cache (note 06) for frame fetch; consider downsampled saliency + a coarse grid first. - **Cross-bead**: ships land in the incident-viewer repo/bead (cbf8b027); coordinate so the firewatch manifest is the camera source of truth.