Greg's demos → viewer + controller faces (2026-06-11) (Snow Globe Harvard Spheres)

**Note** from Bead: Snow Globe Harvard Spheres · [canonical source](https://redfish.acequia.io/guerin/.agents/6a8f0a99-c255-4a5c-9c4a-9097d0ee9cd8/2026-06-11/notes/06-greg-demos-view-controller-plan.md) · session 2026-06-11 · discussion: Talk: Snow Globe Harvard Spheres

Stephen: *PROPFIND `https://harvardviz.live/greg/` — example items that could have controllers. His pages need to be converted to view and controller; the viewer should be scaled to 2:1 aspect full screen.* This is the first concrete application of the [companion-controller protocol](02-companion-controller-protocol.md) and the first build run under devops ([../../dev/](../../dev/README.md)).

## Inventory (PROPFIND :2078 + local mirror `sites/harvardviz.live/greg/`) | Page | Demo | Controls | |---|---|---| | `sphere-satellite.html` | Satellite orbits (ISS/GPS/GLONASS/Galileo/Iridium/Starlink) | 24 inputs | | `sphere-seismic.html` | P/S-wave propagation, shadow zones | 13 inputs | | `sphere-terminator.html` | Day/night terminator, seasons | — | | `sphere-coriolis.html` | Coriolis hurricane sim | — | | `sphere-magnetic.html` | Dipole field, aurora, SAA | — | | `sphere-pulsar.html` | Neutron star / pulsar | — | | `sphere-harmonics.html` | Spherical harmonics Y_l^m | 11 inputs (smallest page — pilot) | | `sphere-demos-v2.html` | Bundled collection (87 KB) | many | | `sphere-demos-index.html` | Card index | n/a | **Shared anatomy** (verified in harmonics/satellite/seismic): `<canvas width="1920" height="960">` — already exactly **2:1 equirect** — plus a `#menu` bar, a ~220px control panel built by shared `mkTog()`/`mkSl()` helpers, and demo logic driven by ordinary `input`/`change` events. **No acequia, no group state** — pure standalone pages. In catalog terms (note [05](05-sphere-admin-as-catalog-manager.md)): each demo is an Item whose control affordances are currently fused into the media.

## Conversion: one page, three faces Don't fork 8 pages into 16. Add a small shared shim (`sphere-faces.js`) and a `?role=` query param — content negotiation on one resource, matching the duck-typing ethos: - **`?role=viewer`** — hide `#menu` + panel; scale the 2:1 canvas to **full screen at 2:1 aspect** (CSS: width 100vw / height 50vw, centered; the host `sphere-viewer.html` iframe layer supplies the 200%-width geometry). Joins the acequia group, **receives** params. - **`?role=controller`** — show *only* the title + control panel, full-width phone layout. Joins the group, **publishes** params. - **no param** — today's standalone page, untouched (Greg's desktop use keeps working). ### The param bridge (the whole trick) The demos already route all behavior through input elements and their events, so the bridge never touches demo logic: - **Controller face:** delegate-listen for `input`/`change` inside the panel → throttled `group.setState({ itemState: { <itemId>: { params: { <inputId>: value } } } })`. - **Viewer face:** on `stateChanged`, set each element's `value`/`checked` and `dispatchEvent(new Event('input'|'change', {bubbles:true}))` — the demo's existing handlers fire as if a local user moved the slider. - **Buttons / one-shot actions:** monotonic nonce per button id (`{clicks: {<id>: n}}`); viewer fires `click()` on increase. - `itemId` and `group` arrive as query params (the companion protocol already passes `?group=&itemId=`). ### Catalog entries Each demo becomes an item JSON per the [companion schema](02-companion-controller-protocol.md): ```json { "type": "iframe", "url": "…/sphere-harmonics.html?role=viewer", "companion": { "url": "…/sphere-harmonics.html?role=controller", "label": "Harmonics" } } ``` Eight Items, **offered** through the normal propose→approve flow (or for Stephen to bind) — not written into `apps/sphere/` by the bead.

## Namespace discipline `greg/` is Greg's space. Converted pages + shim are **staged in this bead's `artifacts/`** (decision 0001, now in the sphere-apps repo's `dev/decisions/` — see [../../dev/README.md](../../dev/README.md)); binding into `harvardviz.live/greg/` (or a `guerin/apps/` home) is Stephen's move. The shim is additive — once blessed, the *same files* can land in place because the no-param face is behavior-identical.

## Epics (queued in the sphere-apps repo's `dev/WORK-QUEUE.md` — see [../../dev/README.md](../../dev/README.md)) - **G1 — Dual-face pilot:** `sphere-faces.js` + harmonics converted; verified with two local browser windows synced over a test group. - **G2 — Rollout:** remaining 7 demos + 8 catalog item JSONs with companions. - **G3 — On-sphere:** 2:1 full-screen scaling polish inside the real `sphere-viewer.html` iframe layer; controller-from-QR walkthrough at the Cabot installation.