From 815f6561b797cd00a24c879801b5cf6b9852b116 Mon Sep 17 00:00:00 2001 From: iris Date: Sun, 31 May 2026 14:40:34 +0200 Subject: [PATCH] screen.html + docs: migrate canvas-sizing + RFB design prose (#713 batch 3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Expanded the /screen endpoint description in docs/web-ui.md to cover the substantive design rationale that lived in screen.html comments. screen.html shrinks correspondingly. Moved to docs/web-ui.md::Per-agent endpoints (GET /screen): - Deliberate thinness — minimal RFB renderer; noVNC vendoring path called out for production-grade replacement. - Fit-mode flex-item min-width:auto clamp: a flex item's automatic minimum size resolves to the canvas's intrinsic framebuffer resolution and clamps CSS max-* back up, making fit mode a silent no-op. The fix (flex: none + min-width: 0 + min-height: 0 + explicit px sizing via relayoutCanvas()) is now documented. - localStorage persistence for fit-mode (key screen-fit; default on). - Pointer rescale in sendPointer keeps clicks accurate. - ExtendedDesktopSize pseudo-encoding (-308 rect) gates the match-size button. Collapsed in screen.html: 8 #NNN cookies scrubbed across all inline comments. #133 (canvas-sizing fit bug — closed) ×5, #52 (noVNC vendoring — closed) ×1, #14 (relative URL — closed my piece) ×1, plus one CSS-block #133. Each comment shrinks to a brief pointer. screen.html: 8 → 0 #NNN cookies (100% reduction). Net ~26 lines of substantive prose moved into docs/web-ui.md. --- docs/web-ui.md | 28 +++++++---- frontend/packages/agent/src/screen.html | 62 +++++++++++-------------- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/docs/web-ui.md b/docs/web-ui.md index 7a38849a..1a1c2a35 100644 --- a/docs/web-ui.md +++ b/docs/web-ui.md @@ -1055,14 +1055,26 @@ shaped). `wait_for_login` entry. - `GET /events/history` — replay buffer for the terminal. - `GET /screen` — VNC viewer page (minimal RFB-over-WebSocket - renderer). Only accessible when `hyperhive.gui.enable = true` - in the agent's `agent.nix`; the harness shows a 🖥 screen link - in the state row when `gui_vnc_port` is present. Toolbar: - `⤢ fit` CSS-downscales the canvas to the window; `⤡ match size` - sends an RFB `SetDesktopSize` request so the server (weston) - changes its real output resolution to the window dimensions — - enabled once the server advertises the `ExtendedDesktopSize` - pseudo-encoding (issue #133). + renderer — deliberately thin, just enough to display the + desktop + forward pointer + keyboard. A production-grade viewer + would vendor noVNC; this file ships the minimal in-tree variant). + Only accessible when `hyperhive.gui.enable = true` in the agent's + `agent.nix`; the harness shows a 🖥 screen link in the state row + when `gui_vnc_port` is present. Toolbar: `⤢ fit` CSS-downscales + the canvas to the window via `relayoutCanvas()` setting explicit + pixel dimensions on the canvas — *not* CSS `max-width/max-height`, + because a flex item's automatic minimum size (`min-width: auto` + resolves to the canvas's intrinsic framebuffer resolution) silently + clamps `max-*` back up, making fit mode a no-op that just centred + + clipped the oversized canvas. The fit-mode rules pin the canvas + with `flex: none; min-width: 0; min-height: 0` so the JS-set size + sticks. `⤡ match size` sends an RFB `SetDesktopSize` request so the + server (weston) changes its real output resolution to the window + dimensions; enabled once the server advertises the + `ExtendedDesktopSize` pseudo-encoding (`-308` rect in the header). + Fit-mode state persists in `localStorage` (`screen-fit`); default + is on. Pointer coordinates are rescaled in `sendPointer` so clicks + land on the right pixel regardless of CSS scale. - `GET /screen/ws` — raw RFB byte relay: proxies WebSocket frames to the weston VNC server at `127.0.0.1:`. Transparent to any RFB variant. VNC port comes from diff --git a/frontend/packages/agent/src/screen.html b/frontend/packages/agent/src/screen.html index 702505d2..d9e983ad 100644 --- a/frontend/packages/agent/src/screen.html +++ b/frontend/packages/agent/src/screen.html @@ -62,13 +62,10 @@ html, body { height: 100%; background: var(--base); color: var(--text); fit the wrap) and clip any sub-pixel rounding overflow. */ #canvas-wrap.fit { align-items: center; overflow: hidden; } canvas { display: block; cursor: default; } -/* In fit mode relayoutCanvas() sets the canvas display size explicitly. - The canvas is a flex item, and flex items default to - min-width/min-height: auto — which resolves to the canvas's intrinsic - framebuffer resolution and clamps the JS-set size straight back up, - defeating the downscale (the bug behind #133 round 1). Pin the canvas - to exactly the size relayoutCanvas() sets: min-* 0 lifts the clamp, - flex: none stops flex grow/shrink from fighting it. */ +/* Pin the canvas to exactly the size relayoutCanvas() sets. See + docs/web-ui.md::Per-agent endpoints (GET /screen) for the + flex-item min-width:auto clamp that made fit mode a silent + no-op before this pinning. */ #canvas-wrap.fit canvas { flex: none; min-width: 0; min-height: 0; } #msg { position: fixed; bottom: 1rem; left: 50%; transform: translateX(-50%); @@ -93,13 +90,11 @@ canvas { display: block; cursor: default; }