diff --git a/hive-ag3nt/assets/screen.html b/hive-ag3nt/assets/screen.html index 338b5dc..b0dfdc1 100644 --- a/hive-ag3nt/assets/screen.html +++ b/hive-ag3nt/assets/screen.html @@ -30,6 +30,12 @@ html, body { height: 100%; background: var(--base); color: var(--text); } #toolbar a { color: var(--blue); text-decoration: none; font-size: 0.85rem; } #toolbar a:hover { text-decoration: underline; } +.tbtn { + padding: 0.15rem 0.5rem; font-size: 0.72rem; font-family: inherit; + background: var(--surface0); color: var(--subtext0); + border: 1px solid var(--surface1); border-radius: 4px; cursor: pointer; +} +.tbtn.active { color: var(--green); border-color: var(--green); } #status { margin-left: auto; font-size: 0.75rem; color: var(--subtext0); } #status.connected { color: var(--green); } #status.error { color: var(--red); } @@ -50,7 +56,12 @@ html, body { height: 100%; background: var(--base); color: var(--text); width: 100%; height: calc(100% - 36px); overflow: auto; background: var(--crust); } +/* Fit mode: centre the canvas and let CSS scale it down to the + viewport (intrinsic resolution unchanged — see canvas.fit). */ +#canvas-wrap.fit { align-items: center; overflow: hidden; } canvas { display: block; cursor: default; } +/* max-* on a replaced element shrinks it preserving aspect ratio. */ +canvas.fit { max-width: 100%; max-height: 100%; } #msg { position: fixed; bottom: 1rem; left: 50%; transform: translateX(-50%); background: var(--surface0); color: var(--yellow); border-radius: 6px; @@ -64,10 +75,8 @@ canvas { display: block; cursor: default; }
🖥 screen ← agent - + + connecting…
@@ -92,15 +101,36 @@ canvas { display: block; cursor: default; } const msg = document.getElementById('msg'); const debugLog = document.getElementById('debug-log'); const debugBtn = document.getElementById('debug-toggle'); + const fitBtn = document.getElementById('fit-toggle'); + const canvasWrap = document.getElementById('canvas-wrap'); // --- Debug log --- let debugVisible = false; debugBtn.addEventListener('click', () => { debugVisible = !debugVisible; debugLog.style.display = debugVisible ? 'block' : 'none'; - debugBtn.style.color = debugVisible ? 'var(--green)' : 'var(--subtext0)'; + debugBtn.classList.toggle('active', debugVisible); }); + // --- Fit-to-window toggle --- + // Scales the canvas down via CSS so the whole desktop is visible + // without scrolling. The canvas's intrinsic resolution is untouched; + // only its displayed size changes (see canvas.fit / #canvas-wrap.fit). + // Pointer coordinates are rescaled in sendPointer to stay accurate. + // The choice is persisted in localStorage; default is fit-on. + let fitMode = localStorage.getItem('screen-fit') !== 'off'; + function applyFitMode() { + canvas.classList.toggle('fit', fitMode); + canvasWrap.classList.toggle('fit', fitMode); + fitBtn.classList.toggle('active', fitMode); + } + fitBtn.addEventListener('click', () => { + fitMode = !fitMode; + localStorage.setItem('screen-fit', fitMode ? 'on' : 'off'); + applyFitMode(); + }); + applyFitMode(); + function hex(bytes) { return Array.from(bytes).map(b => b.toString(16).padStart(2,'0')).join(' '); } @@ -570,8 +600,12 @@ canvas { display: block; cursor: default; } function sendPointer(ev) { const r = canvas.getBoundingClientRect(); - const x = Math.max(0, Math.min(fbW-1, ev.clientX - r.left)); - const y = Math.max(0, Math.min(fbH-1, ev.clientY - r.top)); + // In fit mode the canvas is CSS-scaled, so the rendered rect differs + // from the intrinsic resolution — map client coords back to fb pixels. + const sx = r.width ? canvas.width / r.width : 1; + const sy = r.height ? canvas.height / r.height : 1; + const x = Math.max(0, Math.min(fbW-1, Math.round((ev.clientX - r.left) * sx))); + const y = Math.max(0, Math.min(fbH-1, Math.round((ev.clientY - r.top) * sy))); let mask = 0; if (ev.buttons & 1) mask |= 1; if (ev.buttons & 4) mask |= 2;