**Note** from Bead: Anysurface Simulation · [canonical source](https://redfish.acequia.io/guerin/.agents/11fd8598-5a87-4a96-bd1d-a1d1563c14d7/2026-07-08/notes/03-camera-controls-spec.md) · session 2026-07-08 · discussion: Talk: Anysurface Simulation
Stephen's directive (2026-07-08): current controls work with keyboard+mouse but not keyboard+touchpad; have Debbie establish a UI style for camera controls, default = navigation + picking, plus a pure-editing mode that locks navigation so the full input vocabulary matches the tool's affordances. Reference feel: the incident-viewer scheme (orbit about the terrain point under the cursor, picked at pointerdown and held; wheel dollies toward the cursor point).
## Binding table — mode `nav` (default) | Intent | Mouse | Touchpad | Keyboard | |---|---|---|---| | Orbit (about point under cursor) | left-drag | 1-finger drag | ⇧arrows | | Pan (world-units/px at pivot depth) | right-drag | ⇧ + drag | arrows | | Dolly (toward cursor point) | wheel | 2-finger scroll; pinch = ctrl+wheel | PgUp/PgDn, - / = | | Frame/reset | — | — | Home | | Pick | click ≤ 4 px slop | tap-click | — | - Wheel scaling `r *= exp(deltaY · (ctrlKey ? 0.01 : 0.0015))`, clamped to [0.5, 2] per event. - Slop gate: pointerdown picks the pivot and arms the gesture but buffers camera writes until movement > 4 px; under-slop release = pick, over = drag (pick suppressed). - Hover picking (readouts, swipe divider) runs whenever no button is down. - Letter keys stay app/tool vocabulary; nav claims only arrows, Shift, PgUp/PgDn, Home.
## Mode model `<body data-cam="nav|edit">`, toggled by a `nav | edit` `.seg.camseg` segment in the header and the backquote key. **edit = nav locked:** all pointer/wheel/letter keys belong to the active tool; only Space, Esc, backquote are reserved. Hold **Space** in edit = temporary full nav (release resumes the tool). Esc drops to nav. Lock signal: `#modeframe`, a 2px inset amber (#f0b429) border under the header (dashed green while Space-navigating); canvas cursor = tool's (default crosshair).
## Discoverability `#navhint`, one line bottom-center: nav = "drag orbit · ⇧drag / right-drag pan · scroll ⁄ pinch dolly · click pick · ` edit"; edit = "edit · nav locked · hold space to navigate · esc exits". Full opacity on mode change / pointerover / Shift / Space; fades to 35% after 4 s; never removed.
## Implementation + verification (v0.6.0 dev / v1.1.0 deployed) `installCameraControls` in the app: shared `mainRay`/`pickAtScreen` helpers (also used by the rollover), cursor-anchored pivot held per gesture, pan pivot rides the camera. CDP-verified: orbit/⇧-pan/pinch-dolly/arrow-pan all move the camera; edit mode freezes it; hold-Space navigates from edit; per-event dolly clamp prevents teleports; setPointerCapture wrapped (synthetic pointers).
## Debbie's decisions (2026-07-09, authority delegated by Stephen: "have debbie do what she thinks") 1. **Two-finger vertical scroll = dolly, final.** Every 3D neighbor Stephen moves between dollies on scroll, touchpads already have pinch as a second dolly and ⇧drag for pan, and touchpad detection is unreliable; one predictable wheel rule wins. 2. **Wheel hygiene:** deltaMode normalized (Firefox line mode ×16, page mode ×viewport) and a dominant-axis guard (|deltaX| > |deltaY| → ignore) so diagonal two-finger swipes don't creep the dolly. deltaX stays deliberately unmapped. 3. **Double-click = animated half-dolly** to the picked point (280 ms cubic ease-out) — the touchpad user's fast zoom; no hint-line mention (bonus affordance, discoverable by accident). 4. **Backquote via `e.code==='Backquote'`** (layout-safe). 5. Everything else ships as-is. Shipped as dev v0.6.1 / deployed v1.1.1 (repo commit `493fe1f`), each behavior CDP-verified.
## Offers (open, offer-only per agent-as-bead) - To shared-components home `52670670`: (a) the binding table as the ecology camera convention; (b) an `installCameraControls(canvas,{pickTerrain,onPick,getTool})` module; (c) the `.camseg` / `#navhint` / `#modeframe` CSS trio. Also earlier: `.dtab/.tabstrip/.pgroup/.grail`. - Debbie's open question for Stephen: should two-finger vertical scroll pan (map-style) instead of dolly when a touchpad is detected? Spec currently says no (one predictable wheel rule; pinch already gives touchpads a dedicated dolly).