Problem
The first presenter use on a two-display Mac worked, but setup is still an implementation-level display_index choice. An operator should be able to start HydraHeadFlatScreen in presenter mode without manually moving/full-screening windows or closing applications that retain the presentation display.
Today:
display_index can target the stream window (v2.2.5+, with HydraExperienceNet v6.1.38+), but it is static and display-index based.
- There is no explicit presenter mode, control surface, or clear single-screen fallback.
- macOS and Windows use the stream subprocess path while Omarchy/Linux is moving toward in-process streaming, which risks UX drift.
Desired UX
Provide an explicit, easy-to-run presenter mode with two supported layouts:
- Dual display: keep presenter controls on the primary display; show only the viewer/stream fullscreen on the selected secondary display.
- Single display: provide a clean one-screen experience with accessible controls that do not unintentionally cover the viewer (for example, an overlay/drawer or a deliberate viewer/controls transition).
The operator should be able to select the mode and target display by stable display identity/name where available, see which display will be used, launch/stop the experience, and recover predictably if the target display disconnects. Existing kiosk and self-service behavior must remain unchanged.
Platform parity requirements
| Capability |
macOS |
Omarchy/Linux |
Windows |
| Explicit single-screen and dual-display modes |
Required |
Required |
Required |
| Primary-display presenter controls |
Required |
Required |
Required |
| Secondary-display fullscreen viewer |
Required |
Required |
Required |
| Display discovery/selection using stable identity where supported |
Required |
Required |
Required |
| Clear fallback on missing/disconnected display |
Required |
Required |
Required |
| Same launch/stop/status semantics and configuration contract |
Required |
Required |
Required |
Platform-specific window APIs are expected, but user-visible behavior, configuration/API fields, lifecycle states, and diagnostics should match. Both subprocess and Linux in-process stream paths must honor the same contract.
Acceptance criteria
- A documented CLI/config/API option selects
single or presenter mode; it does not require hand-editing window state.
- In presenter mode with two displays, controls remain usable on the primary display and the viewer launches fullscreen on the selected secondary display.
- In single-screen mode, the viewer and controls are usable on one display without relying on a second monitor.
- Selection persists across restart and display reordering when the OS exposes a stable display identity; numeric index remains a backwards-compatible fallback.
- Disconnecting the selected display produces a visible, actionable status and a deterministic fallback; reconnecting can restore the intended layout without restarting the machine.
- Start, stop, relaunch, application handoff, and error recovery do not leave a stale fullscreen window or another managed presentation app covering the viewer.
- Existing
display_index, kiosk, and kiosk_disabled behavior remains backwards compatible.
- Heartbeat/diagnostics report mode, selected display, detected displays, actual viewer display, and fallback/error state.
- The feature is documented for operators on all three platforms.
Testing
- Add unit/contract tests for config parsing, display selection, lifecycle state, missing-display fallback, and argument/parameter propagation on all GOOS builds.
- Exercise both subprocess and in-process stream paths.
- Add manual/E2E coverage on macOS, Omarchy/Linux, and Windows for:
- one display;
- two displays;
- displays reordered between launches;
- secondary display disconnected/reconnected during a session;
- start/stop/relaunch and handoff from a presentation app;
- reboot/login recovery.