From f8ccb5cbccd22952344707b9521296ff4b5d9166 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Sat, 11 Jul 2026 02:02:24 +0700 Subject: [PATCH] fix(recording): keep live webcam preview visible --- electron/electron-env.d.ts | 1 + electron/hudOverlayBounds.test.ts | 33 ++++++++++++++++++++++++++ electron/hudOverlayBounds.ts | 13 ++++++++++ electron/preload.ts | 3 +++ electron/windows.ts | 27 +++++++++++++++++++-- src/components/launch/LaunchWindow.tsx | 10 ++++++++ 6 files changed, 85 insertions(+), 2 deletions(-) diff --git a/electron/electron-env.d.ts b/electron/electron-env.d.ts index 2aa748b4..8a4eedd6 100644 --- a/electron/electron-env.d.ts +++ b/electron/electron-env.d.ts @@ -209,6 +209,7 @@ interface Window { hudOverlayHide: () => void; hudOverlayClose: () => void; hudOverlayRendererReady: () => void; + hudOverlaySetWebcamPreviewVisible: (visible: boolean) => void; getHudOverlayCaptureProtection: () => Promise<{ success: boolean; enabled: boolean }>; getHudOverlayMousePassthroughSupported: () => Promise<{ success: boolean; diff --git a/electron/hudOverlayBounds.test.ts b/electron/hudOverlayBounds.test.ts index dac1058c..dcc4daef 100644 --- a/electron/hudOverlayBounds.test.ts +++ b/electron/hudOverlayBounds.test.ts @@ -3,6 +3,7 @@ import { describe, expect, it } from "vitest"; import { getHudOverlayWindowBounds, resizeHudOverlayFallbackBounds, + shouldExpandHudOverlayFallback, } from "./hudOverlayBounds"; describe("getHudOverlayWindowBounds", () => { @@ -143,3 +144,35 @@ describe("resizeHudOverlayFallbackBounds", () => { }); }); }); + +describe("shouldExpandHudOverlayFallback", () => { + it("expands while recording only when the floating webcam preview is visible", () => { + expect( + shouldExpandHudOverlayFallback({ + fallbackExpanded: false, + recordingActive: true, + webcamPreviewVisible: true, + }), + ).toBe(true); + }); + + it("keeps the compact recording fallback when there is no webcam preview", () => { + expect( + shouldExpandHudOverlayFallback({ + fallbackExpanded: false, + recordingActive: true, + webcamPreviewVisible: false, + }), + ).toBe(false); + }); + + it("preserves manual fallback expansion outside recording", () => { + expect( + shouldExpandHudOverlayFallback({ + fallbackExpanded: true, + recordingActive: false, + webcamPreviewVisible: false, + }), + ).toBe(true); + }); +}); diff --git a/electron/hudOverlayBounds.ts b/electron/hudOverlayBounds.ts index 22facf93..8c51b88c 100644 --- a/electron/hudOverlayBounds.ts +++ b/electron/hudOverlayBounds.ts @@ -37,6 +37,19 @@ export function getHudOverlayWindowBounds( height, }; } + +export function shouldExpandHudOverlayFallback({ + fallbackExpanded, + recordingActive, + webcamPreviewVisible, +}: { + fallbackExpanded: boolean; + recordingActive: boolean; + webcamPreviewVisible: boolean; +}): boolean { + return fallbackExpanded || (recordingActive && webcamPreviewVisible); +} + export function resizeHudOverlayFallbackBounds( workArea: HudOverlayWorkArea, currentBounds: HudOverlayWorkArea, diff --git a/electron/preload.ts b/electron/preload.ts index 9a15edb9..e55d42cb 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -182,6 +182,9 @@ contextBridge.exposeInMainWorld("electronAPI", { hudOverlayRendererReady: () => { ipcRenderer.send("hud-overlay-renderer-ready"); }, + hudOverlaySetWebcamPreviewVisible: (visible: boolean) => { + ipcRenderer.send("hud-overlay-set-webcam-preview-visible", visible); + }, getHudOverlayCaptureProtection: () => { return ipcRenderer.invoke("get-hud-overlay-capture-protection"); }, diff --git a/electron/windows.ts b/electron/windows.ts index 478584b5..55f6314c 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -5,7 +5,11 @@ import path from "node:path"; import { fileURLToPath } from "node:url"; import { app, BrowserWindow, ipcMain } from "electron"; import { USER_DATA_PATH } from "./appPaths"; -import { getHudOverlayWindowBounds, resizeHudOverlayFallbackBounds } from "./hudOverlayBounds"; +import { + getHudOverlayWindowBounds, + resizeHudOverlayFallbackBounds, + shouldExpandHudOverlayFallback, +} from "./hudOverlayBounds"; import { getPackagedRendererBaseUrl } from "./rendererServer"; const electronWindowsDir = path.dirname(fileURLToPath(import.meta.url)); @@ -30,6 +34,7 @@ let hudOverlayIgnoringMouse = true; let hudOverlaySourceSelectionActive = false; let hudOverlayMouseReassertTimer: NodeJS.Timeout | null = null; let hudOverlayRecordingActive = false; +let hudOverlayWebcamPreviewVisible = false; let countdownWindow: BrowserWindow | null = null; let updateToastWindow: BrowserWindow | null = null; @@ -190,10 +195,15 @@ function getHudOverlayDisplay() { function getHudOverlayBounds() { const { workArea } = getHudOverlayDisplay(); + const fallbackExpanded = shouldExpandHudOverlayFallback({ + fallbackExpanded: hudOverlayFallbackExpanded, + recordingActive: hudOverlayRecordingActive, + webcamPreviewVisible: hudOverlayWebcamPreviewVisible, + }); return getHudOverlayWindowBounds( workArea, isHudOverlayMousePassthroughSupported() && !hudOverlayRecordingActive, - hudOverlayFallbackExpanded, + fallbackExpanded, ); } @@ -410,6 +420,18 @@ ipcMain.handle("get-hud-overlay-mouse-passthrough-supported", () => { }; }); +ipcMain.on("hud-overlay-set-webcam-preview-visible", (_event, visible: boolean) => { + const nextVisible = Boolean(visible); + if (hudOverlayWebcamPreviewVisible === nextVisible) { + return; + } + + hudOverlayWebcamPreviewVisible = nextVisible; + if (hudOverlayRecordingActive) { + applyHudOverlayBounds(); + } +}); + ipcMain.handle("set-hud-overlay-capture-protection", (_event, enabled: boolean) => { loadHudOverlayCaptureProtectionSetting(); hudOverlayHiddenFromCapture = Boolean(enabled); @@ -432,6 +454,7 @@ ipcMain.handle("set-hud-overlay-capture-protection", (_event, enabled: boolean) export function createHudOverlayWindow(): BrowserWindow { loadHudOverlayCaptureProtectionSetting(); hudOverlayFallbackExpanded = false; + hudOverlayWebcamPreviewVisible = false; const initialBounds = getHudOverlayBounds(); let hasShownHudWindow = false; diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx index d7dc51bc..09cca63e 100644 --- a/src/components/launch/LaunchWindow.tsx +++ b/src/components/launch/LaunchWindow.tsx @@ -152,6 +152,16 @@ function LaunchWindowContent() { hudOverlayMousePassthroughSupported, }); + useEffect(() => { + window.electronAPI?.hudOverlaySetWebcamPreviewVisible?.(showRecordingWebcamPreview); + }, [showRecordingWebcamPreview]); + + useEffect(() => { + return () => { + window.electronAPI?.hudOverlaySetWebcamPreviewVisible?.(false); + }; + }, []); + const { recordingHudOffset, isHudDragging,