**Note** from Bead: Firewatch Camera Grid · [canonical source](https://redfish.acequia.io/guerin/.agents/65783732-7907-4a36-983a-3b015e75e80b/2026-06-23/notes/03-grid-layout-v2-sketch.md) · session 2026-06-23 · discussion: Talk: Firewatch Camera Grid
Sketched by Debbie (senior UX/UI). This is the **convergent v2** built on the decisions Stephen ratified from the v1 sketch (see [`01-grid-layout-transitions-sketch.md` §Decisions](../../2026-06-22/notes/01-grid-layout-transitions-sketch.md)): spatial-morph transitions, fly tile→frustum, distinct fullscreen mode, segmented toggle, preserved selection + time-cursor, and **both** auto-ordering and hand-rearrange. The forks are settled, so per Buxton this is now "getting the design *right*" — but it is still a rendered low-fi sketch, not production. The transitions remain the heart. **Rendered sketch:** https://redfish.acequia.io/guerin/.agents/65783732-7907-4a36-983a-3b015e75e80b/2026-06-23/artifacts/sketches/grid-layout-transitions-v2.html
## Walkthrough of the transitions The whole thing runs on one morphing **stage** holding two panes (map + grid) that resize/slide between layouts; nothing cross-fades blind. A persistent **amber time-cursor** sits in its own strip above the stage and survives every step (`▶ play full tour` replays the entire arc end-to-end). 1. **Select on the map.** The map renders camera **poses** as the OrientedMap glyph set — blue frustum wedge, green dashed centerline, white-ringed camera dot, and a red projection ray on the selected camera. Click *or* tap a dot/wedge toggles selection (`click` + `touchstart`, multi-select). A `2D ⇄ 3D` toggle tilts the map into a cheap oblique so the same selection works in 3D. 2. **Fly to grid (shared-element).** On confirm, each selected camera spawns a **flyer** clone that animates from its map dot to its destination grid tile (position+size tween, 0.6s), then the grid pane reveals underneath as the flyers land. This is the load-bearing transition — it makes grid and map feel like one space. 3. **Auto-order by the 180° rule.** Tiles are ordered by each camera's **bearing around the scene** relative to the **line of action** (the axis through the scene and the selected cluster's circular-mean bearing). The axis is drawn on the map as a dashed orange line with a callout, and each tile shows its bearing (`taz`) and its `auto #n` slot. Ordering neighbors by azimuth means an adjacent fly-to never "crosses the line." 4. **Hand-rearrange.** Every tile has a drag grip; mouse or touch drag reorders live, the other tiles re-flow with a tween, and a dragged tile flips to a blue **✋ manual** badge — auto first, then hand-tweak (Stephen's "both"). 5. **Fullscreen grid ⇄ map.** The `⤢ fullscreen` mode is distinct: two full screens with **no side panels** — the segmented `Grid | 3D | Map` toggle swaps which pane fills the stage, the other parking offstage. 6. **To/from panel mode.** `▦ panel mode` is a separate transition: the grid and map panes morph to a 50/50 side-by-side split (drag still works in the grid half), and back. 7. **Return.** Flying back reverses step 2 — tiles clone out and shrink onto their map dots — and the map reappears with **selection and time-cursor intact**.
## How auto-ordering works, and how drag overrides it Auto order = sort selected cameras by `azFromScene` (bearing from the scene centroid). The 180° axis is the circular mean of those bearings; ordering by bearing keeps grid-adjacency = azimuth-adjacency so a fly never crosses the line of action. A hand-drag adds the tile's id to a `manualSet` (pinned). The **pin-only** policy is shown as the working default (pinned tiles hold their slot, unpinned ones take the remaining auto order) — but which policy is *right* is exactly the open question below.
## Reused from the real app - **OrientedMap glyph vocabulary** (`apps/camera-grid/oriented-map.js`): blue wedge `#39c0ff`, green dashed centerline `#2ee06a`, red ray `#ff2d2d`, white-ringed dot — redrawn as inline SVG on both the map and the tile faces. - **grid⇄map collapse** generalized from the app's `map-closed` / `panel-closed` flex-collapse into the morphing-pane stage. - **House style** from `plume.html` / `styles.css`: dark palette (`#06080d`/`#0a0f1a`/`#1e3a5f`), amber accent (`#ffd24a`/`#f1c40f`), segmented-toggle and `.go` button look, the time strip.
## Remaining open sub-question (answerable in the sketch) **After a manual card-drag, what happens to the rest?** The card carries three forks, each PUT to the handler `request/` dock as a `sketch-answer` request object: - **Pin only** — dragged card pinned where dropped; all others keep their slot (pure manual swap). - **Re-flow the rest** — pinned cards are fixed anchors; unpinned cards re-derive their 180°-aware order in the gaps. - **First drag locks all** — one manual move switches the whole grid to manual; auto returns only on an explicit "re-auto." (Provisional sub-fork still forkable later: keep the segmented toggle vs. add click-a-tile / gesture triggers, per the v1 ratification leaving those open.)