diff --git a/desktop/index.html b/desktop/index.html index 9d11436..ff2fb02 100644 --- a/desktop/index.html +++ b/desktop/index.html @@ -105,11 +105,16 @@
- - + + + diff --git a/desktop/src/main.ts b/desktop/src/main.ts index d2c8e7c..348da70 100644 --- a/desktop/src/main.ts +++ b/desktop/src/main.ts @@ -465,6 +465,9 @@ function leaveVoice() { if (statusInterval) { clearInterval(statusInterval); statusInterval = null; } stopCamera(); remoteVideoActive = false; + remoteFrameCount = 0; + vdRemoteCounter.textContent = "0 frames received"; + vdRemotePlaceholder.classList.remove("hidden"); vdVideoStrip.classList.add("hidden"); remoteCtx.clearRect(0, 0, vdRemoteVideo.width, vdRemoteVideo.height); } @@ -535,6 +538,9 @@ vdCamBtn.addEventListener("click", () => { // ── Remote video display (Blocker 5) ───────────────────────────── const remoteCtx = vdRemoteVideo.getContext("2d")!; +const vdRemotePlaceholder = document.getElementById("vd-remote-placeholder")!; +const vdRemoteCounter = document.getElementById("vd-remote-counter")!; +let remoteFrameCount = 0; listen("video:frame", (event: any) => { const { width, height, jpeg_b64 } = event.payload; @@ -542,8 +548,11 @@ listen("video:frame", (event: any) => { remoteVideoActive = true; vdVideoStrip.classList.remove("hidden"); + vdRemotePlaceholder.classList.add("hidden"); vdRemoteVideo.width = width ?? vdRemoteVideo.width; vdRemoteVideo.height = height ?? vdRemoteVideo.height; + remoteFrameCount++; + if (remoteFrameCount === 1) console.log("first remote video frame:", width, "x", height); const img = new Image(); img.onload = () => { diff --git a/desktop/src/style.css b/desktop/src/style.css index 8834f6d..47c25ce 100644 --- a/desktop/src/style.css +++ b/desktop/src/style.css @@ -316,20 +316,51 @@ body { padding: 2px 0 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } -/* Video strip in voice drawer */ -.vd-video-strip { - display: flex; - gap: 4px; - padding: 4px 0 2px; - overflow-x: auto; -} -.vd-video-tile { - width: 160px; - height: 90px; - border-radius: 6px; +/* Full-screen video stage — overlays lobby/main when video is active */ +.vd-video-stage { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 96px; /* leave room for voice drawer */ background: #000; + z-index: 50; + overflow: hidden; +} +.vd-remote-stage { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: contain; + background: #000; +} +.vd-remote-placeholder { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: #888; + pointer-events: none; + z-index: 1; +} +.vd-remote-placeholder.hidden { display: none; } +.vd-placeholder-text { font-size: 18px; margin-bottom: 8px; } +.vd-placeholder-sub { font-size: 12px; opacity: 0.7; } +.vd-local-pip { + position: absolute; + right: 16px; + bottom: 16px; + width: 200px; + height: 112px; + border-radius: 8px; + background: #111; + border: 2px solid rgba(255, 255, 255, 0.2); object-fit: cover; - flex-shrink: 0; + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5); + z-index: 2; } /* Incoming call banner */