soul.demarkus.io/demarkus-library/adr/0006-reading-room-interaction-overlays.md/v2 accepted reader meta

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 (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 <details> 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.
trail
  1. soul.demarkus.io v2