remote trackpad and keyboard server
git clone https://git.lucas.co/cce-remote.git
fix: black square in live view — move zoom transform off the <img>
iOS Safari stops repainting a GPU-promoted layer when its
multipart/x-mixed-replace <img> updates, so the persistent inline
transform + will-change I added for pinch-zoom turned the live view
black. The zoom/pan transform now lives on a #screenwrap div; the <img>
stays in the normal paint path. Tap mapping and the cursor marker are
unaffected (getBoundingClientRect reflects the ancestor transform).
Co-Authored-By: Claude Fable 5 <[email protected]>
index.html | 16 +++++++++++-----
1 file changed, 11 insertions(+), 5 deletions(-)
diff --git a/index.html b/index.html
index 74015f5..ccd4b2c 100644
--- a/index.html
+++ b/index.html
@@ -28,9 +28,14 @@
border-radius: 10px; }
#clicks button:active, #bar button:active { background: #2c5f69; }
#kb { position: absolute; opacity: 0.02; width: 1px; height: 1px; left: -10px; top: -10px; }
- #screen { display: none; position: absolute; inset: 0; width: 100%; height: 100%;
- object-fit: contain; background: #0c0d12; border-radius: 12px; z-index: 2;
- transform-origin: 0 0; will-change: transform; }
+ /* Zoom/pan transform lives on the WRAPPER, never the <img>: iOS Safari
+ stops repainting a GPU-promoted layer when its multipart-MJPEG <img>
+ updates (black square). The img stays in the normal paint path. */
+ #screenwrap { display: none; position: absolute; inset: 0; z-index: 2;
+ transform-origin: 0 0; border-radius: 12px; overflow: hidden; }
+ #pad.view #screenwrap { display: block; }
+ #screen { display: block; width: 100%; height: 100%;
+ object-fit: contain; background: #0c0d12; }
#vcursor { display: none; position: absolute; width: 14px; height: 14px; z-index: 3;
pointer-events: none; border: 2px solid #7dffff; border-radius: 50%;
box-shadow: 0 0 4px #000; margin: -7px 0 0 -7px; }
@@ -76,7 +81,7 @@
</div>
<div id="preview"></div>
<div id="pad"><div class="hint">drag = move · tap = click · 2-finger drag = scroll<br>2-finger tap = right click · hold = drag</div>
- <img id="screen" draggable="false">
+ <div id="screenwrap"><img id="screen" draggable="false"></div>
<div id="vcursor"></div>
<div id="switcher"></div>
<div id="menu"></div>
@@ -153,8 +158,9 @@ function updateRect(wins) {
// transform of the streamed image. Uniform scale+translate means
// getBoundingClientRect reflects it, so mapToWindow stays correct zoomed.
let vZoom = 1, vPanX = 0, vPanY = 0, pinch = null;
+const screenWrap = document.getElementById("screenwrap");
function applyViewTransform() {
- screenEl.style.transform = "translate(" + vPanX + "px," + vPanY + "px) scale(" + vZoom + ")";
+ screenWrap.style.transform = "translate(" + vPanX + "px," + vPanY + "px) scale(" + vZoom + ")";
}
function resetViewTransform() { vZoom = 1; vPanX = 0; vPanY = 0; pinch = null; applyViewTransform(); }
function clampPan() {