From be255ee5f5ed1180463c5575a0f2675931429317 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Sat, 29 Aug 2026 08:17:38 +0100 Subject: [PATCH] show press-to-paint in the panel, temporarily MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The lag is felt in the browser and every number so far was measured somewhere else. At x11vnc's own socket, press-to-paint is ~50ms: median 47ms over 8 synthetic presses, and 51ms with a second x11vnc running with X DAMAGE enabled — so -noxdamage costs nothing and the comment defending it stands. What that cannot include is the sidecar relay, the platform's socket relay and the network, which is where the rest of the lag has to be. This prints the end-to-end figure in the status row so the two can be subtracted. Instrumentation, not a feature. Delete it and its row once the question is settled. Co-Authored-By: Claude Opus 5 Officer-Session: f7a62308-0977-4cf4-aa29-c020853fd420 --- web/MinesweeperPanel.tsx | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/web/MinesweeperPanel.tsx b/web/MinesweeperPanel.tsx index 014c0c4..17bed45 100644 --- a/web/MinesweeperPanel.tsx +++ b/web/MinesweeperPanel.tsx @@ -82,6 +82,19 @@ export const MinesweeperPanel = () => { const [frame, setFrame] = useState<{ width: number; height: number } | null>(null); const [box, setBox] = useState<{ width: number; height: number; dpr: number; zoom: number } | null>(null); const [status, setStatus] = useState(null); + /* + TEMPORARY INSTRUMENTATION — press-to-paint, measured where it is actually felt. + + The same figure taken at x11vnc's own socket is ~50ms (median 47ms over 8 synthetic presses, and 51ms + with the X DAMAGE extension enabled, so `-noxdamage` is not costing anything). What that number cannot + include is the two relay hops and the network, and those are the only places the rest of the lag can + be. This is the end-to-end figure, so the two can be subtracted. + + Cleared on the frame that follows a press, so it times the first paint after a click rather than every + repaint. Delete this and its row below once the question is settled. + */ + const pressAtRef = useRef(null); + const [lagMs, setLagMs] = useState(null); const [error, setError] = useState(null); const [connected, setConnected] = useState(false); const [busy, setBusy] = useState(false); @@ -200,6 +213,10 @@ export const MinesweeperPanel = () => { }, onFrame: (image, x, y) => { canvasRef.current?.getContext('2d')?.putImageData(image, x, y); + if (pressAtRef.current !== null) { + setLagMs(Math.round(performance.now() - pressAtRef.current)); + pressAtRef.current = null; + } }, onCopyRect: (from, to) => { // Same canvas as source and destination, which is what CopyRect is: the 2D context takes a @@ -301,7 +318,10 @@ export const MinesweeperPanel = () => { const rfb = rfbRef.current; if (!rfb) return; ev.preventDefault(); - if (kind === 'down') ev.currentTarget.focus(); + if (kind === 'down') { + ev.currentTarget.focus(); + pressAtRef.current = performance.now(); + } if (kind !== 'move') { const bit = BUTTON_MASK[ev.button] ?? 0; @@ -351,6 +371,10 @@ export const MinesweeperPanel = () => { game or a repair for when it stops behaving, and a footer is where neither gets read. */}
{connected ? 'connected' : 'connecting…'} + {/* Temporary — see `pressAtRef`. ~50ms of this is the game and the capture; the rest is the trip. */} + + lag {lagMs === null ? '—' : `${lagMs}ms`} + {/* Focus decides where keys go, and a canvas gives no hint that it can hold any. */} click the board to send it keys