# ADR 0006 — Reading Room interaction model: dock, palette, and on-demand overlays **Status:** accepted, accruing. This is the umbrella ADR for the reading-room interaction model that grew on top of [ADR 0005](0005-reading-room-spatial-trail.md) (the spatial trail). Its sections are referenced throughout the `internal/adapter/inbound/web` code as "ADR 0006 §N". The doc was created late (the sections shipped before it was written down), so §0 through §5 are recorded here as a descriptive index, grounded in the shipped code and templates; their full rationale lives in the originating PRs and journals. The **§6 universe overlay** below is recorded in full, as the section added with that work (PR #47, merged to main 2026-06-22). ## Section index (§0–§6) These are the affordances that sit on the spatial trail (ADR 0005). Each is server-rendered, htmx-driven, and degrades without JS (ADR 0003). - **§0 — Reading-room shell / nav.** The page chrome: title, nav, the `/` → `/t/u` entry that makes the universe floor the landing. - **§2 — The dock.** The bottom orientation strip: a `
` trail summary with walk/jump connectors and "from here →" one-hop neighbor chips. Zero-JS minimize. - **§3 — The command palette + active search.** ⌘K palette (htmx results fragment) and the htmx active-search overlay. Replaces ADR 0005's removed global search box; lookup still lives in the catalog/tag panes. - **§4 — The graph overlay.** On-demand pull-up of the focused document's reference neighborhood (`g` / margin "graph" link). Server-rendered SVG, embedded hidden, summoned by islands.js; node clicks are trail jumps, so navigating dismisses it. Replaces the in-trail graph pane. - **§5 — The world map + rich index.** One zoom level into a single world: the catalog as a reference-connectivity SVG (`/w/:world/u`), lazily htmx-loaded into the `m` overlay; plus the rich directory index (titles over a bare ls). The universe lists worlds as door cards by default; the map is the deliberate secondary view. ## §6 — Universe overlay (added 2026-06-22, PR #47, merged to main) ### Context The universe floor (ADR 0005 §4: "the universe view/floor is pane zero") was the one map still trapped as a trail pane. Its `floorSVG` laid worlds in a single horizontal row whose width was set by whichever band (systems or portals) was wider, so a lone world slid to the corner, and the row grew without bound as worlds multiplied. A trail pane also gives the universe no room: it is squeezed to pane width while the rest of the canvas competes for space. The graph (§4) and world map (§5) had already solved exactly this with full-viewport on-demand overlays; the floor had not been given the same treatment. ### Decision Give the universe floor the on-demand overlay treatment, in parity with §4 and §5: a full-viewport lens summoned on demand, plus a layout that scales to a large universe instead of one ever-widening row. 1. **The floor's "view as map" link summons a full-viewport overlay**, rather than rendering the map inline in the pane. `GET /u?overlay=1` returns the bare `floorSVG` fragment, trail-aware from `HX-Current-URL`; a direct `/u` hit redirects to `/t/u` (the floor has no standalone permalink — its home is pane zero). A `FloorHas` flag on the canvas VM renders the `#universe-overlay` shell whenever the floor pane is present; islands.js lazily htmx-loads the fragment into `#universe-canvas` on summon. Reuses the §4/§5 overlay chrome (`.graph-backdrop` / `.graph-panel` / `.graph-canvas`). 2. **Progressive enhancement.** The trigger carries `hx-boost="false"` so htmx does not boost-navigate the click; islands.js intercepts it to open the overlay. With JS off, the same href is a real `?view=map` that renders the map inline on the floor pane. The topology stays reachable either way (ADR 0003). 3. **Landing-only reach.** The trigger lives only on the floor pane (the landing), not as a global nav affordance. To pull up the universe you return to the landing (pane zero / one dock click away). Decided with Fritz over adding a persistent nav element. 4. **The floor renders worlds-as-cards by default; the overlay is the map.** No change to the ADR 0005 §5 cold-entry default — the overlay is the spatial topology that needs the real estate, not a second home for the cards. 5. **`floorSVG` is laid out as centered grids, not single rows.** Systems up top, portals in a band below, each band wrapping at roughly √N landscape- biased columns and centered within the canvas, so a lone world sits in the middle and the universe grows downward into the scrollable overlay. Width is bounded by column count; height grows with rows. 6. **One accessibility implementation across all three overlays.** A shared `showOverlay` / `hideOverlay` focus helper (islands.js) moves focus into the panel on open and restores it on close — to the trigger link for a click, to the active element for a hotkey toggle. Each overlay panel carries `role="dialog"`, `aria-modal="true"`, and `aria-labelledby` pointing at its title. The map overlay gained these in the same pass (it lacked them); the universe one was aligned to the panel to match the graph overlay. ### Envelope Web-layer only. No core / port / service / domain change, no broker / worlds / agent / deploy change, reader-only. The floor data (`Floor` / `FloorCached`) and `floorSVG` already existed; this adds a fragment route, an overlay shell, the islands.js glue, and the grid layout. Both transports (ADR 0005 §16) are unaffected — the floor renders the home world in QUIC mode and the full universe through the broker. ### Consequences - The universe map has room to breathe and the layout scales: many worlds wrap and center rather than sliding off one edge. - The three pull-up overlays (graph §4, world map §5, universe §6) now share one focus + ARIA implementation; the map and graph overlays inherited the focus management and the map inherited dialog ARIA in this pass. - **Open follow-up — satellite density at very large N.** Each system still draws its orbiting top-docs, so at tens of worlds the grid is correct and scrolls but each cell is busy. Capping satellites per world (or showing them only on zoom into a world) is the next increment. Same family as the roadmap's "graph-pane aggregation/cap for high-degree hubs". ### Alternatives rejected - **A global nav affordance for the universe** (always-present trigger). Rejected for landing-only reach; the floor is already pane zero and one click away. - **Overlay-only floor / map-first landing.** Rejected; the worlds-as-cards cold-entry (ADR 0005 §5) stays the default, and the overlay is additive. - **Link-graph clustering (Leiden) to organize the layout.** Investigated and shelved: measured on the real soul graph it mostly re-derived the directory tree (hub-and-spoke topology, no real community structure), so it did not earn a place in the floor. Recorded in the soul under the demarkus project journal.