Skip to content

Workspace, mobile and watch-center presentation

WorkspaceLayout (from entity-viz-kit/react) is a two-pane layout with a keyboard-operable separator:

  • Keys. Arrow keys resize (hold Shift for larger steps), Home and End jump to the minimum sizes, and Enter collapses or restores the details pane.
  • Pointer. Pointer resizing works on the separator only.
  • Minimum sizes and stacking. Each pane has a minimum width. Below a container width (760 px by default) the panes stack.
  • No storage. It stores nothing. onLayoutChange lets a host persist layout if the user opts in. Layout changes never touch query state or graph physics.

/workspace.html composes it with the search controls, explicit Results and Connections view tabs (ARIA tabs), InspectionPanel (profiles, relations, evidence and sources) and ControllerGraph.

  • Views stay mounted. Switching views never loses the results reading position or restarts the graph.
  • Show connections in a profile routes to the graph.
  • Unsupported capabilities are hidden. A host whose adapter has no profile/relation/evidence/source endpoints, and no graph (?capabilities=search-only), gets unavailable states and hidden actions, not errors.
  • Independent instances. ?instances=2 shows two workspaces that do not affect each other.
  • Layout memory is opt-in. It is only saved when the “Remember this layout on this device” box is checked (browser storage); unchecking it removes the saved layout.

Mobile behavior comes from the same page:

  • Stacking is decided by container width, not device detection.
  • Sheets are used for details on narrow screens, and they respect safe areas.
  • Touch targets are at least 44 px.
  • Keyboard-aware sizing: visualViewport updates --evk-keyboard-inset and --evk-viewport-height.
  • The graph has explicit full-screen entry and exit.
  • No hover or drag is required for any operation.

The automated checks use Chromium touch emulation in portrait and landscape; real devices are pending (docs/checklists/real-device-mobile.md). The installable browser extension is a desktop-browser surface; the mobile surfaces are the web workspace and the generic sidebar.

The operator prepares privately and publishes deliberately. The audience is view-only.

import { createPresentationSender, createSnapshotReceiver, projectAudienceSnapshot, newSessionId } from 'entity-viz-kit/core';
const sender = createPresentationSender({ pairing: 'room-42', sessionId: newSessionId(), startedAt: Date.now() });
transport.send(sender.snapshot(session => projectAudienceSnapshot({
...session, state: controller.getSnapshot().state, registry: controller.registry,
focus: presented, // chosen explicitly; not the operator's inspection
documents: visibleResults, relations: approvedRelations, evidence: approvedEvidence
}), false));
const receiver = createSnapshotReceiver({ pairing: 'room-42' }); // audience side
transport.subscribe(message => render(receiver.receive(message).state));
  • Projection. projectAudienceSnapshot includes only the query, the context summary, the presentation settings (graph positions, pins and camera limited to the included entities; scale), the presented focus and the records you pass. It returns a deep-frozen copy that shares nothing with the operator’s objects. The host decides what is approved; a front-end projection does not replace server-side authorization.
  • Messages. Operator messages are snapshot, hold, repeat (the current publication in answer to an audience request) and end. Every message carries the pairing, session ID, session start time and a strictly increasing sequence.
  • Receiver rules. The receiver refuses other pairings, audience-direction messages, older sessions, replayed or out-of-order sequences, and invalid or oversized data.
  • Publish, hold and reset. Publish sends a complete snapshot. Hold freezes the audience; the operator’s Publish is disabled until the hold is released. Reset publishes an overview of the same query: it changes presentation only.
  • Reload and reconnect. A reloaded audience asks for the current publication. A reloaded operator is a new session; the audience keeps the old view marked stale until the new session publishes. A heartbeat every 4 s lets the audience show reconnecting.
  • Transport. /operator.html and /audience.html#pair=<code> use a same-origin BroadcastChannel (createBroadcastTransport). It is not authentication. Implement PresentationTransport over your own channel for cross-machine use; no server is shipped.

PresentationControls shows Presenting separately from Inspecting privately and includes an audience-scale control. AudienceDisplay renders the query, the presented profile, relation evidence or source, and a host-supplied frozen graph (see the audience example: EntityGraph with paused, no worker, and a key per publication).

Physical display and room checks are pending: docs/checklists/watch-center.md.