Note 05 — through-the-lens UX correction (2026-06-17) (Image Pose Uxui)

**Note** from Bead: Image Pose Uxui · [canonical source](https://redfish.acequia.io/guerin/.agents/74c30681-2b0c-48b2-b2a8-9e21190a4926/2026-06-16/notes/05-through-the-lens-ux-correction.md) · session 2026-06-16 · discussion: Talk: Image Pose Uxui

Stephen: *"The UI is not through-the-lens. we want to select a point on model and drag it to the uv of the image. this is overlay and compositing. not placing markers on a second panel."* + "watch the Naimark campanile segment (~27:05, 10–15s) — grab frames."

## What the Naimark/Debevec campanile demo actually shows (frames grabbed) Frames from `LRAj21y23r8.mp4` ≈27:05–27:28 (saved in `#through-the-lens-campanile` `2026-06-16/artifacts/campanile-frames/`, "Figure 7. Proof of concept for the 2D-to-3D approach"): - **One composite view.** The **photo of the Campanile is the backdrop**, with a **white wireframe model of the Campanile overlaid on it** (semi-transparent compositing). - The user **grabs a point on the wireframe model and drags it onto the matching feature in the photo.** As they drag, the camera `(K,R,t)` updates so the **whole wireframe slides / rotates / foreshortens onto the photo** until it registers. "The world appears to warp — but the camera is moving." - **No second panel. No separate markers.** Direct manipulation *on the overlay*.

## What I built (WRONG) vs the target | | Built (wrong) | Target (Naimark) | |---|---|---| | Layout | left image pane ∥ right 3D pane | **one composite** — image overlaid on the 3D model | | Correspond | click pixel on left, then click world on right | **grab a point ON the model, drag it to its place ON the image** | | Feedback | static; solve button | **camera follows the drag**; model registers live (through-the-lens) |

## Rebuild plan 1. **Composite is primary.** Image overlaid on the 3D canvas with opacity (have `#ovl` + slider). Left image pane demoted/optional (UV-on-left-image is the *later* path Stephen named). 2. **Grab a model point** = on `pointerdown` over the 3D canvas, build the camera ray (origin = camera, dir through the cursor pixel from pose+fov) and **`pickFeature(scene, origin, dir)`** → the world hit point `X` on the Google-tile surface (DSM). Requires tiles loaded **pickable** (retain CPU pick soup). 3. **Drag to the image** = the cursor's screen position is the target image **uv**. The pinned pair is `(X ↔ uv)` — same campanile correspondence, but captured by direct drag on the composite. 4. **Camera follows** = on each drag tick, re-solve the pose so `X` projects to the cursor (continuous Gleicher–Witkin differential OR per-tick LM/SQPnP from the accumulated pins). The model re-projects → appears to slide onto the photo. 5. On release the pair is a soft constraint; ≥4 → fully determined (+focal). Reuse `solver.js`.

## Enabler (this step) `pickFeature` is in `src/geo/pick_feature.ts` but NOT in our bundle. Add it (+ the `pickable` tiles option) to the `_build` facade and rebuild `taos-engine-ion.js` (same as `resolveGoogleTiles`).

## To verify (this time on the GPU) CDP on :9333 — drag on the composite, confirm `pickFeature` returns a world hit and the model registers.