From 31d1022fef0fb8a7c8e2a82268dd6789f6dbf0f9 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Tue, 26 May 2026 23:12:01 +0700 Subject: [PATCH 1/8] fix(capture): stabilize platform source handling --- electron/ipc/register/recording.ts | 36 ++++++----- electron/ipc/windowsCaptureSelection.test.ts | 66 +++++++++++++++++++- electron/ipc/windowsCaptureSelection.ts | 60 ++++++++++++++++++ electron/windows.ts | 4 +- src/hooks/useScreenRecorder.test.ts | 11 ++++ src/hooks/useScreenRecorder.ts | 9 ++- 6 files changed, 167 insertions(+), 19 deletions(-) diff --git a/electron/ipc/register/recording.ts b/electron/ipc/register/recording.ts index e88f6f17..b13453c7 100644 --- a/electron/ipc/register/recording.ts +++ b/electron/ipc/register/recording.ts @@ -147,7 +147,7 @@ import { parseJsonWithByteOrderMark, parseWindowId, } from "../utils"; -import { resolveWindowsCaptureDisplay } from "../windowsCaptureSelection"; +import { resolveWindowsCaptureTarget } from "../windowsCaptureSelection"; const execFileAsync = promisify(execFile); @@ -442,15 +442,13 @@ export function registerRecordingHandlers( const browserMicFallbackRequested = shouldStartWindowsBrowserMicrophoneFallback(options); - const windowId = parseWindowId(source?.id); - const isWindowCapture = Boolean(windowId && source?.id?.startsWith("window:")); - - const resolvedDisplay = resolveWindowsCaptureDisplay( + const captureTarget = resolveWindowsCaptureTarget( source, getScreen().getAllDisplays(), getScreen().getPrimaryDisplay(), ); - const displayBounds = resolvedDisplay.bounds; + const displayBounds = + captureTarget.kind === "display" ? captureTarget.bounds : null; setWindowsOrphanedMicAudioPath(null); const config: Record = { @@ -458,29 +456,37 @@ export function registerRecordingHandlers( fps: 60, }; - if (isWindowCapture) { - config.windowHandle = windowId; + if (captureTarget.kind === "invalid-window") { + return { + success: false, + message: + "Selected window is no longer available. Please choose the window again.", + }; + } + + if (captureTarget.kind === "window") { + config.windowHandle = captureTarget.windowHandle; } else { // Windows Graphics Capture (WGC) requires a raw HMONITOR handle. // We attempt to resolve the handle by matching the physical coordinates of the target display. const monitors = getMonitorHandles(); const matchedMonitor = monitors.find( (monitor) => - monitor.x === Math.round(displayBounds.x) && - monitor.y === Math.round(displayBounds.y), + monitor.x === Math.round(captureTarget.bounds.x) && + monitor.y === Math.round(captureTarget.bounds.y), ); if (matchedMonitor) { config.displayId = matchedMonitor.handle; } else { // Fallback to coordinate-based matching if handle resolution fails - config.displayId = resolvedDisplay.displayId; + config.displayId = captureTarget.displayId; } - config.displayX = Math.round(resolvedDisplay.bounds.x); - config.displayY = Math.round(resolvedDisplay.bounds.y); - config.displayW = Math.round(resolvedDisplay.bounds.width); - config.displayH = Math.round(resolvedDisplay.bounds.height); + config.displayX = Math.round(captureTarget.bounds.x); + config.displayY = Math.round(captureTarget.bounds.y); + config.displayW = Math.round(captureTarget.bounds.width); + config.displayH = Math.round(captureTarget.bounds.height); } if (options?.capturesSystemAudio) { diff --git a/electron/ipc/windowsCaptureSelection.test.ts b/electron/ipc/windowsCaptureSelection.test.ts index de6a36cf..17039d4d 100644 --- a/electron/ipc/windowsCaptureSelection.test.ts +++ b/electron/ipc/windowsCaptureSelection.test.ts @@ -1,6 +1,9 @@ import { describe, expect, it } from "vitest"; -import { resolveWindowsCaptureDisplay } from "./windowsCaptureSelection"; +import { + resolveWindowsCaptureDisplay, + resolveWindowsCaptureTarget, +} from "./windowsCaptureSelection"; describe("resolveWindowsCaptureDisplay", () => { const primaryDisplay = { @@ -62,3 +65,64 @@ describe("resolveWindowsCaptureDisplay", () => { }); }); }); + +describe("resolveWindowsCaptureTarget", () => { + const primaryDisplay = { + id: 101, + bounds: { + x: 0, + y: 0, + width: 1920, + height: 1080, + }, + }; + + const secondaryDisplay = { + id: 202, + bounds: { + x: 1920, + y: -40, + width: 2560, + height: 1440, + }, + }; + + it("uses a window handle when a Windows window source is selected", () => { + const resolved = resolveWindowsCaptureTarget( + { id: "window:123456:0", sourceType: "window" }, + [primaryDisplay, secondaryDisplay], + primaryDisplay, + ); + + expect(resolved).toEqual({ + kind: "window", + windowHandle: 123456, + }); + }); + + it("does not silently turn an invalid window source into display capture", () => { + const resolved = resolveWindowsCaptureTarget( + { id: "window:0:0", sourceType: "window", display_id: String(secondaryDisplay.id) }, + [primaryDisplay, secondaryDisplay], + primaryDisplay, + ); + + expect(resolved).toEqual({ + kind: "invalid-window", + }); + }); + + it("keeps display capture behavior for selected screens", () => { + const resolved = resolveWindowsCaptureTarget( + { id: "screen:202:0", sourceType: "screen", display_id: String(secondaryDisplay.id) }, + [primaryDisplay, secondaryDisplay], + primaryDisplay, + ); + + expect(resolved).toEqual({ + kind: "display", + displayId: secondaryDisplay.id, + bounds: secondaryDisplay.bounds, + }); + }); +}); diff --git a/electron/ipc/windowsCaptureSelection.ts b/electron/ipc/windowsCaptureSelection.ts index 4250c12f..3fdf3c00 100644 --- a/electron/ipc/windowsCaptureSelection.ts +++ b/electron/ipc/windowsCaptureSelection.ts @@ -1,5 +1,7 @@ export type WindowsCaptureSourceLike = { + id?: string; display_id?: string; + sourceType?: string; }; export type WindowsCaptureDisplayBounds = { @@ -19,6 +21,38 @@ export type ResolvedWindowsCaptureDisplay = { bounds: WindowsCaptureDisplayBounds; }; +export type ResolvedWindowsCaptureTarget = + | { + kind: "window"; + windowHandle: number; + } + | { + kind: "display"; + displayId: number; + bounds: WindowsCaptureDisplayBounds; + } + | { + kind: "invalid-window"; + }; + +function parseDesktopCapturerWindowHandle(sourceId?: string) { + if (!sourceId) { + return null; + } + + const match = sourceId.match(/^window:(\d+)/); + if (!match) { + return null; + } + + const handle = Number.parseInt(match[1], 10); + return Number.isFinite(handle) && handle > 0 ? handle : null; +} + +function isWindowCaptureSource(source: WindowsCaptureSourceLike | null | undefined) { + return source?.sourceType === "window" || source?.id?.startsWith("window:") === true; +} + export function resolveWindowsCaptureDisplay( source: WindowsCaptureSourceLike | null | undefined, allDisplays: WindowsCaptureDisplayLike[], @@ -40,3 +74,29 @@ export function resolveWindowsCaptureDisplay( bounds: matchedDisplay.bounds, }; } + +export function resolveWindowsCaptureTarget( + source: WindowsCaptureSourceLike | null | undefined, + allDisplays: WindowsCaptureDisplayLike[], + primaryDisplay: WindowsCaptureDisplayLike, +): ResolvedWindowsCaptureTarget { + if (isWindowCaptureSource(source)) { + const windowHandle = parseDesktopCapturerWindowHandle(source?.id); + if (windowHandle !== null) { + return { + kind: "window", + windowHandle, + }; + } + + return { + kind: "invalid-window", + }; + } + + const resolvedDisplay = resolveWindowsCaptureDisplay(source, allDisplays, primaryDisplay); + return { + kind: "display", + ...resolvedDisplay, + }; +} diff --git a/electron/windows.ts b/electron/windows.ts index dbdb4692..a5e6cd01 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -272,7 +272,9 @@ function setHudOverlayFallbackExpanded(expanded: boolean) { ipcMain.on("hud-overlay-set-ignore-mouse", (_event, ignore: boolean) => { if (hudOverlayWindow && !hudOverlayWindow.isDestroyed()) { if (!isHudOverlayMousePassthroughSupported()) { - setHudOverlayFallbackExpanded(!ignore); + if (process.platform !== "linux") { + setHudOverlayFallbackExpanded(!ignore); + } hudOverlayWindow.setIgnoreMouseEvents(false); return; } diff --git a/src/hooks/useScreenRecorder.test.ts b/src/hooks/useScreenRecorder.test.ts index 2c422c4f..00a8a7a9 100644 --- a/src/hooks/useScreenRecorder.test.ts +++ b/src/hooks/useScreenRecorder.test.ts @@ -4,6 +4,7 @@ import { createProcessedMicrophoneConstraints, normalizeBrowserMicrophoneProfile, resolveBrowserCaptureCursorPolicy, + shouldUseNativeWindowsCaptureForSource, } from "./useScreenRecorder"; type RecordingState = "inactive" | "recording" | "paused"; @@ -129,6 +130,16 @@ describe("resolveBrowserCaptureCursorPolicy", () => { }); }); +describe("shouldUseNativeWindowsCaptureForSource", () => { + it("keeps native Windows capture on screen sources", () => { + expect(shouldUseNativeWindowsCaptureForSource({ id: "screen:101:0" })).toBe(true); + }); + + it("routes window sources through browser capture", () => { + expect(shouldUseNativeWindowsCaptureForSource({ id: "window:123456:0" })).toBe(false); + }); +}); + function stopRecording( recorder: ReturnType, isNativeRecording: boolean, diff --git a/src/hooks/useScreenRecorder.ts b/src/hooks/useScreenRecorder.ts index cb34670c..4da2ae71 100644 --- a/src/hooks/useScreenRecorder.ts +++ b/src/hooks/useScreenRecorder.ts @@ -211,6 +211,12 @@ export function resolveBrowserCaptureCursorPolicy({ }; } +export function shouldUseNativeWindowsCaptureForSource( + source: Pick | null | undefined, +): boolean { + return source?.id?.startsWith("screen:") === true; +} + export function createProcessedMicrophoneConstraints( microphoneDeviceId?: string, profile: BrowserMicrophoneProfile = DEFAULT_BROWSER_MICROPHONE_PROFILE, @@ -1362,8 +1368,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { let nativeWindowsCaptureStartFailed = false; if ( platform === "win32" && - (selectedSource.id?.startsWith("screen:") || - selectedSource.id?.startsWith("window:")) && + shouldUseNativeWindowsCaptureForSource(selectedSource) && typeof window.electronAPI.isNativeWindowsCaptureAvailable === "function" ) { try { From 035d4a64bdacf0d4d3c5695b010a2c7cf062e657 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Tue, 26 May 2026 23:29:14 +0700 Subject: [PATCH 2/8] fix(timeline): make horizontal scroll easier --- .../video-editor/KeyboardShortcutsHelp.tsx | 4 +- src/components/video-editor/TutorialHelp.tsx | 4 +- .../timeline/hooks/useTimelineRange.test.ts | 57 ++++++++++++++++++ .../timeline/hooks/useTimelineRange.ts | 59 +++++++++++++++---- src/lib/shortcuts.ts | 2 +- 5 files changed, 111 insertions(+), 15 deletions(-) create mode 100644 src/components/video-editor/timeline/hooks/useTimelineRange.test.ts diff --git a/src/components/video-editor/KeyboardShortcutsHelp.tsx b/src/components/video-editor/KeyboardShortcutsHelp.tsx index 4c99ff57..4071d3ad 100644 --- a/src/components/video-editor/KeyboardShortcutsHelp.tsx +++ b/src/components/video-editor/KeyboardShortcutsHelp.tsx @@ -10,13 +10,13 @@ export function KeyboardShortcutsHelp() { const t = useScopedT("editor"); const [scrollLabels, setScrollLabels] = useState({ - pan: "Shift + Ctrl + Scroll", + pan: "Shift + Scroll", zoom: "Ctrl + Scroll", }); useEffect(() => { Promise.all([ - formatShortcut(["shift", "mod", "Scroll"]), + formatShortcut(["shift", "Scroll"]), formatShortcut(["mod", "Scroll"]), ]).then(([pan, zoom]) => setScrollLabels({ pan, zoom })); }, []); diff --git a/src/components/video-editor/TutorialHelp.tsx b/src/components/video-editor/TutorialHelp.tsx index b773683f..a09e5c88 100644 --- a/src/components/video-editor/TutorialHelp.tsx +++ b/src/components/video-editor/TutorialHelp.tsx @@ -149,13 +149,13 @@ export function KeyboardShortcutsDialog({ const { shortcuts, isMac, openConfig } = useShortcuts(); const t = useScopedT("editor"); const [scrollLabels, setScrollLabels] = useState({ - pan: "Shift + Ctrl + Scroll", + pan: "Shift + Scroll", zoom: "Ctrl + Scroll", }); useEffect(() => { Promise.all([ - formatShortcut(["shift", "mod", "Scroll"]), + formatShortcut(["shift", "Scroll"]), formatShortcut(["mod", "Scroll"]), ]).then(([pan, zoom]) => setScrollLabels({ pan, zoom })); }, []); diff --git a/src/components/video-editor/timeline/hooks/useTimelineRange.test.ts b/src/components/video-editor/timeline/hooks/useTimelineRange.test.ts new file mode 100644 index 00000000..bff6a651 --- /dev/null +++ b/src/components/video-editor/timeline/hooks/useTimelineRange.test.ts @@ -0,0 +1,57 @@ +import { describe, expect, it } from "vitest"; + +import { resolveTimelineWheelPanDeltaPx } from "./useTimelineRange"; + +describe("resolveTimelineWheelPanDeltaPx", () => { + it("uses trackpad horizontal wheel movement for timeline panning", () => { + expect( + resolveTimelineWheelPanDeltaPx({ + deltaX: 24, + deltaY: 0, + deltaMode: 0, + }), + ).toBe(24); + }); + + it("uses shifted vertical wheel movement for timeline panning", () => { + expect( + resolveTimelineWheelPanDeltaPx({ + deltaX: 0, + deltaY: 3, + deltaMode: 1, + shiftKey: true, + }), + ).toBe(48); + }); + + it("keeps ctrl wheel available for timeline zoom unless shift is also held", () => { + expect( + resolveTimelineWheelPanDeltaPx({ + deltaX: 0, + deltaY: 3, + deltaMode: 1, + ctrlKey: true, + }), + ).toBe(0); + expect( + resolveTimelineWheelPanDeltaPx({ + deltaX: 0, + deltaY: 3, + deltaMode: 1, + ctrlKey: true, + shiftKey: true, + }), + ).toBe(48); + }); + + it("uses regular wheel movement when the timeline has no vertical overflow", () => { + expect( + resolveTimelineWheelPanDeltaPx({ + deltaX: 0, + deltaY: 20, + deltaMode: 0, + canScrollVertically: false, + }), + ).toBe(20); + }); +}); diff --git a/src/components/video-editor/timeline/hooks/useTimelineRange.ts b/src/components/video-editor/timeline/hooks/useTimelineRange.ts index e3d5ff59..c72b2fd9 100644 --- a/src/components/video-editor/timeline/hooks/useTimelineRange.ts +++ b/src/components/video-editor/timeline/hooks/useTimelineRange.ts @@ -7,6 +7,40 @@ interface UseTimelineRangeParams { timelineContainerRef: RefObject; } +export interface TimelineWheelPanDeltaInput { + deltaX: number; + deltaY: number; + deltaMode: number; + shiftKey?: boolean; + ctrlKey?: boolean; + metaKey?: boolean; + canScrollVertically?: boolean; +} + +export function resolveTimelineWheelPanDeltaPx({ + deltaX, + deltaY, + deltaMode, + shiftKey = false, + ctrlKey = false, + metaKey = false, + canScrollVertically = true, +}: TimelineWheelPanDeltaInput) { + if ((ctrlKey || metaKey) && !shiftKey) { + return 0; + } + + if (Math.abs(deltaX) > 0) { + return normalizeWheelDeltaToPixels(deltaX, deltaMode); + } + + if ((shiftKey || !canScrollVertically) && Math.abs(deltaY) > 0) { + return normalizeWheelDeltaToPixels(deltaY, deltaMode); + } + + return 0; +} + export function useTimelineRange({ totalMs, timelineContainerRef }: UseTimelineRangeParams) { const [range, setRange] = useState(() => createInitialRange(totalMs)); @@ -42,29 +76,34 @@ export function useTimelineRange({ totalMs, timelineContainerRef }: UseTimelineR const handleTimelineWheel = useCallback( (event: WheelEvent) => { - if (event.ctrlKey || event.metaKey || totalMs <= 0) { + if (((event.ctrlKey || event.metaKey) && !event.shiftKey) || totalMs <= 0) { return; } - const rawHorizontalDelta = - Math.abs(event.deltaX) > 0 - ? event.deltaX - : event.shiftKey && Math.abs(event.deltaY) > 0 - ? event.deltaY - : 0; + const container = timelineContainerRef.current; + const horizontalDeltaPx = resolveTimelineWheelPanDeltaPx({ + deltaX: event.deltaX, + deltaY: event.deltaY, + deltaMode: event.deltaMode, + shiftKey: event.shiftKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + canScrollVertically: container + ? container.scrollHeight > container.clientHeight + 1 + : true, + }); - if (rawHorizontalDelta === 0) { + if (horizontalDeltaPx === 0) { return; } - const containerWidth = timelineContainerRef.current?.clientWidth ?? 0; + const containerWidth = container?.clientWidth ?? 0; const visibleRangeMs = clampedRange.end - clampedRange.start; if (containerWidth <= 0 || visibleRangeMs <= 0) { return; } event.preventDefault(); - const horizontalDeltaPx = normalizeWheelDeltaToPixels(rawHorizontalDelta, event.deltaMode); const deltaMs = (horizontalDeltaPx / containerWidth) * visibleRangeMs; panTimelineRange(deltaMs); }, diff --git a/src/lib/shortcuts.ts b/src/lib/shortcuts.ts index d2d9828c..d4384693 100644 --- a/src/lib/shortcuts.ts +++ b/src/lib/shortcuts.ts @@ -37,7 +37,7 @@ export const FIXED_SHORTCUTS: FixedShortcut[] = [ display: "Del / ⌫", bindings: [{ key: "delete" }, { key: "backspace" }], }, - { label: "Pan Timeline", display: "Shift + Ctrl + Scroll", bindings: [] }, + { label: "Pan Timeline", display: "Shift + Scroll", bindings: [] }, { label: "Zoom Timeline", display: "Ctrl + Scroll", bindings: [] }, ]; From fe828433adf7703aca96566396bdcd65bbf000b5 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Wed, 27 May 2026 18:12:21 +0700 Subject: [PATCH 3/8] fix(recording): stabilize capture quality and CUDA export canvas --- electron/ipc/export/native-video.test.ts | 14 +- electron/ipc/export/native-video.ts | 8 +- electron/ipc/register/settings.ts | 350 ++++++++++-------- electron/main.ts | 31 +- .../bin/win32-x64/helpers-manifest.json | 66 ++-- .../recordly-nvidia-cuda-compositor.exe | Bin 459776 -> 460288 bytes .../run-mp4-pipeline.mjs | 16 +- .../native/nvidia-cuda-compositor/src/main.cu | 32 +- electron/windows.ts | 100 +++-- scripts/build-nvidia-cuda-compositor.mjs | 106 +++++- src/components/launch/LaunchWindow.tsx | 235 ++++++------ .../hooks/useLaunchHudInteractionState.ts | 47 +-- src/components/video-editor/VideoEditor.tsx | 43 ++- .../timeline/zoomSuggestionUtils.test.ts | 62 ++-- .../timeline/zoomSuggestionUtils.ts | 20 + src/hooks/recordingMimeType.test.ts | 27 +- src/hooks/recordingMimeType.ts | 10 +- src/hooks/useScreenRecorder.test.ts | 43 ++- src/hooks/useScreenRecorder.ts | 164 +++++--- src/lib/exporter/exportBitrate.test.ts | 22 ++ src/lib/exporter/exportBitrate.ts | 6 + 21 files changed, 882 insertions(+), 520 deletions(-) diff --git a/electron/ipc/export/native-video.test.ts b/electron/ipc/export/native-video.test.ts index 1c82a8d4..ee31dcdd 100644 --- a/electron/ipc/export/native-video.test.ts +++ b/electron/ipc/export/native-video.test.ts @@ -406,7 +406,9 @@ describe("getNativeExportCapabilities", () => { expect(capabilities.nvidiaCuda.available).toBe(process.platform === "win32"); expect(capabilities.nvidiaCuda.hasWrapper).toBe(process.platform === "win32"); - expect(capabilities.nvidiaCuda.hasNvidiaGpu).toBe(process.platform === "win32" ? true : null); + expect(capabilities.nvidiaCuda.hasNvidiaGpu).toBe( + process.platform === "win32" ? true : null, + ); }); }); @@ -600,6 +602,16 @@ describe("resolveExperimentalNvidiaCudaExportScriptPath", () => { }); describe("buildExperimentalNvidiaCudaStaticLayoutArgs", () => { + it("passes output canvas dimensions to the CUDA wrapper", () => { + const args = buildExperimentalNvidiaCudaStaticLayoutArgs( + createNvidiaCudaSkipOptions({ width: 1020, height: 572 }), + "output.mp4", + "work", + ); + + expect(args).toEqual(expect.arrayContaining(["--width", "1020", "--height", "572"])); + }); + it("keeps explicit copy-source CUDA audio inline by default", () => { const args = buildExperimentalNvidiaCudaStaticLayoutArgs( createNvidiaCudaSkipOptions({ diff --git a/electron/ipc/export/native-video.ts b/electron/ipc/export/native-video.ts index ad884651..16b2993e 100644 --- a/electron/ipc/export/native-video.ts +++ b/electron/ipc/export/native-video.ts @@ -1990,9 +1990,7 @@ function isNvidiaCudaForceVideoOnlyEnabled() { return process.env[NVIDIA_CUDA_FORCE_VIDEO_ONLY_ENV] === "1"; } -export function getNvidiaCudaAutoStallTimeoutMs( - autoCandidateActive = false, -) { +export function getNvidiaCudaAutoStallTimeoutMs(autoCandidateActive = false) { if (!autoCandidateActive && !isExplicitNvidiaCudaExportEnabled()) { return null; } @@ -2664,6 +2662,10 @@ export function buildExperimentalNvidiaCudaStaticLayoutArgs( outputPath, "--work-dir", workDir, + "--width", + String(options.width), + "--height", + String(options.height), "--fps", String(Math.max(1, Math.round(options.frameRate))), "--bitrate-mbps", diff --git a/electron/ipc/register/settings.ts b/electron/ipc/register/settings.ts index cecabb5f..e84f6317 100644 --- a/electron/ipc/register/settings.ts +++ b/electron/ipc/register/settings.ts @@ -22,7 +22,7 @@ import { import { parseJsonWithByteOrderMark } from "../utils"; const BROWSER_MICROPHONE_PROFILE_ENV = "RECORDLY_BROWSER_MIC_PROFILE"; -const DEFAULT_BROWSER_MICROPHONE_PROFILE = "no-agc"; +const DEFAULT_BROWSER_MICROPHONE_PROFILE = "processed"; const BROWSER_MICROPHONE_PROFILES = new Set([ "processed", "no-agc", @@ -60,14 +60,18 @@ function writeAppSettingsStore(store: Record) { writeFileSync(APP_SETTINGS_FILE, JSON.stringify(store, null, 2), "utf-8"); } -export function registerSettingsHandlers() { - ipcMain.handle('app:getVersion', () => { - return app.getVersion() - }) +function hasAppSetting(store: Record, key: string): boolean { + return Reflect.getOwnPropertyDescriptor(store, key) !== undefined; +} - ipcMain.handle('get-platform', () => { - return process.platform; - }); +export function registerSettingsHandlers() { + ipcMain.handle("app:getVersion", () => { + return app.getVersion(); + }); + + ipcMain.handle("get-platform", () => { + return process.platform; + }); ipcMain.on("app-settings:get", (event, key: unknown) => { try { @@ -79,7 +83,7 @@ export function registerSettingsHandlers() { const store = readAppSettingsStore(); event.returnValue = { success: true, - value: Object.prototype.hasOwnProperty.call(store, key) ? store[key] : null, + value: hasAppSetting(store, key) ? store[key] : null, }; } catch (error) { console.error("Failed to read app setting:", error); @@ -104,173 +108,201 @@ export function registerSettingsHandlers() { } }); - // --------------------------------------------------------------------------- - // Cursor hiding for the browser-capture fallback. - // The IPC promise resolves only after the cursor hide attempt completes. - // --------------------------------------------------------------------------- - ipcMain.handle('hide-cursor', () => { - if (process.platform !== 'win32') { - return { success: true } - } + // --------------------------------------------------------------------------- + // Cursor hiding for the browser-capture fallback. + // The IPC promise resolves only after the cursor hide attempt completes. + // --------------------------------------------------------------------------- + ipcMain.handle("hide-cursor", () => { + if (process.platform !== "win32") { + return { success: true }; + } - return { success: hideCursor() } - }) + return { success: hideCursor() }; + }); - ipcMain.handle('get-shortcuts', async () => { - try { - const data = await fs.readFile(SHORTCUTS_FILE, 'utf-8'); - return parseJsonWithByteOrderMark(data); - } catch { - return null; - } - }); + ipcMain.handle("get-shortcuts", async () => { + try { + const data = await fs.readFile(SHORTCUTS_FILE, "utf-8"); + return parseJsonWithByteOrderMark(data); + } catch { + return null; + } + }); - ipcMain.handle('save-shortcuts', async (_, shortcuts: unknown) => { - try { - await fs.writeFile(SHORTCUTS_FILE, JSON.stringify(shortcuts, null, 2), 'utf-8'); - return { success: true }; - } catch (error) { - console.error('Failed to save shortcuts:', error); - return { success: false, error: String(error) }; - } - }); + ipcMain.handle("save-shortcuts", async (_, shortcuts: unknown) => { + try { + await fs.writeFile(SHORTCUTS_FILE, JSON.stringify(shortcuts, null, 2), "utf-8"); + return { success: true }; + } catch (error) { + console.error("Failed to save shortcuts:", error); + return { success: false, error: String(error) }; + } + }); - // --------------------------------------------------------------------------- - // Countdown timer before recording - // --------------------------------------------------------------------------- - ipcMain.handle('get-recording-preferences', async () => { - try { - const content = await fs.readFile(RECORDINGS_SETTINGS_FILE, 'utf-8') - const parsed = parseJsonWithByteOrderMark>(content) - return { - success: true, - microphoneEnabled: parsed.microphoneEnabled === true, - microphoneDeviceId: typeof parsed.microphoneDeviceId === 'string' ? parsed.microphoneDeviceId : undefined, - systemAudioEnabled: parsed.systemAudioEnabled === true, - } - } catch { - return { success: true, microphoneEnabled: false, microphoneDeviceId: undefined, systemAudioEnabled: false } - } - }) + // --------------------------------------------------------------------------- + // Countdown timer before recording + // --------------------------------------------------------------------------- + ipcMain.handle("get-recording-preferences", async () => { + try { + const content = await fs.readFile(RECORDINGS_SETTINGS_FILE, "utf-8"); + const parsed = parseJsonWithByteOrderMark>(content); + return { + success: true, + microphoneEnabled: parsed.microphoneEnabled === true, + microphoneDeviceId: + typeof parsed.microphoneDeviceId === "string" + ? parsed.microphoneDeviceId + : undefined, + systemAudioEnabled: parsed.systemAudioEnabled === true, + }; + } catch { + return { + success: true, + microphoneEnabled: false, + microphoneDeviceId: undefined, + systemAudioEnabled: false, + }; + } + }); - ipcMain.handle('get-recording-audio-lab-config', () => { - return getBrowserMicrophoneProfileFromEnv() - }) + ipcMain.handle("get-recording-audio-lab-config", () => { + return getBrowserMicrophoneProfileFromEnv(); + }); - ipcMain.handle('set-recording-preferences', async (_, prefs: { microphoneEnabled?: boolean; microphoneDeviceId?: string; systemAudioEnabled?: boolean }) => { - try { - let existing: Record = {} - try { - const content = await fs.readFile(RECORDINGS_SETTINGS_FILE, 'utf-8') - existing = parseJsonWithByteOrderMark>(content) - } catch { - // file doesn't exist yet - } - const merged = { ...existing, ...prefs } - await fs.writeFile(RECORDINGS_SETTINGS_FILE, JSON.stringify(merged, null, 2), 'utf-8') - return { success: true } - } catch (error) { - console.error('Failed to save recording preferences:', error) - return { success: false, error: String(error) } - } - }) + ipcMain.handle( + "set-recording-preferences", + async ( + _, + prefs: { + microphoneEnabled?: boolean; + microphoneDeviceId?: string; + systemAudioEnabled?: boolean; + }, + ) => { + try { + let existing: Record = {}; + try { + const content = await fs.readFile(RECORDINGS_SETTINGS_FILE, "utf-8"); + existing = parseJsonWithByteOrderMark>(content); + } catch { + // file doesn't exist yet + } + const merged = { ...existing, ...prefs }; + await fs.writeFile( + RECORDINGS_SETTINGS_FILE, + JSON.stringify(merged, null, 2), + "utf-8", + ); + return { success: true }; + } catch (error) { + console.error("Failed to save recording preferences:", error); + return { success: false, error: String(error) }; + } + }, + ); - ipcMain.handle('get-countdown-delay', async () => { - try { - const content = await fs.readFile(COUNTDOWN_SETTINGS_FILE, 'utf-8') - const parsed = parseJsonWithByteOrderMark<{ delay?: number }>(content) - return { success: true, delay: parsed.delay ?? 3 } - } catch { - return { success: true, delay: 3 } - } - }) + ipcMain.handle("get-countdown-delay", async () => { + try { + const content = await fs.readFile(COUNTDOWN_SETTINGS_FILE, "utf-8"); + const parsed = parseJsonWithByteOrderMark<{ delay?: number }>(content); + return { success: true, delay: parsed.delay ?? 3 }; + } catch { + return { success: true, delay: 3 }; + } + }); - ipcMain.handle('set-countdown-delay', async (_, delay: number) => { - try { - await fs.writeFile(COUNTDOWN_SETTINGS_FILE, JSON.stringify({ delay }, null, 2), 'utf-8') - return { success: true } - } catch (error) { - console.error('Failed to save countdown delay:', error) - return { success: false, error: String(error) } - } - }) + ipcMain.handle("set-countdown-delay", async (_, delay: number) => { + try { + await fs.writeFile( + COUNTDOWN_SETTINGS_FILE, + JSON.stringify({ delay }, null, 2), + "utf-8", + ); + return { success: true }; + } catch (error) { + console.error("Failed to save countdown delay:", error); + return { success: false, error: String(error) }; + } + }); - ipcMain.handle('start-countdown', async (_, seconds: number) => { - if (countdownInProgress) { - return { success: false, error: 'Countdown already in progress' } - } + ipcMain.handle("start-countdown", async (_, seconds: number) => { + if (countdownInProgress) { + return { success: false, error: "Countdown already in progress" }; + } - setCountdownInProgress(true) - setCountdownCancelled(false) - setCountdownRemaining(seconds) + setCountdownInProgress(true); + setCountdownCancelled(false); + setCountdownRemaining(seconds); - const countdownWin = createCountdownWindow() + const countdownWin = createCountdownWindow(); - if (countdownWin.webContents.isLoadingMainFrame()) { - await new Promise((resolve) => { - countdownWin.webContents.once('did-finish-load', () => { - resolve() - }) - }) - } + if (countdownWin.webContents.isLoadingMainFrame()) { + await new Promise((resolve) => { + countdownWin.webContents.once("did-finish-load", () => { + resolve(); + }); + }); + } - return new Promise<{ success: boolean; cancelled?: boolean }>((resolve) => { - let remaining = seconds - setCountdownRemaining(remaining) + return new Promise<{ success: boolean; cancelled?: boolean }>((resolve) => { + let remaining = seconds; + setCountdownRemaining(remaining); - countdownWin.webContents.send('countdown-tick', remaining) + countdownWin.webContents.send("countdown-tick", remaining); - setCountdownTimer(setInterval(() => { - if (countdownCancelled) { - if (countdownTimer) { - clearInterval(countdownTimer) - setCountdownTimer(null) - } - closeCountdownWindow() - setCountdownInProgress(false) - setCountdownRemaining(null) - resolve({ success: false, cancelled: true }) - return - } + setCountdownTimer( + setInterval(() => { + if (countdownCancelled) { + if (countdownTimer) { + clearInterval(countdownTimer); + setCountdownTimer(null); + } + closeCountdownWindow(); + setCountdownInProgress(false); + setCountdownRemaining(null); + resolve({ success: false, cancelled: true }); + return; + } - remaining-- - setCountdownRemaining(remaining) + remaining--; + setCountdownRemaining(remaining); - if (remaining <= 0) { - if (countdownTimer) { - clearInterval(countdownTimer) - setCountdownTimer(null) - } - closeCountdownWindow() - setCountdownInProgress(false) - setCountdownRemaining(null) - resolve({ success: true }) - } else { - const win = getCountdownWindow() - if (win && !win.isDestroyed()) { - win.webContents.send('countdown-tick', remaining) - } - } - }, 1000)) - }) - }) + if (remaining <= 0) { + if (countdownTimer) { + clearInterval(countdownTimer); + setCountdownTimer(null); + } + closeCountdownWindow(); + setCountdownInProgress(false); + setCountdownRemaining(null); + resolve({ success: true }); + } else { + const win = getCountdownWindow(); + if (win && !win.isDestroyed()) { + win.webContents.send("countdown-tick", remaining); + } + } + }, 1000), + ); + }); + }); - ipcMain.handle('cancel-countdown', () => { - setCountdownCancelled(true) - setCountdownInProgress(false) - setCountdownRemaining(null) - if (countdownTimer) { - clearInterval(countdownTimer) - setCountdownTimer(null) - } - closeCountdownWindow() - return { success: true } - }) + ipcMain.handle("cancel-countdown", () => { + setCountdownCancelled(true); + setCountdownInProgress(false); + setCountdownRemaining(null); + if (countdownTimer) { + clearInterval(countdownTimer); + setCountdownTimer(null); + } + closeCountdownWindow(); + return { success: true }; + }); - ipcMain.handle('get-active-countdown', () => { - return { - success: true, - seconds: countdownInProgress ? countdownRemaining : null, - } - }) + ipcMain.handle("get-active-countdown", () => { + return { + success: true, + seconds: countdownInProgress ? countdownRemaining : null, + }; + }); } diff --git a/electron/main.ts b/electron/main.ts index 0a50b6f9..ed05ffeb 100644 --- a/electron/main.ts +++ b/electron/main.ts @@ -49,6 +49,8 @@ import { getUpdateToastWindow, hideUpdateToastWindow, isHudOverlayMousePassthroughSupported, + reassertHudOverlayMousePassthrough as reassertHudOverlayMouseState, + setHudOverlayRecordingActive, showUpdateToastWindow, } from "./windows"; @@ -337,32 +339,6 @@ function focusOrCreateMainWindow() { } } -/** - * On Windows 10, focus changes and native notifications can break - * {@link BrowserWindow.setIgnoreMouseEvents} forwarding on the transparent HUD - * overlay, causing it to become permanently click-through. Call this after any - * operation that may alter focus or z-order so that hover detection keeps working. - */ -function reassertHudOverlayMouseState() { - if (process.platform !== "win32" || !isHudOverlayMousePassthroughSupported()) { - return; - } - - const hud = getHudOverlayWindow(); - if (!hud) { - return; - } - - // Toggle off then back on so the native WS_EX_TRANSPARENT flag is fully - // re-initialised rather than merely re-asserted in a potentially broken state. - hud.setIgnoreMouseEvents(false); - setTimeout(() => { - if (!hud.isDestroyed()) { - hud.setIgnoreMouseEvents(true, { forward: true }); - } - }, 50); -} - function isEditorWindow(window: BrowserWindow) { return window.webContents.getURL().includes("windowType=editor"); } @@ -803,7 +779,7 @@ function createEditorWindowWrapper() { const previousWindow = mainWindow; if (previousWindow && !previousWindow.isDestroyed()) { const closingEditorWindow = isEditorWindow(previousWindow); - + if (closingEditorWindow) { closeEditorWindowBypassingUnsavedPrompt(previousWindow); } else { @@ -985,6 +961,7 @@ app.whenReady().then(async () => { () => sourceSelectorWindow, (recording: boolean, sourceName: string) => { selectedSourceName = sourceName; + setHudOverlayRecordingActive(recording); if (!tray) createTray(); updateTrayMenu(recording); if (recording) { diff --git a/electron/native/bin/win32-x64/helpers-manifest.json b/electron/native/bin/win32-x64/helpers-manifest.json index 2df0f4e5..3a9f7dfa 100644 --- a/electron/native/bin/win32-x64/helpers-manifest.json +++ b/electron/native/bin/win32-x64/helpers-manifest.json @@ -1,35 +1,35 @@ { - "version": 1, - "platform": "win32", - "arch": "x64", - "helpers": { - "wgc-capture": { - "binaryName": "wgc-capture.exe", - "binarySha256": "298b41f371c3881046061048b466e12ed70dd93fa761bade2fd57d1ccddf3cb9", - "sourceDir": "electron/native/wgc-capture", - "sourceFingerprint": "6ee457080c27dc939ff4b61965f86b6d73995e40200440a1dc44865f9708d39f", - "updatedAt": "2026-05-24T19:49:15.077Z" - }, - "cursor-monitor": { - "binaryName": "cursor-monitor.exe", - "binarySha256": "6ae6d91103b6e891a851e8ea5791e1c1f9aaab700134c18bc4c46cfffd7fdd12", - "sourceDir": "electron/native/cursor-monitor", - "sourceFingerprint": "6ad1b8b50bb336f2a48937b06f5ec56d90b6ab4a3e56a4bca278cf67a5d3e52e", - "updatedAt": "2026-05-07T15:22:18.173Z" - }, - "recordly-gpu-export": { - "binaryName": "recordly-gpu-export.exe", - "binarySha256": "4cb3a293fd36f718af55906820d9b3fd78babc855888c2e248f0b918ec1aff3c", - "sourceDir": "electron/native/gpu-export-probe", - "sourceFingerprint": "743b386a5f1bbcc99cec5465c3de228d2b045061dead31dfcbf25cf6a1e61de5", - "updatedAt": "2026-05-07T20:13:48.585Z" - }, - "recordly-nvidia-cuda-compositor": { - "binaryName": "recordly-nvidia-cuda-compositor.exe", - "binarySha256": "a787531c07142de7c292d1726e0339c97dbce5073d9a0853d539a725265fd945", - "sourceDir": "electron/native/nvidia-cuda-compositor", - "sourceFingerprint": "528b599e9d576d81ec087d0d4dc93a79af1bbf30fdb969f44f773bef90146135", - "updatedAt": "2026-05-07T20:14:13.794Z" - } - } + "version": 1, + "platform": "win32", + "arch": "x64", + "helpers": { + "wgc-capture": { + "binaryName": "wgc-capture.exe", + "binarySha256": "298b41f371c3881046061048b466e12ed70dd93fa761bade2fd57d1ccddf3cb9", + "sourceDir": "electron/native/wgc-capture", + "sourceFingerprint": "6ee457080c27dc939ff4b61965f86b6d73995e40200440a1dc44865f9708d39f", + "updatedAt": "2026-05-24T19:49:15.077Z" + }, + "cursor-monitor": { + "binaryName": "cursor-monitor.exe", + "binarySha256": "6ae6d91103b6e891a851e8ea5791e1c1f9aaab700134c18bc4c46cfffd7fdd12", + "sourceDir": "electron/native/cursor-monitor", + "sourceFingerprint": "6ad1b8b50bb336f2a48937b06f5ec56d90b6ab4a3e56a4bca278cf67a5d3e52e", + "updatedAt": "2026-05-07T15:22:18.173Z" + }, + "recordly-gpu-export": { + "binaryName": "recordly-gpu-export.exe", + "binarySha256": "4cb3a293fd36f718af55906820d9b3fd78babc855888c2e248f0b918ec1aff3c", + "sourceDir": "electron/native/gpu-export-probe", + "sourceFingerprint": "743b386a5f1bbcc99cec5465c3de228d2b045061dead31dfcbf25cf6a1e61de5", + "updatedAt": "2026-05-07T20:13:48.585Z" + }, + "recordly-nvidia-cuda-compositor": { + "binaryName": "recordly-nvidia-cuda-compositor.exe", + "binarySha256": "e9e062d1177075ac36eecf97e5934722a7fb782809e29ab60da54b396feb95b9", + "sourceDir": "electron/native/nvidia-cuda-compositor", + "sourceFingerprint": "021ea1abd83606b589f694ddedb3af8035e2e08e2e130cf4fff6d6a3f7d64833", + "updatedAt": "2026-05-27T10:56:40.171Z" + } + } } diff --git a/electron/native/bin/win32-x64/recordly-nvidia-cuda-compositor.exe b/electron/native/bin/win32-x64/recordly-nvidia-cuda-compositor.exe index 0fd5f273232f39d5080fe19b034b66e9bbd3a056..3e6ebd579db4191476aca1f51d21a5371fc595df 100644 GIT binary patch delta 130949 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 0 ? `;[bg_scaled]boxblur=luma_radius=${safeBlurPx}:luma_power=1:chroma_radius=${safeBlurPx}:chroma_power=1:alpha_radius=${safeBlurPx}:alpha_power=1[bg]` @@ -895,7 +895,7 @@ function createBackgroundFilter(videoInfo, shadowOptions, blurPx = 0) { "-f", "lavfi", "-i", - `color=c=black@0.0:s=${videoInfo.width}x${videoInfo.height}:d=1`, + `color=c=black@0.0:s=${outputSize.width}x${outputSize.height}:d=1`, "-filter_complex", `${scaled}${blurFilter};${shadow};[bg][shadow]overlay=format=auto,format=nv12[out]`, "-map", @@ -930,6 +930,8 @@ const inputPath = resolve(getArg("--input")); const outputPath = resolve( getArg("--output", join(scriptDir, "recordly-nvdec-nvenc-mp4-output.mp4")), ); +const requestedOutputWidth = Math.round(getNumberArg("--width", 0)); +const requestedOutputHeight = Math.round(getNumberArg("--height", 0)); const fps = Math.round(getNumberArg("--fps", 30)); const bitrateMbps = Math.round(getNumberArg("--bitrate-mbps", 18)); const encodingMode = getArg("--encoding-mode", "balanced"); @@ -1050,6 +1052,8 @@ const sourcePtsPath = join(workDir, `${baseName}.source-pts.csv`); const videoInfo = getVideoInfo(inputPath); const webcamInfo = webcamInput ? getVideoInfo(webcamInput) : null; +const outputWidth = requestedOutputWidth > 0 ? requestedOutputWidth : videoInfo.width; +const outputHeight = requestedOutputHeight > 0 ? requestedOutputHeight : videoInfo.height; const timelineSegments = readTimelineSegments(timelineMap); const timelineOutputDurationSec = timelineSegments.length ? Math.max(...timelineSegments.map((segment) => segment.outputEndMs)) / 1000 @@ -1105,7 +1109,7 @@ let webcamSourceWindowFrames = webcamInfo : 0; const backgroundNv12Path = backgroundImage ? generatedBackgroundNv12Path : backgroundNv12; const backgroundFilter = createBackgroundFilter( - videoInfo, + { width: outputWidth, height: outputHeight }, shouldBakeStaticShadow ? { x: contentX, @@ -1261,6 +1265,10 @@ const encodeArgs = [ annexBPath, "--output", encodedPath, + "--width", + String(outputWidth), + "--height", + String(outputHeight), "--fps", String(fps), "--input-frames", diff --git a/electron/native/nvidia-cuda-compositor/src/main.cu b/electron/native/nvidia-cuda-compositor/src/main.cu index 6adcbcf7..8c5ea9dc 100644 --- a/electron/native/nvidia-cuda-compositor/src/main.cu +++ b/electron/native/nvidia-cuda-compositor/src/main.cu @@ -39,6 +39,8 @@ struct Options { std::string sourcePtsPath; std::string timelineMapPath; std::vector timelineSegments; + int width = 0; + int height = 0; int fps = 30; int maxFrames = 0; int inputFrames = 0; @@ -167,6 +169,10 @@ Options parseOptions(int argc, char** argv) { options.outputPath = requireValue("--output"); } else if (arg == "--source-pts") { options.sourcePtsPath = requireValue("--source-pts"); + } else if (arg == "--width") { + options.width = parsePositiveInt(requireValue("--width"), "--width"); + } else if (arg == "--height") { + options.height = parsePositiveInt(requireValue("--height"), "--height"); } else if (arg == "--timeline-map") { options.timelineMapPath = requireValue("--timeline-map"); } else if (arg == "--fps") { @@ -274,7 +280,7 @@ Options parseOptions(int argc, char** argv) { options.zoomSamplesPath = requireValue("--zoom-samples"); } else if (arg == "--help") { std::cout << "Usage: recordly-nvidia-cuda-compositor --input input.annexb.h264 " - "[--output out.h264] [--source-pts source-pts.csv] [--fps 30] " + "[--output out.h264] [--source-pts source-pts.csv] [--width N --height N] [--fps 30] " "[--max-frames N] [--bitrate-mbps N] [--encoding-mode fast|balanced|quality] " "[--post-select] [--callback-encode] [--stream-sync] [--prewarm-ms N] [--chunk-mb N] " "[--content-x N --content-y N --content-width N --content-height N --radius N] " @@ -320,6 +326,14 @@ bool hasWebcamOverlay(const Options& options) { return (!options.webcamNv12Path.empty() || !options.webcamAnnexbPath.empty()) && options.webcamSize > 0; } +int outputWidthForSource(const Options& options, int sourceWidth) { + return options.width > 0 ? options.width : sourceWidth; +} + +int outputHeightForSource(const Options& options, int sourceHeight) { + return options.height > 0 ? options.height : sourceHeight; +} + std::vector loadFramePts(const std::string& path) { std::vector timestamps; if (path.empty()) { @@ -2866,8 +2880,8 @@ void encodeMappedDisplayFrame( if (!*state->sink) { *state->sink = std::make_unique( state->context, - width, - height, + outputWidthForSource(*state->options, width), + outputHeightForSource(*state->options, height), state->options->fps, state->bitrate, state->options->outputPath, @@ -3106,8 +3120,8 @@ int main(int argc, char** argv) { if (!sink) { sink = std::make_unique( context, - decoder->GetWidth(), - decoder->GetHeight(), + outputWidthForSource(options, decoder->GetWidth()), + outputHeightForSource(options, decoder->GetHeight()), options.fps, bitrate, options.outputPath, @@ -3152,8 +3166,8 @@ int main(int argc, char** argv) { if (!sink) { sink = std::make_unique( context, - decoder->GetWidth(), - decoder->GetHeight(), + outputWidthForSource(options, decoder->GetWidth()), + outputHeightForSource(options, decoder->GetHeight()), options.fps, bitrate, options.outputPath, @@ -3225,8 +3239,8 @@ int main(int argc, char** argv) { << "\"syncMode\":\"" << (options.streamSync ? "stream" : "device") << "\"," << "\"prewarmMs\":" << options.prewarmMs << "," << "\"chunkMb\":" << options.chunkMb << "," - << "\"width\":" << decoder->GetWidth() << "," - << "\"height\":" << decoder->GetHeight() << "," + << "\"width\":" << outputWidthForSource(options, decoder->GetWidth()) << "," + << "\"height\":" << outputHeightForSource(options, decoder->GetHeight()) << "," << "\"fps\":" << options.fps << "," << "\"encodingMode\":\"" << options.encodingMode << "\"," << "\"staticLayout\":" << (hasStaticLayout(options) ? "true" : "false") << "," diff --git a/electron/windows.ts b/electron/windows.ts index a5e6cd01..982fa677 100644 --- a/electron/windows.ts +++ b/electron/windows.ts @@ -5,10 +5,7 @@ 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 } from "./hudOverlayBounds"; import { getPackagedRendererBaseUrl } from "./rendererServer"; const electronWindowsDir = path.dirname(fileURLToPath(import.meta.url)); @@ -17,7 +14,8 @@ const nodeRequire = createRequire(import.meta.url); const APP_ROOT = path.join(electronWindowsDir, ".."); const VITE_DEV_SERVER_URL = process.env["VITE_DEV_SERVER_URL"]; const RENDERER_DIST = path.join(APP_ROOT, "dist"); -const WINDOW_ICON_FILENAME = process.platform === "darwin" ? "recordlymac-512.png" : "recordly-512.png"; +const WINDOW_ICON_FILENAME = + process.platform === "darwin" ? "recordlymac-512.png" : "recordly-512.png"; const WINDOW_ICON_PATH = path.join( process.env.VITE_PUBLIC || RENDERER_DIST, "app-icons", @@ -28,6 +26,9 @@ let hudOverlayWindow: BrowserWindow | null = null; let hudOverlayHiddenFromCapture = true; let hudOverlayCaptureProtectionLoaded = false; let hudOverlayFallbackExpanded = false; +let hudOverlayIgnoringMouse = true; +let hudOverlayMouseReassertTimer: NodeJS.Timeout | null = null; +let hudOverlayRecordingActive = false; let countdownWindow: BrowserWindow | null = null; let updateToastWindow: BrowserWindow | null = null; @@ -190,7 +191,7 @@ function getHudOverlayBounds() { const { workArea } = getHudOverlayDisplay(); return getHudOverlayWindowBounds( workArea, - isHudOverlayMousePassthroughSupported(), + isHudOverlayMousePassthroughSupported() && !hudOverlayRecordingActive, hudOverlayFallbackExpanded, ); } @@ -247,6 +248,11 @@ function positionUpdateToastWindow() { } function setHudOverlayFallbackExpanded(expanded: boolean) { + if (hudOverlayRecordingActive) { + hudOverlayFallbackExpanded = false; + return; + } + hudOverlayFallbackExpanded = expanded; if ( !hudOverlayWindow || @@ -269,23 +275,43 @@ function setHudOverlayFallbackExpanded(expanded: boolean) { } } -ipcMain.on("hud-overlay-set-ignore-mouse", (_event, ignore: boolean) => { - if (hudOverlayWindow && !hudOverlayWindow.isDestroyed()) { - if (!isHudOverlayMousePassthroughSupported()) { - if (process.platform !== "linux") { - setHudOverlayFallbackExpanded(!ignore); - } - hudOverlayWindow.setIgnoreMouseEvents(false); - return; - } +function setHudOverlayMousePassthrough(ignore: boolean) { + hudOverlayIgnoringMouse = hudOverlayRecordingActive ? false : ignore; - if (ignore) { - hudOverlayWindow.setIgnoreMouseEvents(true, { forward: true }); - return; - } - - hudOverlayWindow.setIgnoreMouseEvents(false); + if (hudOverlayMouseReassertTimer) { + clearTimeout(hudOverlayMouseReassertTimer); + hudOverlayMouseReassertTimer = null; } + + if (!hudOverlayWindow || hudOverlayWindow.isDestroyed()) { + return; + } + + if (hudOverlayRecordingActive) { + hudOverlayFallbackExpanded = false; + applyHudOverlayBounds(); + hudOverlayWindow.setIgnoreMouseEvents(false); + return; + } + + if (!isHudOverlayMousePassthroughSupported()) { + if (process.platform !== "linux") { + setHudOverlayFallbackExpanded(!ignore); + } + hudOverlayWindow.setIgnoreMouseEvents(false); + return; + } + + if (ignore) { + hudOverlayWindow.setIgnoreMouseEvents(true, { forward: true }); + return; + } + + hudOverlayWindow.setIgnoreMouseEvents(false); +} + +ipcMain.on("hud-overlay-set-ignore-mouse", (_event, ignore: boolean) => { + setHudOverlayMousePassthrough(Boolean(ignore)); }); // Keep compatibility with existing drag IPC/state. @@ -426,7 +452,7 @@ export function createHudOverlayWindow(): BrowserWindow { win.setIgnoreMouseEvents(false); setTimeout(() => { if (!win.isDestroyed()) { - win.setIgnoreMouseEvents(true, { forward: true }); + setHudOverlayMousePassthrough(hudOverlayIgnoringMouse); } }, 50); } @@ -437,7 +463,13 @@ export function createHudOverlayWindow(): BrowserWindow { } if (isHudOverlayMousePassthroughSupported()) { - win.setIgnoreMouseEvents(true, { forward: true }); + if (hudOverlayRecordingActive) { + hudOverlayIgnoringMouse = false; + win.setIgnoreMouseEvents(false); + } else { + hudOverlayIgnoringMouse = true; + win.setIgnoreMouseEvents(true, { forward: true }); + } } // On Windows 11+, focus changes (e.g. showing a native notification) can break @@ -452,7 +484,7 @@ export function createHudOverlayWindow(): BrowserWindow { win.setIgnoreMouseEvents(false); setTimeout(() => { if (!win.isDestroyed()) { - win.setIgnoreMouseEvents(true, { forward: true }); + setHudOverlayMousePassthrough(hudOverlayIgnoringMouse); } }, 50); } @@ -566,16 +598,32 @@ export function reassertHudOverlayMousePassthrough(): void { return; } + if (hudOverlayRecordingActive) { + hud.setIgnoreMouseEvents(false); + return; + } + // Toggle off then back on so the native WS_EX_TRANSPARENT flag is fully // re-initialised rather than merely re-asserted in a potentially broken state. hud.setIgnoreMouseEvents(false); - setTimeout(() => { + if (hudOverlayMouseReassertTimer) { + clearTimeout(hudOverlayMouseReassertTimer); + } + hudOverlayMouseReassertTimer = setTimeout(() => { + hudOverlayMouseReassertTimer = null; if (!hud.isDestroyed()) { - hud.setIgnoreMouseEvents(true, { forward: true }); + setHudOverlayMousePassthrough(hudOverlayIgnoringMouse); } }, 50); } +export function setHudOverlayRecordingActive(recording: boolean): void { + hudOverlayRecordingActive = Boolean(recording); + hudOverlayFallbackExpanded = false; + applyHudOverlayBounds(); + setHudOverlayMousePassthrough(!hudOverlayRecordingActive); +} + export function createUpdateToastWindow(): BrowserWindow { const initialBounds = getUpdateToastBounds(); const parentWindow = diff --git a/scripts/build-nvidia-cuda-compositor.mjs b/scripts/build-nvidia-cuda-compositor.mjs index cdccbc12..e2959022 100644 --- a/scripts/build-nvidia-cuda-compositor.mjs +++ b/scripts/build-nvidia-cuda-compositor.mjs @@ -1,5 +1,5 @@ import { execSync } from "node:child_process"; -import { copyFileSync, existsSync, mkdirSync, rmSync } from "node:fs"; +import { copyFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import path from "node:path"; import { @@ -117,6 +117,110 @@ if (!existsSync(path.join(videoCodecSdkRoot, "Samples", "NvCodec"))) { ); } +function replaceOrThrow(filePath, content, pattern, replacement, label) { + const updated = content.replace(pattern, replacement); + if (updated === content) { + throw new Error(`Unable to patch ${label} in ${filePath}`); + } + return updated; +} + +function patchNvDecoderForRecordlyCallbacks() { + const nvDecoderDir = path.join(videoCodecSdkRoot, "Samples", "NvCodec", "NvDecoder"); + const headerPath = path.join(nvDecoderDir, "NvDecoder.h"); + const sourcePath = path.join(nvDecoderDir, "NvDecoder.cpp"); + + let header = readFileSync(headerPath, "utf8"); + if (!header.includes("RecordlyMappedFrameHandler")) { + header = replaceOrThrow( + headerPath, + header, + /#include "nvcuvid\.h"\r?\n/, + `#include "nvcuvid.h" + +using RecordlyMappedFrameHandler = void (*)(CUdeviceptr, unsigned int, int, int, int, int64_t, void*); +using RecordlyDisplayFramePolicy = bool (*)(int, void*); +`, + "NvDecoder callback aliases", + ); + header = replaceOrThrow( + headerPath, + header, + / {4}int setReconfigParams\(const Rect \* pCropRect, const Dim \* pResizeDim\);\r?\n/, + ` int setReconfigParams(const Rect * pCropRect, const Dim * pResizeDim); + void SetMappedFrameHandler(RecordlyMappedFrameHandler handler, void* userData) { m_recordlyMappedFrameHandler = handler; m_recordlyMappedFrameUserData = userData; } + void SetDisplayFramePolicy(RecordlyDisplayFramePolicy policy, void* userData) { m_recordlyDisplayFramePolicy = policy; m_recordlyDisplayFramePolicyUserData = userData; } + int GetDisplayFrameCount() const { return m_nDisplayFrameCount; } +`, + "NvDecoder public callback methods", + ); + header = replaceOrThrow( + headerPath, + header, + / {4}int m_nDecodedFrame = 0, m_nDecodedFrameReturned = 0;\r?\n/, + ` int m_nDecodedFrame = 0, m_nDecodedFrameReturned = 0; + int m_nDisplayFrameCount = 0; + RecordlyMappedFrameHandler m_recordlyMappedFrameHandler = nullptr; + void* m_recordlyMappedFrameUserData = nullptr; + RecordlyDisplayFramePolicy m_recordlyDisplayFramePolicy = nullptr; + void* m_recordlyDisplayFramePolicyUserData = nullptr; +`, + "NvDecoder callback state", + ); + writeFileSync(headerPath, header); + } + + let source = readFileSync(sourcePath, "utf8"); + if (!source.includes("Recordly mapped frame callback")) { + source = replaceOrThrow( + sourcePath, + source, + / {4}if \(result == CUDA_SUCCESS && \(DecodeStatus\.decodeStatus == cuvidDecodeStatus_Error \|\| DecodeStatus\.decodeStatus == cuvidDecodeStatus_Error_Concealed\)\)\r?\n {4}\{\r?\n {8}printf\("Decode Error occurred for picture %d\\n", m_nPicNumInDecodeOrder\[pDispInfo->picture_index\]\);\r?\n {4}\}\r?\n {4}uint8_t \*pDecodedFrame = nullptr;\r?\n/, + ` if (result == CUDA_SUCCESS && (DecodeStatus.decodeStatus == cuvidDecodeStatus_Error || DecodeStatus.decodeStatus == cuvidDecodeStatus_Error_Concealed)) + { + printf("Decode Error occurred for picture %d\\n", m_nPicNumInDecodeOrder[pDispInfo->picture_index]); + } + + const int displayFrameIndex = m_nDisplayFrameCount++; + if (m_recordlyDisplayFramePolicy && + !m_recordlyDisplayFramePolicy(displayFrameIndex, m_recordlyDisplayFramePolicyUserData)) + { + NVDEC_API_CALL(cuvidUnmapVideoFrame(m_hDecoder, dpSrcFrame)); + return 1; + } + + // Recordly mapped frame callback keeps the CUDA helper from making an + // extra device-to-device copy when the caller can consume mapped NV12. + if (m_recordlyMappedFrameHandler) + { + m_recordlyMappedFrameHandler( + dpSrcFrame, + nSrcPitch, + m_nWidth, + m_nHeight, + m_nSurfaceHeight, + pDispInfo->timestamp, + m_recordlyMappedFrameUserData); + NVDEC_API_CALL(cuvidUnmapVideoFrame(m_hDecoder, dpSrcFrame)); + return 1; + } + + uint8_t *pDecodedFrame = nullptr; +`, + "NvDecoder mapped frame callback hook", + ); + writeFileSync(sourcePath, source); + } +} + +try { + patchNvDecoderForRecordlyCallbacks(); +} catch (error) { + fallbackToBundledHelperOrExit( + `Failed to patch NVIDIA Video Codec SDK samples: ${error instanceof Error ? error.message : String(error)}`, + ); +} + const cmake = findCmake(); if (!cmake) { fallbackToBundledHelperOrExit( diff --git a/src/components/launch/LaunchWindow.tsx b/src/components/launch/LaunchWindow.tsx index b3c92476..d7dc51bc 100644 --- a/src/components/launch/LaunchWindow.tsx +++ b/src/components/launch/LaunchWindow.tsx @@ -21,9 +21,7 @@ import { useScreenRecorder } from "../../hooks/useScreenRecorder"; import { useVideoDevices } from "../../hooks/useVideoDevices"; import { Button } from "../ui/button"; import { HudInteractionContext } from "./contexts/HudInteractionContext"; -import { - canToggleFloatingWebcamPreview, -} from "./floatingWebcamPreview"; +import { canToggleFloatingWebcamPreview } from "./floatingWebcamPreview"; import { useHudBarDrag } from "./hooks/useHudBarDrag"; import { useLaunchHudInteractionState } from "./hooks/useLaunchHudInteractionState"; import { useLaunchWindowActions } from "./hooks/useLaunchWindowActions"; @@ -32,7 +30,10 @@ import { useRecordingTimer } from "./hooks/useRecordingTimer"; import { useWebcamPreviewOverlay } from "./hooks/useWebcamPreviewOverlay"; import styles from "./LaunchWindow.module.css"; import { CountdownPopover } from "./popovers/CountdownPopover"; -import { LaunchPopoverCoordinatorProvider, useLaunchPopoverCoordinator } from "./popovers/LaunchPopoverCoordinator"; +import { + LaunchPopoverCoordinatorProvider, + useLaunchPopoverCoordinator, +} from "./popovers/LaunchPopoverCoordinator"; import { MicPopover } from "./popovers/MicPopover"; import { MorePopover } from "./popovers/MorePopover"; import { ProjectPopover } from "./popovers/ProjectPopover"; @@ -83,7 +84,6 @@ function LaunchWindowContent() { const hudContentRef = useRef(null); const hudBarRef = useRef(null); - const { selectedSource, hasSelectedSource, @@ -166,12 +166,13 @@ function LaunchWindowContent() { recordingWebcamPreviewContainerRef, }); - const { handleHudMouseEnter, handleHudMouseLeave, beginInteractiveHudAction } = useLaunchHudInteractionState({ - openId, - isHudDraggingRef, - isWebcamPreviewDraggingRef, - webcamPreviewDragStartRef, - }); + const { handleHudMouseEnter, handleHudMouseLeave, beginInteractiveHudAction } = + useLaunchHudInteractionState({ + openId, + isHudDraggingRef, + isWebcamPreviewDraggingRef, + webcamPreviewDragStartRef, + }); useEffect(() => { let mounted = true; @@ -195,7 +196,6 @@ function LaunchWindowContent() { ease: [0.22, 1, 0.36, 1] as const, }; - const recordingControls = ( - {microphoneEnabled ? : } + {microphoneEnabled ? ( + + ) : ( + + )} } /> @@ -282,9 +286,7 @@ function LaunchWindowContent() { hudOverlayMousePassthroughSupported, )} showFloatingWebcamPreview={showFloatingWebcamPreview} - onToggleFloatingPreview={() => - setShowFloatingWebcamPreview((current) => !current) - } + onToggleFloatingPreview={() => setShowFloatingWebcamPreview((current) => !current)} showWebcamControls={showWebcamControls} setWebcamPreviewNode={setWebcamPreviewNode} videoDevices={videoDevices} @@ -307,7 +309,11 @@ function LaunchWindowContent() { } className={webcamEnabled ? styles.ibActive : ""} > - {webcamEnabled ? : } + {webcamEnabled ? ( + + ) : ( + + )} } /> @@ -328,7 +334,6 @@ function LaunchWindowContent() { } /> - } @@ -430,112 +430,113 @@ function LaunchWindowContent() { platform === "linux" || hudOverlayMousePassthroughSupported === false; return ( - +
-
- -
- -
- -
- - - {finalizing - ? finalizingControls - : recording - ? recordingControls - : idleControls} - - -
-
-
- {showRecordingWebcamPreview && (
-
- )} -
+ +
+ +
+
+ + + {finalizing + ? finalizingControls + : recording + ? recordingControls + : idleControls} + + +
+
+
+ {showRecordingWebcamPreview && ( +
+
+ )} +
+ -
); } diff --git a/src/components/launch/hooks/useLaunchHudInteractionState.ts b/src/components/launch/hooks/useLaunchHudInteractionState.ts index 31187e1a..9d0160a7 100644 --- a/src/components/launch/hooks/useLaunchHudInteractionState.ts +++ b/src/components/launch/hooks/useLaunchHudInteractionState.ts @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef, type MouseEvent, type RefObject } from "react"; +import { type MouseEvent, type RefObject, useCallback, useEffect, useRef } from "react"; export function useLaunchHudInteractionState({ openId, @@ -32,7 +32,7 @@ export function useLaunchHudInteractionState({ const target = e.target as HTMLElement | null; if (!target) return; const isInteractive = !!target.closest( - ".pointer-events-auto, [data-hud-interactive], [data-radix-popper-content-wrapper]" + ".pointer-events-auto, [data-hud-interactive], [data-radix-popper-content-wrapper]", ); if (isInteractive) { @@ -70,27 +70,30 @@ export function useLaunchHudInteractionState({ window.electronAPI?.hudOverlaySetIgnoreMouse?.(false); }, []); - const handleHudMouseLeave = useCallback((event: MouseEvent) => { - const nextTarget = event.relatedTarget; - if (nextTarget instanceof Node && event.currentTarget.contains(nextTarget)) { - return; - } - - isMouseOverHudRef.current = false; - - if (timeoutRef.current) clearTimeout(timeoutRef.current); - - timeoutRef.current = setTimeout(() => { - if ( - !isHudDraggingRef.current && - !isWebcamPreviewDraggingRef.current && - !webcamPreviewDragStartRef.current && - !isMouseOverHudRef.current - ) { - window.electronAPI?.hudOverlaySetIgnoreMouse?.(true); + const handleHudMouseLeave = useCallback( + (event: MouseEvent) => { + const nextTarget = event.relatedTarget; + if (nextTarget instanceof Node && event.currentTarget.contains(nextTarget)) { + return; } - }, 300); - }, [isHudDraggingRef, isWebcamPreviewDraggingRef, webcamPreviewDragStartRef]); + + isMouseOverHudRef.current = false; + + if (timeoutRef.current) clearTimeout(timeoutRef.current); + + timeoutRef.current = setTimeout(() => { + if ( + !isHudDraggingRef.current && + !isWebcamPreviewDraggingRef.current && + !webcamPreviewDragStartRef.current && + !isMouseOverHudRef.current + ) { + window.electronAPI?.hudOverlaySetIgnoreMouse?.(true); + } + }, 300); + }, + [isHudDraggingRef, isWebcamPreviewDraggingRef, webcamPreviewDragStartRef], + ); return { handleHudMouseEnter, diff --git a/src/components/video-editor/VideoEditor.tsx b/src/components/video-editor/VideoEditor.tsx index 4050189e..0893630f 100644 --- a/src/components/video-editor/VideoEditor.tsx +++ b/src/components/video-editor/VideoEditor.tsx @@ -163,7 +163,10 @@ import { RECORDLY_ISSUES_URL, } from "./TutorialHelp"; import TimelineEditor, { type TimelineEditorHandle } from "./timeline/TimelineEditor"; -import { normalizeCursorTelemetry } from "./timeline/zoomSuggestionUtils"; +import { + normalizeCursorTelemetry, + shouldAutoApplyFreshRecordingZoomsForSource, +} from "./timeline/zoomSuggestionUtils"; import { type AnnotationRegion, type AudioRegion, @@ -3344,6 +3347,23 @@ export default function VideoEditor() { ); useEffect(() => { + if ( + videoPath && + pendingFreshRecordingAutoZoomPathRef.current === videoPath && + isPreviewReady && + !shouldAutoApplyFreshRecordingZoomsForSource( + videoPlaybackRef.current?.video?.videoWidth, + videoPlaybackRef.current?.video?.videoHeight, + ) + ) { + pendingFreshRecordingAutoZoomPathRef.current = null; + if (pendingFreshRecordingAutoSuggestTimeoutRef.current !== null) { + window.clearTimeout(pendingFreshRecordingAutoSuggestTimeoutRef.current); + pendingFreshRecordingAutoSuggestTimeoutRef.current = null; + } + return; + } + if ( !videoPath || loading || @@ -3402,6 +3422,27 @@ export default function VideoEditor() { zoomRegions, ]); + useEffect(() => { + if ( + !videoPath || + !isPreviewReady || + zoomRegions.length === 0 || + autoSuggestedVideoPathRef.current !== videoPath || + shouldAutoApplyFreshRecordingZoomsForSource( + videoPlaybackRef.current?.video?.videoWidth, + videoPlaybackRef.current?.video?.videoHeight, + ) + ) { + return; + } + + autoSuggestedVideoPathRef.current = null; + setZoomRegions((prev) => { + const next = prev.filter((region) => region.mode !== "auto"); + return next.length === prev.length ? prev : next; + }); + }, [videoPath, isPreviewReady, zoomRegions]); + const handleZoomSpanChange = useCallback((id: string, span: Span) => { setZoomRegions((prev) => prev.map((region) => diff --git a/src/components/video-editor/timeline/zoomSuggestionUtils.test.ts b/src/components/video-editor/timeline/zoomSuggestionUtils.test.ts index 77080bfc..f1a6dd21 100644 --- a/src/components/video-editor/timeline/zoomSuggestionUtils.test.ts +++ b/src/components/video-editor/timeline/zoomSuggestionUtils.test.ts @@ -1,10 +1,11 @@ import { describe, expect, it } from "vitest"; +import type { CursorTelemetryPoint } from "../types"; import { + buildInteractionZoomSuggestions, CLICK_CLUSTER_MERGE_GAP_MS, CLICK_CLUSTER_PAD_MS, - buildInteractionZoomSuggestions, + shouldAutoApplyFreshRecordingZoomsForSource, } from "./zoomSuggestionUtils"; -import type { CursorTelemetryPoint } from "../types"; function makeClick( timeMs: number, @@ -20,19 +21,28 @@ function makeMove(timeMs: number, cx = 0.5, cy = 0.5): CursorTelemetryPoint { } /** Wraps click samples with surrounding move events to mimic real mixed telemetry. */ -function withMoves( - clicks: CursorTelemetryPoint[], - totalMs: number, -): CursorTelemetryPoint[] { - return [ - makeMove(0), - ...clicks, - makeMove(totalMs), - ]; +function withMoves(clicks: CursorTelemetryPoint[], totalMs: number): CursorTelemetryPoint[] { + return [makeMove(0), ...clicks, makeMove(totalMs)]; } const TOTAL_MS = 30_000; +describe("shouldAutoApplyFreshRecordingZoomsForSource", () => { + it("allows automatic fresh-recording zooms for landscape captures", () => { + expect(shouldAutoApplyFreshRecordingZoomsForSource(1920, 1080)).toBe(true); + expect(shouldAutoApplyFreshRecordingZoomsForSource(1280, 960)).toBe(true); + }); + + it("blocks automatic fresh-recording zooms for narrow or near-square captures", () => { + expect(shouldAutoApplyFreshRecordingZoomsForSource(960, 1020)).toBe(false); + expect(shouldAutoApplyFreshRecordingZoomsForSource(1080, 1080)).toBe(false); + }); + + it("does not block when source dimensions are not available yet", () => { + expect(shouldAutoApplyFreshRecordingZoomsForSource()).toBe(true); + }); +}); + describe("buildInteractionZoomSuggestions (click-cluster logic)", () => { it("creates one zoom track for a single isolated click with 500ms padding", () => { const telemetry = withMoves([makeClick(5_000)], TOTAL_MS); @@ -62,23 +72,23 @@ describe("buildInteractionZoomSuggestions (click-cluster logic)", () => { expect(result.suggestions).toHaveLength(1); }); - it.each(["right-click", "middle-click"] as const)( - "accepts %s telemetry like a standard click", - (interactionType) => { - const result = buildInteractionZoomSuggestions({ - cursorTelemetry: withMoves([makeClick(5_000, 0.5, 0.5, interactionType)], TOTAL_MS), - totalMs: TOTAL_MS, - defaultDurationMs: 3_000, - }); + it.each([ + "right-click", + "middle-click", + ] as const)("accepts %s telemetry like a standard click", (interactionType) => { + const result = buildInteractionZoomSuggestions({ + cursorTelemetry: withMoves([makeClick(5_000, 0.5, 0.5, interactionType)], TOTAL_MS), + totalMs: TOTAL_MS, + defaultDurationMs: 3_000, + }); - expect(result.status).toBe("ok"); - expect(result.suggestions).toHaveLength(1); + expect(result.status).toBe("ok"); + expect(result.suggestions).toHaveLength(1); - const [suggestion] = result.suggestions; - expect(suggestion.start).toBe(5_000 - CLICK_CLUSTER_PAD_MS); - expect(suggestion.end).toBe(5_000 + CLICK_CLUSTER_PAD_MS); - }, - ); + const [suggestion] = result.suggestions; + expect(suggestion.start).toBe(5_000 - CLICK_CLUSTER_PAD_MS); + expect(suggestion.end).toBe(5_000 + CLICK_CLUSTER_PAD_MS); + }); it("merges two clicks within 2500ms into one zoom track", () => { const telemetry = withMoves( diff --git a/src/components/video-editor/timeline/zoomSuggestionUtils.ts b/src/components/video-editor/timeline/zoomSuggestionUtils.ts index 189c7604..bf38efa6 100644 --- a/src/components/video-editor/timeline/zoomSuggestionUtils.ts +++ b/src/components/video-editor/timeline/zoomSuggestionUtils.ts @@ -3,6 +3,7 @@ import type { CursorTelemetryPoint, ZoomFocus } from "../types"; export const MIN_DWELL_DURATION_MS = 450; export const MAX_DWELL_DURATION_MS = 2600; export const DWELL_MOVE_THRESHOLD = 0.02; +export const MIN_FRESH_RECORDING_AUTO_ZOOM_SOURCE_ASPECT_RATIO = 1.2; export interface ZoomDwellCandidate { centerTimeMs: number; @@ -39,6 +40,25 @@ export interface InteractionZoomSuggestionResult { suggestions: SuggestedZoomRegion[]; } +export function shouldAutoApplyFreshRecordingZoomsForSource( + sourceWidth?: number, + sourceHeight?: number, +): boolean { + if ( + !Number.isFinite(sourceWidth) || + !Number.isFinite(sourceHeight) || + (sourceWidth ?? 0) <= 0 || + (sourceHeight ?? 0) <= 0 + ) { + return true; + } + + return ( + (sourceWidth as number) / (sourceHeight as number) >= + MIN_FRESH_RECORDING_AUTO_ZOOM_SOURCE_ASPECT_RATIO + ); +} + /** Max gap between consecutive clicks before they are split into separate zoom clusters. */ export const CLICK_CLUSTER_MERGE_GAP_MS = 2500; /** Padding added before the first click and after the last click in a cluster. */ diff --git a/src/hooks/recordingMimeType.test.ts b/src/hooks/recordingMimeType.test.ts index 9f4919f2..79dd6c2d 100644 --- a/src/hooks/recordingMimeType.test.ts +++ b/src/hooks/recordingMimeType.test.ts @@ -7,15 +7,15 @@ import { } from "./recordingMimeType"; describe("selectRecordingMimeType", () => { - it("prefers codecs the editor can play back", () => { + it("keeps browser screen captures in WebM/H.264 when supported", () => { const mimeType = selectRecordingMimeType({ isTypeSupported: () => true, canPlayType: (type) => { - if (type === "video/webm;codecs=vp9") { + if (type === "video/webm;codecs=h264") { return "probably"; } - if (type === "video/webm") { + if (type === "video/webm;codecs=vp9") { return "maybe"; } @@ -23,16 +23,13 @@ describe("selectRecordingMimeType", () => { }, }); - expect(mimeType).toBe("video/webm;codecs=vp9"); + expect(mimeType).toBe("video/webm;codecs=h264"); }); it("skips recorder-only codecs when playback support is missing", () => { const mimeType = selectRecordingMimeType({ isTypeSupported: (type) => - [ - "video/webm;codecs=vp9", - "video/webm;codecs=vp8", - ].includes(type), + ["video/webm;codecs=vp9", "video/webm;codecs=vp8"].includes(type), canPlayType: (type) => (type === "video/webm;codecs=vp8" ? "probably" : ""), }); @@ -42,14 +39,11 @@ describe("selectRecordingMimeType", () => { it("falls back to the first supported codec when playback probing is unavailable", () => { const mimeType = selectRecordingMimeType({ isTypeSupported: (type) => - [ - "video/webm;codecs=av1", - "video/webm;codecs=h264", - ].includes(type), + ["video/webm;codecs=av1", "video/webm;codecs=h264"].includes(type), canPlayType: () => "", }); - expect(mimeType).toBe("video/webm;codecs=av1"); + expect(mimeType).toBe("video/webm;codecs=h264"); }); it("returns undefined when no preferred mime type is supported", () => { @@ -64,9 +58,7 @@ describe("selectRecordingMimeType", () => { it("prefers MP4/H.264 for webcam captures when supported", () => { const mimeType = selectWebcamRecordingMimeType({ isTypeSupported: (type) => - ["video/mp4;codecs=avc1.42E01E", "video/webm;codecs=vp9"].includes( - type, - ), + ["video/mp4;codecs=avc1.42E01E", "video/webm;codecs=vp9"].includes(type), canPlayType: () => "probably", }); @@ -75,8 +67,7 @@ describe("selectRecordingMimeType", () => { it("falls back to WebM webcam capture when MP4 is unavailable", () => { const mimeType = selectWebcamRecordingMimeType({ - isTypeSupported: (type) => - ["video/webm;codecs=vp9", "video/webm"].includes(type), + isTypeSupported: (type) => ["video/webm;codecs=vp9", "video/webm"].includes(type), canPlayType: () => "probably", }); diff --git a/src/hooks/recordingMimeType.ts b/src/hooks/recordingMimeType.ts index 93a5ba82..56930b84 100644 --- a/src/hooks/recordingMimeType.ts +++ b/src/hooks/recordingMimeType.ts @@ -1,9 +1,9 @@ const RECORDING_MIME_TYPE_PREFERENCES = [ + "video/webm;codecs=h264", "video/webm;codecs=vp9", "video/webm", "video/webm;codecs=vp8", "video/webm;codecs=av1", - "video/webm;codecs=h264", ] as const; const WEBCAM_RECORDING_MIME_TYPE_PREFERENCES = [ @@ -38,9 +38,7 @@ function selectMimeTypeFromPreferences( return playableType ?? supportedTypes[0]; } -export function selectRecordingMimeType( - options: MimeTypeSelectorOptions = {}, -): string | undefined { +export function selectRecordingMimeType(options: MimeTypeSelectorOptions = {}): string | undefined { return selectMimeTypeFromPreferences(RECORDING_MIME_TYPE_PREFERENCES, options); } @@ -54,6 +52,8 @@ export function isWebmMimeType(mimeType: string | undefined | null): boolean { return /^video\/webm(?:[;\s]|$)/i.test(mimeType ?? ""); } -export function getVideoExtensionForMimeType(mimeType: string | undefined | null): ".mp4" | ".webm" { +export function getVideoExtensionForMimeType( + mimeType: string | undefined | null, +): ".mp4" | ".webm" { return /^video\/mp4(?:[;\s]|$)/i.test(mimeType ?? "") ? ".mp4" : ".webm"; } diff --git a/src/hooks/useScreenRecorder.test.ts b/src/hooks/useScreenRecorder.test.ts index 00a8a7a9..85811467 100644 --- a/src/hooks/useScreenRecorder.test.ts +++ b/src/hooks/useScreenRecorder.test.ts @@ -1,6 +1,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { + createBrowserRecordingOptions, createProcessedMicrophoneConstraints, normalizeBrowserMicrophoneProfile, resolveBrowserCaptureCursorPolicy, @@ -32,12 +33,12 @@ function createMockMediaRecorder(initialState: RecordingState = "inactive") { } describe("createProcessedMicrophoneConstraints", () => { - it("requests browser voice processing without AGC for the default microphone", () => { + it("requests browser voice processing with AGC for the default microphone", () => { expect(createProcessedMicrophoneConstraints()).toEqual({ audio: { echoCancellation: true, noiseSuppression: true, - autoGainControl: false, + autoGainControl: true, channelCount: { ideal: 1 }, sampleRate: { ideal: 48000 }, }, @@ -45,13 +46,13 @@ describe("createProcessedMicrophoneConstraints", () => { }); }); - it("keeps no-AGC voice processing when a specific microphone is selected", () => { + it("keeps default voice processing when a specific microphone is selected", () => { expect(createProcessedMicrophoneConstraints("device-123")).toMatchObject({ audio: { deviceId: { exact: "device-123" }, echoCancellation: true, noiseSuppression: true, - autoGainControl: false, + autoGainControl: true, channelCount: { ideal: 1 }, sampleRate: { ideal: 48000 }, }, @@ -103,10 +104,38 @@ describe("createProcessedMicrophoneConstraints", () => { }); }); - it("normalizes invalid lab microphone profiles to production no-AGC processing", () => { + it("normalizes invalid lab microphone profiles to production voice processing", () => { expect(normalizeBrowserMicrophoneProfile("RAW")).toBe("raw"); - expect(normalizeBrowserMicrophoneProfile("unknown")).toBe("no-agc"); - expect(normalizeBrowserMicrophoneProfile(null)).toBe("no-agc"); + expect(normalizeBrowserMicrophoneProfile("unknown")).toBe("processed"); + expect(normalizeBrowserMicrophoneProfile(null)).toBe("processed"); + }); +}); + +describe("createBrowserRecordingOptions", () => { + it("sets an aggregate bitrate target for browser screen recordings", () => { + expect( + createBrowserRecordingOptions({ + audioBitsPerSecond: 128_000, + mimeType: "video/webm;codecs=vp9", + videoBitsPerSecond: 30_600_000, + }), + ).toEqual({ + audioBitsPerSecond: 128_000, + bitsPerSecond: 30_728_000, + mimeType: "video/webm;codecs=vp9", + videoBitsPerSecond: 30_600_000, + }); + }); + + it("keeps video-only recordings on the requested video budget", () => { + expect( + createBrowserRecordingOptions({ + videoBitsPerSecond: 30_600_000, + }), + ).toEqual({ + bitsPerSecond: 30_600_000, + videoBitsPerSecond: 30_600_000, + }); }); }); diff --git a/src/hooks/useScreenRecorder.ts b/src/hooks/useScreenRecorder.ts index 4da2ae71..30ed7c62 100644 --- a/src/hooks/useScreenRecorder.ts +++ b/src/hooks/useScreenRecorder.ts @@ -29,10 +29,9 @@ const BITS_PER_MEGABIT = 1_000_000; const MIN_FRAME_RATE = 30; const CHROME_MEDIA_SOURCE = "desktop"; const RECORDING_FILE_PREFIX = "recording-"; -const VIDEO_FILE_EXTENSION = ".webm"; const AUDIO_BITRATE_VOICE = 128_000; const AUDIO_BITRATE_SYSTEM = 192_000; -const MIC_GAIN_BOOST = 1; +const MIC_GAIN_BOOST = 1.4; const WEBCAM_BITRATE = 8_000_000; const WEBCAM_WIDTH = 1280; const WEBCAM_HEIGHT = 720; @@ -52,7 +51,7 @@ export type BrowserCaptureCursorPolicy = { hideOsCursorBeforeRecording: boolean; hideEditorOverlayCursorByDefault: boolean; }; -const DEFAULT_BROWSER_MICROPHONE_PROFILE: BrowserMicrophoneProfile = "no-agc"; +const DEFAULT_BROWSER_MICROPHONE_PROFILE: BrowserMicrophoneProfile = "processed"; const BROWSER_MICROPHONE_PROFILES = new Set([ "processed", "no-agc", @@ -238,6 +237,31 @@ export function createProcessedMicrophoneConstraints( return { audio, video: false }; } +export function createBrowserRecordingOptions({ + audioBitsPerSecond, + mimeType, + videoBitsPerSecond, +}: { + audioBitsPerSecond?: number; + mimeType?: string; + videoBitsPerSecond: number; +}): MediaRecorderOptions { + const options: MediaRecorderOptions = { + videoBitsPerSecond, + bitsPerSecond: videoBitsPerSecond + (audioBitsPerSecond ?? 0), + }; + + if (audioBitsPerSecond !== undefined) { + options.audioBitsPerSecond = audioBitsPerSecond; + } + + if (mimeType) { + options.mimeType = mimeType; + } + + return options; +} + function createMicrophoneTrackSettingsSnapshot( stream: MediaStream, ): MicrophoneTrackSettingsSnapshot | null { @@ -901,7 +925,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { const webcamPath = await stopWebcamRecorder(); await storeMicrophoneSidecar(resolvedMicFallbackBlobPromise, result.path, startDelayMs); await finalizeRecordingSession(result.path, webcamPath); - + if (typeof window.electronAPI?.hudOverlayClose === "function") { window.electronAPI.hudOverlayClose(); } @@ -1106,52 +1130,60 @@ export function useScreenRecorder(): UseScreenRecorderReturn { // We pass null for webcamPath initially to avoid blocking on webcam disk writes/muxing. await finalizeRecordingSession(finalPath, null); - // 2. Perform background finalization (webcam, muxing, sidecars) - // We don't await this to keep the UI responsive - void (async () => { - try { - // Await the webcam path in the background - const webcamPath = await webcamPathPromise; - console.log("[useScreenRecorder] Background native processing: webcamPath is", webcamPath); + // 2. Perform background finalization (webcam, muxing, sidecars) + // We don't await this to keep the UI responsive + void (async () => { + try { + // Await the webcam path in the background + const webcamPath = await webcamPathPromise; + console.log( + "[useScreenRecorder] Background native processing: webcamPath is", + webcamPath, + ); - // Store sidecars - await storeMicrophoneSidecar( - micFallbackBlobPromise, - finalPath, - fallbackStartDelayMs, - fallbackTrackSettings, - ); + // Store sidecars + await storeMicrophoneSidecar( + micFallbackBlobPromise, + finalPath, + fallbackStartDelayMs, + fallbackTrackSettings, + ); - // Perform muxing/renaming if on Windows - if (isNativeWindows) { - await window.electronAPI.muxNativeWindowsRecording(expectedDurationMs); - } + // Perform muxing/renaming if on Windows + if (isNativeWindows) { + await window.electronAPI.muxNativeWindowsRecording(expectedDurationMs); + } - console.log("[useScreenRecorder] Emitting setCurrentRecordingSession with:", { finalPath, webcamPath }); + console.log( + "[useScreenRecorder] Emitting setCurrentRecordingSession with:", + { finalPath, webcamPath }, + ); - // Update the session state to notify the editor that all background assets (webcam, mic, etc.) are now ready. - // This broadcasts a 'recording-session-changed' event that the open editor listens to for re-scanning assets. - await window.electronAPI.setCurrentRecordingSession({ - videoPath: finalPath, - webcamPath, - timeOffsetMs: webcamTimeOffsetMs.current, - hideOverlayCursorByDefault: hideEditorOverlayCursorByDefault.current, - }); + // Update the session state to notify the editor that all background assets (webcam, mic, etc.) are now ready. + // This broadcasts a 'recording-session-changed' event that the open editor listens to for re-scanning assets. + await window.electronAPI.setCurrentRecordingSession({ + videoPath: finalPath, + webcamPath, + timeOffsetMs: webcamTimeOffsetMs.current, + hideOverlayCursorByDefault: hideEditorOverlayCursorByDefault.current, + }); - console.log( - `[PERF:RENDERER] Background Stop Sequence: COMPLETED in ${(performance.now() - stopStart).toFixed(2)}ms`, - ); - } catch (bgError) { - console.error("Error in background finalization:", bgError); - } finally { - // After all background tasks are done (webcam, mic sidecars, muxing), - // we can safely close the HUD window to release hardware and resources. - if (typeof window.electronAPI?.hudOverlayClose === "function") { - console.log("[useScreenRecorder] All background tasks finished, closing HUD"); - window.electronAPI.hudOverlayClose(); - } - } - })(); + console.log( + `[PERF:RENDERER] Background Stop Sequence: COMPLETED in ${(performance.now() - stopStart).toFixed(2)}ms`, + ); + } catch (bgError) { + console.error("Error in background finalization:", bgError); + } finally { + // After all background tasks are done (webcam, mic sidecars, muxing), + // we can safely close the HUD window to release hardware and resources. + if (typeof window.electronAPI?.hudOverlayClose === "function") { + console.log( + "[useScreenRecorder] All background tasks finished, closing HUD", + ); + window.electronAPI.hudOverlayClose(); + } + } + })(); })(); return; } @@ -1551,7 +1583,10 @@ export function useScreenRecorder(): UseScreenRecorderReturn { try { const hideCursorResult = await window.electronAPI.hideOsCursor?.(); if (hideCursorResult && !hideCursorResult.success) { - console.warn("Could not hide OS cursor before recording.", hideCursorResult); + console.warn( + "Could not hide OS cursor before recording.", + hideCursorResult, + ); } } catch { console.warn("Could not hide OS cursor before recording."); @@ -1747,17 +1782,19 @@ export function useScreenRecorder(): UseScreenRecorderReturn { chunks.current = []; const hasAudio = stream.current.getAudioTracks().length > 0; - const recorder = new MediaRecorder(stream.current, { - videoBitsPerSecond, - ...(mimeType ? { mimeType } : {}), - ...(hasAudio - ? { - audioBitsPerSecond: systemAudioIncluded - ? AUDIO_BITRATE_SYSTEM - : AUDIO_BITRATE_VOICE, - } - : {}), - }); + const audioBitsPerSecond = hasAudio + ? systemAudioIncluded + ? AUDIO_BITRATE_SYSTEM + : AUDIO_BITRATE_VOICE + : undefined; + const recorder = new MediaRecorder( + stream.current, + createBrowserRecordingOptions({ + audioBitsPerSecond, + mimeType, + videoBitsPerSecond, + }), + ); mediaRecorder.current = recorder; recorder.ondataavailable = (event) => { @@ -1779,10 +1816,12 @@ export function useScreenRecorder(): UseScreenRecorderReturn { ); chunks.current = []; const timestamp = recordingSessionTimestamp.current ?? Date.now(); - const videoFileName = `${RECORDING_FILE_PREFIX}${timestamp}${VIDEO_FILE_EXTENSION}`; + const videoFileName = `${RECORDING_FILE_PREFIX}${timestamp}${getVideoExtensionForMimeType(recordingBlobType)}`; try { - const videoBlob = await fixWebmDuration(buggyBlob, duration); + const videoBlob = isWebmMimeType(recordingBlobType) + ? await fixWebmDuration(buggyBlob, duration) + : buggyBlob; const arrayBuffer = await videoBlob.arrayBuffer(); const videoResult = await window.electronAPI.storeRecordedVideo( arrayBuffer, @@ -1813,14 +1852,17 @@ export function useScreenRecorder(): UseScreenRecorderReturn { videoPath: finalVideoPath, webcamPath, timeOffsetMs: webcamTimeOffsetMs.current, - hideOverlayCursorByDefault: hideEditorOverlayCursorByDefault.current, + hideOverlayCursorByDefault: + hideEditorOverlayCursorByDefault.current, }); } } finally { // After all background tasks are done (webcam), // we can safely close the HUD window to release hardware and resources. if (typeof window.electronAPI?.hudOverlayClose === "function") { - console.log("[useScreenRecorder:browser] All background tasks finished, closing HUD"); + console.log( + "[useScreenRecorder:browser] All background tasks finished, closing HUD", + ); window.electronAPI.hudOverlayClose(); } } diff --git a/src/lib/exporter/exportBitrate.test.ts b/src/lib/exporter/exportBitrate.test.ts index 5b6c5f91..1d46dc09 100644 --- a/src/lib/exporter/exportBitrate.test.ts +++ b/src/lib/exporter/exportBitrate.test.ts @@ -15,6 +15,28 @@ describe("export bitrate policy", () => { ).toBe(27_000_000); }); + it("raises high-resolution 60fps source-quality exports above the 30fps budget", () => { + const sharedOptions = { + width: 2560, + height: 1440, + quality: "source" as const, + encodingMode: "quality" as const, + }; + + const thirtyFpsBitrate = getMp4ExportBitrate({ + ...sharedOptions, + frameRate: 30, + }); + const sixtyFpsBitrate = getMp4ExportBitrate({ + ...sharedOptions, + frameRate: 60, + }); + + expect(thirtyFpsBitrate).toBe(45_000_000); + expect(sixtyFpsBitrate).toBeGreaterThan(thirtyFpsBitrate); + expect(sixtyFpsBitrate).toBe(63_639_610); + }); + it("keeps modern native static-layout source exports high enough for screen text", () => { expect( getMp4ExportBitrate({ diff --git a/src/lib/exporter/exportBitrate.ts b/src/lib/exporter/exportBitrate.ts index 7d3fa240..40110b6f 100644 --- a/src/lib/exporter/exportBitrate.ts +++ b/src/lib/exporter/exportBitrate.ts @@ -2,6 +2,7 @@ import type { ExportEncodingMode, ExportMp4FrameRate, ExportQuality } from "./ty const MIN_MP4_BITRATE = 2_000_000; const REFERENCE_PIXEL_RATE = 1920 * 1080 * 30; +const REFERENCE_FRAME_RATE = 30; export function getEncodingModeBitrateMultiplier(encodingMode: ExportEncodingMode): number { switch (encodingMode) { @@ -41,6 +42,10 @@ function getBaseMp4ExportBitrate(width: number, height: number, quality: ExportQ return 30_000_000; } +function getFrameRateBitrateMultiplier(frameRate: ExportMp4FrameRate): number { + return Math.sqrt(Math.max(1, frameRate / REFERENCE_FRAME_RATE)); +} + function getModernNativeStaticLayoutBitrateCap( width: number, height: number, @@ -87,6 +92,7 @@ export function getMp4ExportBitrate(options: { }): number { const requestedBitrate = Math.round( getBaseMp4ExportBitrate(options.width, options.height, options.quality) * + getFrameRateBitrateMultiplier(options.frameRate) * getEncodingModeBitrateMultiplier(options.encodingMode), ); const nativeStaticLayoutBitrate = From 0235b4f9477681dc450e2a2640f2a991f29d67e3 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Wed, 27 May 2026 18:31:00 +0700 Subject: [PATCH 4/8] fix(export): address CUDA dimension review notes --- .../bin/win32-x64/helpers-manifest.json | 6 ++--- .../recordly-nvidia-cuda-compositor.exe | Bin 460288 -> 460288 bytes .../run-mp4-pipeline.mjs | 16 +++++++++--- .../native/nvidia-cuda-compositor/src/main.cu | 6 +++++ src/lib/exporter/exportBitrate.test.ts | 23 ++++++++++++++++++ src/lib/exporter/exportBitrate.ts | 4 +++ 6 files changed, 48 insertions(+), 7 deletions(-) diff --git a/electron/native/bin/win32-x64/helpers-manifest.json b/electron/native/bin/win32-x64/helpers-manifest.json index 3a9f7dfa..c5080b66 100644 --- a/electron/native/bin/win32-x64/helpers-manifest.json +++ b/electron/native/bin/win32-x64/helpers-manifest.json @@ -26,10 +26,10 @@ }, "recordly-nvidia-cuda-compositor": { "binaryName": "recordly-nvidia-cuda-compositor.exe", - "binarySha256": "e9e062d1177075ac36eecf97e5934722a7fb782809e29ab60da54b396feb95b9", + "binarySha256": "250a3f8cac7c6ea38a873434d23d4b2be7d6555e42cc0b405aa26f774169159c", "sourceDir": "electron/native/nvidia-cuda-compositor", - "sourceFingerprint": "021ea1abd83606b589f694ddedb3af8035e2e08e2e130cf4fff6d6a3f7d64833", - "updatedAt": "2026-05-27T10:56:40.171Z" + "sourceFingerprint": "de1219228ce326e96d1f4815a3763b10d5f235cc1286bc6542c99707a85d5947", + "updatedAt": "2026-05-27T11:29:32.957Z" } } } diff --git a/electron/native/bin/win32-x64/recordly-nvidia-cuda-compositor.exe b/electron/native/bin/win32-x64/recordly-nvidia-cuda-compositor.exe index 3e6ebd579db4191476aca1f51d21a5371fc595df..c23c14f90fd72ee8f94c897d727604618201c926 100644 GIT binary patch delta 106244 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%0AvJrc~QSZiZsX^N_49$YvTjT1VDY$={F+gtB%) zA)l@!qmZi*GH60S=!D!)`4 z3cD``u}KIG(S#CoL2OlpGWLjmSak&N-1R|rf?$I+HeSchQ`u3-PRbL6ymR*>3N;c! zcTYRAX{{6bK^3ZkLhX;>R=GCpKfaU_&(aiEf?gsIsGx zjXR9Ds2(Hx5&jy$ZoYTY5p$M~4N=*u$a)=SznI`Q;9g|+33idjihaHuumURkG+o5} z51VI#Lr?DKtpZKZQ2l=X>>=6B%Md*PWo_2W@%ja0=p}@lH6gywSNmx5dXLWg&Xj%awuqEAOE zmD?wV^4V-Y9OX47cU~{Mw1TQM29>-;mxlQvdR(CQVWT3manYefMMDvN%SwB~InEi; zg#u+7`eLu<^?ZgLjb}SV{27S8=O#8|AAvU4&|5lmg^KcjBoyvj%tiDjqLBi1(a^&> zbdZX+MYJ2DClU1&=swtL$XvJT&?prxjA&&B;XOQDL$~NqUll#FT?AZMpy8Vl z-6hZp8p?F&t%I_g#v*$9pqOjni;$fu*avXtmJv_XvFlZ~8nR0cveLz1U73JvH^DB} z*uFY;vdSuHBIKcxO+vP^U|VQx7aeO+*%in}ARE>hS!coK*Vu+S)}*rSkhQabVuoU- zrieb8#d~=_oaMa@<|20w$i6Y6?O9HR6ta92cA z1X@u;-|W#Q?gAAZhv>8e48Fg-cvvxHqXc^o&JEJ-e>%2<%2q|zg4wwtT34Wpj<7dD z2D4`^)%NLD5n{0PV?yIMGkI4u)%^UU^W&qkOOSQL^xP2@e;s5d8v03xKHo1pwI!lA z_v3E4GP1{o+g-2<%k<2=UalnBD(i~ujs0RPmz;v^Si%0Ju|sw2SC!qjMWp)@%G&BI z_aq7mbreEnHKFr5p~tGwa1^?{pA9Q+D4raMi;_{W*I?n22^7|?XV+CW7}?DK6+|-> zauz~!G@%+gp>$Q~?q-qAn*HL?3#)+aqZxegVl~!N$IejMg~*O%ElLr862}qij_vO z>O!oKCRR`&?vZxWs1!a}_a#lpQ1Eh$hR4Rz9?m*ID@HTn_Jqx*21@eC)z{pq|P zFT$E3JL8;gBK)ngWsv=CAI?T`DzO`M@q53Fr#20_7;v`nb91bnD_tV>rCKlJib1DS7N!6kW1`A z>|0`qP)pPns)VYBTB1c$En<)L#xCNvu|Dahv9zeAv4^V0Qetf=rKK9JYGRG8rA6K| z=ggdW1cM<{JY(hdM$&w~7Zb#n^T1q02}f$%gSH>M6M(3$l(_@>_&{^f0@qg#>o z=}a;BaILK_%B9v{Y3GsF3jY6eq6r1MiGgnKF+L1{9sD6|tC;dOq|Diktu_rIcm=|% zU{2-G14X%P^|;dB`wDvuAD5ShE31YiO-5;7EiGe`u2RykNV?egp@OZ9Z#9y(M`?*Y zMnW*0LPsig0I>tH8Q(_4Hb(aQZ;X9af$gSPH?gfTt|yGxzh;OWP6S7erjjU^qp7N- zN7mtJN`n7CITVuwmwrECAdw>(2+uq+&?DG_Fr^6;D0dg8H0)i{&PVMPh%U7~Or7{u zX`7Jt#4bDnJh7x5h1yTFHp-;kptRT5;s8DcUk^ZjmGK=46pn#<>OkF1fo7^eD=E;J zU7ep3X(&bV#YjbTq;952eO07B6sgND+TMDS_P}&8AKwBbQ_;ett)#Rr(v|@Ke}>bC z0&T%SV|Admra%wU<$N53zr_ld;(w;&H~qsfcV5?Y)YjG7aFh19(oQDro^<-)r#-b> z5w*VoBnME>q)k=YhNMkS$FHw7eTB3Es9mPDjZNB-N_+K7?DIh5X=V7}v<*o!6GYy+ zXlYH8w4IWEOwz{bv=KHSZ8Q7=i&bk&o3!PWwg+j8rqhS6O-VZ*+fCoe!>wr2=0Y(p zdmqyNY>cV`U6xy49hAPWrRJ^gtdj2e0!RD(PI|K)NzMABwwl)B<|L1{4N5zPw4Y+L zzIbZzy1w^_Or6_dc*?_Om#WyB#3t{=qf1@%Z$tQl9XveqMgK^py|h}+2o6uqNGwWU z)>89~yriUyNLrVg4U@al8>oG>otri9N;akKOxn9UXaV9W$m=SG+KpQKFC2(!N4o^w z!5Mk73cGxA2Y!_)Oq?xX6T3D|o6^%SS77Y(rDv$Fnp>k-}AIZ=}av(zvt5w%}v z?Ol`hZ%7}`&w~}%BeRr&I(f`mx|Pq zB0Vwg)PSX$O48{lU8SY-Owt>$mT>m&eU78Kh|;h%B#lC8UoHL6B>hoIzar^@ZS*bu z<)kf)T7RvbW72L>+CijUNzG0r>8;5kZJB92*dZqAL?sO*>ATRZ_!Yz{r2QW6+IzHi zut^)Mv_CAz(ME5RTPJB3V7p;j+s>qIsI+rPTba5nu0CL|Ge>OA54e3;w=B*j>_of?Ai>{$kR8skHq`yG&|xNjn;~2RHEGPnon+l{SF1!?%e0 zT>(u=+8L#jwKUx%?W&~5KE|=Pl+AueT0hh_(%Lm9Z8fExLE2JM`z2}riWfQ0UC&+q zz@)tky9}nPIcb02Obh*E(td*4&$M=iNqbUhZ+?V*-n*I7Je{=jQQJ#v-!*ABD(!00 zen#zjhLE;3YJIf!Rg-qQ(ngbZ6!?0b$S>daqCl_WE#dFJ;=#8x1&UIEd?`?b9KdU& z4Zu!}*V>m%+D=M)Cr3X=i%$8LsU`cu)1p zI_~pjQ7*4{AHW`q6V`;Zf2PriKaaG#u-#9z_Pj}ZMrp4b*yn>%dycg8P}@^$zcXo9 zDeX$qE|%IIr0tH{B3irLq#doaeMtLO8ZDHKq%DowjI})8r6z4#rS&6iXd2~eHEI7G zFY-J=YZsWbAxe9A8ICtdYQG`vHq@+QQW5rn^a-gxWvXaGzJ2w71~I zfOFK8w3m#wq3~hi3X;Bs(oeNC(Inljq&Jpgm%sShXxkX>J0_5}Ici_i+E|lziPEkj z?JR7zsfVOKC@rd`@0g@xl(a8N-zMoalAaqUlDzLr9_&z)^kpUWCut)ZY=4q<S8~ zb}&iHDrx2t9Bh%V>G#UolXf<08)|JmlQs`dWSC(|bPY+XlC&;LKhx5pCh0OIy}1~BJcp!@KE(sqhSFYIdRdgq19ym$t|sa0B+Vn~ zsj(u(#kBOiN!n6L-y~^0l!pCA(o~f0U(I7ZY?78&(vl=Cwuug(OQh|N_qir&?IDx) zE}S7T#YYz5V1M68Yw;#&dtU)8tdr-Q3l@ZecKJS~W*jo#+ixZFy`-RxW$iA+d*>7rQfRcVe(rz2+iuMR; z_m2@1Qe0~{o3u@pwjXJ$)95lunuyW^D|vKjCTW0@mLjQxdi(=Pqft6ZOLv;2_u%x8 z^Kmp82m1&75pwb8M>dhRCTc^qc9}_gRB5M^cJ~I_fBOPHAs{h<%Qc+A*a46t%sz_Dz$vjnaNe+J;iwm$YM0>(bhn zP1@2*+n=P1?ioXHMZd?sM+*QJTLaSv(#1~?GwCf@rKqqM7iA6B9(RxX~U(q6lu?(wuILHXKJ^y z(heZ4ugr5%($>ZCe!rZ@d)K7B1y@!$M{d$y`ikc0j$pj5yKy2{Q?&MHllFwt9$$dt z{g$*%&y)5DY8z{9hDp0XX=jpliZQ4KoZ1hQGz)J=T!Rya{5<$;lk`0$Z9&pEWtTUR zb^&x`un)nUAwS7AC zOa(eI9|u2YoiV5-Tod&n?N_L6qP1;J+Tlt&i?scXn3nKetSFKuqVzgAvj5>GX;&qE ziKH!`>A$?Q_XY)u!9Xi@pf;vJ)l{IniP-;A>pGh=AtMc-NHsB%7@F)-M^mJK;aU}^ zV;x1hwwCVJ4I}M^5n?)ATHDj4{Yh#2llG92)e6qYi6otY(t{s!v!hJXjY=9o($7%p zNh4`zlup*t6q9s;k{+9fW1j;4GxzB4H^6mphGIP#E=JH$$J%3x6{BK#FqX#^1qFIV z$vol?<8{@;US0i&2lR(2QYRHDjC$4Vd4ceB;&uIpUHVK1sw1{1*#6w&kE4lq4>%(? z=i>M(84+z@KNut!uj?pkdueTFsTI;Ea4C+`)g-;ShCZH;ChbS4EvB^*Chc*heUr3% z*3j3c-XLuZYWJt`;M9!*={q^o;Oalg~gjh($(*a zRkK`6@#;dJp$;qQt=ZV+oh1F3q+?L}x|Yr`wYp46zaZ%xl72+eE+{RorPEE)Axheh zq_2|{uLQlWDkwd$jK`W{lJ-;5QY7t4QoIuMy7Jx=W1Xa>pPQuBl=SE<9BV0*hJ8sL zK8(^(E&aeGEvlr`N&4@6T2UKGyBxJSOS#8OP1?)zx;OkvVew9XE@26m(MmmuB zdf%=B&7eT{5VyBu2_z%){Ah>e4TXa)O#uq@&>fPnS+mppFIJgzhi-hmyysnBE=?xuen~vm6R)N+~poHfI`i8o6<6SXTB^KK}>ZG{J6zL5W zX#hp)^t?#8Fubk<80q^(oF&`_PijHJnK2PS! zd>>E1EZsB)b%gCIorW_JrH!>T)ijzjN;;FI@EadO`ZY;oPia2m*o9Kxg~ktI@OHhH zVh0i%h^*%mV(-U_X+D(9gPUm@+&^<=N=uXUFYxsemcN@mp91}Xfu`y}qfLPhsX!;D z;ZS$XH3mh()#O6b9z|^vt(|DnZdBS?r2Wi@iG<0)`SZFyLh1Dnx&QM_(pgIS5=qCB z6nAg0D-NYAwREmY`ks>Bor*nvlcdY3!);L7M@#3Jq%D+m9ZBnu6yM!@U8Pa#r=`P9 zQhz0lA*mImVPmOP__um6SBF2~vEo@=9!S}9)3 zPfo$Xt}*U(ffRS4W*4Khsg^b}NtY?akfa?@>e12- zCh1xw{b3T0HbpjjjI_b14b$4KCap(l=a6R2dMbd6E zQ%6X98nvsncC$&_RB7)|#4cB#ZS;5@mJ~@7QTnEqrkSJxO1hq;4%zH)q)k9=Nv%C> z(*7|^PS9JV{c#rl-dWgH(l$fw5je%m;hr>Uk1B0h((ax`3*%4H)42QxK$ISZbCw*gd3wK5(sCqS5B@W6Y~_WXJTQ*GEz&+s$9m?#P_a&q z7sI!^M$V-9#vFNF>rvcPi$6Avp|=vxMzO2oO#EGsuw^v(`+zlFf-YJ-6$ z>OhxFfvT!NN5ej)9>L1F;)wRXQrduh5%+*Hz@oQ@kq)61kShwWa0 zoktGfh)Mgs(l#OOb|bAPd_V31Nl#+4DO&ogNxD!;bH-qoryC1jgH8VmNl&1(yOtg| zNn@1sbCO0)r(Y+^BJFh4+O;;_q;09RuaUMMHTxY&V^O*r4q-XiH72QDNsE&7UINYZ zdeT-v?Fg-1Y|@^C)qo$a>>Z7x6^HKs%=97(R15=E*MTOP0xeg8#!;XT5^$zHb4dGL zjF{=4;W&~57-7=RP}h(Xclxx9Oy< zgWC35`>sjbL1~wewrK*Lht`tz@<1_w|6o1K0VJEW^_2D%(pE??Hur?zQ^LjJbuC5h z*IK*HqzzKq{5b5hANYC(_Nsv-J>ZG)* zlC~phOOlE|+y$u#N9k8u`hzH!(z;6e?+EO1d6ar&W_(dPNK4I``FEPk%x02a17A
ohobk@{|Qz}p_1==?aD*q?aeTwuwMiN7iiMVKrv{pr`Op#Ka*Cp}S z^&u^*F_1WbWuOZ>P(SBL73rtpn3sXiM3U!--zm~ejMPd;I;tZ%JE}ll3KTYtmP9UT zhv7xseSl;yPMNfBrEO1Ir;*wRHtRf+hGMhpwe-A6dS$Adod4d({-1%r^a+0gI!vw! zAJo33wdOVPjnZx*?RwIB@YLsZ{nlU1Wm&B~WNLSj(!NXD8Q|-wl*hXh)&b1G4h)n9 zgd96A7P&Adsz5;$=-sJRpA#v7BF)A~bEg`g!#~jVL@VjJ_i*fy&+7wTOn6k(iEw*iqwH36?$Hz<`n5}Kat-J5J?8A zVhVHe;$ zkTe~oUuo$;leCnQ{u_&3wojp}ye~;R619W0_5+i)q|$CCt&N)ff~4J08mOgSlk^TG z0ar;ZNiR<}PPKxgAK$~nN3y8>VIq%qiAj52X)BX9b24_>gYWXZuKRsOmgi{gdXx4$ zrTyt09PZcP>(wd$Qp#x>z%dNeN(VB()8C{5c`4BH$*{-#Po&Ef=_`zMKOTqU2mh@H zKMxT9uqm;txUJ~wOhINq(8#2I!4dFZ`$7gDh)jAV8a~PGRbLEf`9bmf!cGJ734%Z& zn4JN&t)Vv3xBb3IPolFiv>-(AXG)0PPxSSnioR1%(uvM6hT9YDg4W?*80}^FF~FUD z+wX^Fn=@R7;1JPOuWKR0zj<`%CQM&DfW3Z&=)p`M)o^8oza@Am!Oa-nsNr%9Clfr1 z;G#qGJu)FFnszb$HqlFn{&k4T$4m`d7!D)&Fu`dIkI=B4;UWTtnMm|Fe;`4E5QrJ^ zx?dNHMCYvuYF;kx$9()rWN!}LUWd+Q_-lfF;4p(!*Jik(hOaO@!$Wjkq8|@dLoBK3 z-Jm6 zGF~0GbqRLBRS_(cFBqPwVb4RRpYFvW7A88L>7kmw&hROMixT__!#y;7lHt_^I|;7D zaLYPYIR3<@1OHf$=?O$Xq#@pkQTeE;LvLWX3&H;pe30RC8vdN&iUdC;*bp#WRl<(v z)bxC&^S;G=6ro-ZoJHh=J z9a(6<;q^9|->IKkZ*zEO+U$IlF}Avl@fDhzwhY5E4! zlZZY>^!@&7i2F6{%lUYf;9CSAX7~#Y-{r_b1V1A9r3IGf=^1pn|B!VwG))$j#|KO*?Fhv-sF_t5l7rr#&}3BgzUsZO`luugRwf`i`1 ze(YknriL$aWKT(=Un6>fr0GJagis_pe`EU3U6_vn1P|oUPipd%pJq6n;E4n`VmMpF z--}PD=mI2(=mkVOnLeiJOb$JO;57uFe^cdSlZL-xIF#U{1g~d!p@2QK`yOK2L9}Zy zW^WqPV|C~w44+HKe1sF+gW)$ce30R<2yRDkFu@+!^;&3pC(~1j4kP-XzG{dSHT)IB zQ34j1v(Aph9~L|f?NdQ{-A`)3XmPWtMv?m=>2ZC=p|1;sM9Ccb@0~crxfC~!;h!`- zli?!-FCw@d!@D#*p5adg4DWxI5?z|<)tVl}^hgSwN^ou;m5;d^?#l4X1g|G}55vPW z+=gHeyzO!my@TivneMOY792Wf2j=4x!EZ4fsp0Aje?#yYf}1kjm|>68kLeEtjk9== z1WqBK2`MQlm`Ps{!#}p6(5H#K5Uui2ghM-@j#UR&6M}ywcoW0-t9y9L?=W4M=!Zm4 zXZl=qhHo(Z%XZ91u_1W8^kR6whJRytBf((=*94f(|L%>N{+;OrqB|4)?;C1}sTw}Z z@M{FOC-?-zGc}yWa1DZ+4H55uyslKHM`(I0(~q{{5MQRyV;JtC;Y|!57cfp@7vkFq zUQD9b9WDfk&W{-We47VD#}HbUL)X-y7cf1V`tcsYH+rjll+>_?;SL0kC-^&tp9J$H zjt1C6dqN=5i9|1AI$P7jIrR0d*y#lX4`KM2hNBtYOYqkOhckSLV2`-=eU0gbMDHfL z7}NW7=xz)TCin!wmtI%-*r4II3^ybAJi(h4>~R~KuE%syL3>?E0!wrr7b3h+o}}T* z4F9?X^Kq3zzoA0A`)jx)!)XLthvM;4$HR1lrrk`>B)S68PkN~#*43~N!@UXaL~s_v zB{W=&;o1ayz9M=R(~qk00x87w-CVy~BS=*c>CCd0SVFdv-|cE>&wx-W%3!0?&c(z)*_(1H)es{3S)Mj4;dueDtV8?`Jxm=zSFWZWQ%{Lbs&Q z8yS9u;NukfdkK5pb#>$vhAR>LgMeWsQkX8G>6uL5*@*c#N}=Cl_)!&J5#t#?Nbs)& zw`TZ?hWjvV04&~#<`C`A^f^tpXL=ZgzK*c_N_TTUb_hYDvkk+o2!2YDcS_jn{z6A? zgs?|^0`Et3?O~7*uWLTj^EBO*L;tY>^U;;y{tS=Na3I4w2%d|uJLH*8_Y?xS5-!hl zBGF$_Xgh~)t3#JyxF5kc3I3^@TBr3i?9XsRf`i_}5w2snj7QVOnYI!A3ei)TwrTjE z-s%uIyB_n=o8ayerc0kYK{zkh7+y>8y98J5mhX{ASGFMOqW3J*lZhTn^n+K`5RYj% zli_Xze@Jj9!<#gGfZ-|xZ+TC=6ZN`2VfrIY?_m1=S2)CPDf9@2XK8pH!-omZBDgKX zBQ?B$;g3B;|44KI({E|o!}M^1FA@A#SCx+r8lJ&$1i_C8-pz1`hKKj&I{~ExjTf-F zB$zJ*G$C(@m|l0F5aN5utLrcyw~375(1mp9m$)Ch2>zYm#th%7EM}bU1cWiYfanKA z7h?Jf()gKaS%wD^oJa7_uc&}zzZUcHa}>fo8BW*mpA4@j_y)nA>P)ZF^m(SI5q+EJhh5YVKhW?2hIP3d%qR{P#ycntS@rwXy=Fc(Ql;9Bre=T6T6L413yP5VOdOFcFICQ3lw=;a<3(UuA zf?sF&fQHi<-bC zaLq61PCy>fE0~_3>HAFoyBdf1%4-;UEW^VzT$tC#2?2Xu-2|2BoGUbV6*)x1HUZO} zfK&>dNTJJd=qOF!=9^Z!^Q+5qzHD<_vqzX?iu&i-^8XbaAHlYxqNkhY);=;NLo^ zd~DS442HuAzC-Yq4tysdRnx z9SNSmuuH=w8O|bj5W!s-wrJSdi|+)iB6spb}Ap2 zH2ep{oe9Q`4Srpd;UfZ;cLFXkU4iIdML)z5>sl-XUiTgy`V_;rQ!yVt;z;(o-sRA1 zG<=ZZ{RF>4a7%*4oq$D}KFst|qK6Xg%b~|ZVm15)!!Hs1DZ(Dt zcBWs`bPCfYh+adX=P}$-!;=}l{5j_1D8X+s9ID|F3~v)Ky#M)?=mty&XnGLSb18Hl z!B&Rz%k%o^#c*GOONom=uj@=(m5<*w+=gIrC!jvjHHcor^a)Kj;?Nd?LkXV5aJq)8 zGyLOn%ttSRUuAd|!*C~n=`V?%Ky(n(A297K&+tToR}y?LLJe`EhD$KqmEaQuA7c3Z z@*d7!6{af_ok#RXOuwN+7iakHXE?-r1i#O47Y+X-POo^}eot^A@lF$d9R^?@IxW^O zZ}`u%mGYzzU?rfWj7HZ!0U~0e^DIYukKhUf|Jg>Rz^4KhbYd=p?2uYkCKVzVa!iU^u}87(S!nT@3Fecpkx_41XtJxf^X@dOp#sh;}f& zMTg$WaDRdi5qz$-%ExCK-pz0b!H)?3ieRxDC2M*+({`dC6FrqfPu6fc!#{lj`M?X< z;^I>^uj^I8)5YjYL3!P83LP$qbplRwmP69xs>Y#v=+MhJ^c14q6!-5|YKSd0oXBu@ zf`bS?!f;IuPhq&KfMGYnPZhncPnj;M=?P3f_!xWLkwTAT_(@q_O_LbTB)AX3FEgB@ zVZ2^VdPVF;pAg-PXgAY8YC4)jk05v?!8t8eKK5$(ZHC(tJdEIP7+%4!$JvqT072s{ zP9i~)5YQ~D4!}%~1986lua7Vv$wUs~&=WYcvk6DuP4Fs&-AyDcKG}qK;{${u(b^$p7ztf12NP8FkC&wgT3xX=;s{zrXXqNuQC15K)46NqZ!W9@L7hB z5!{d94h$dAa3;X=zT|SE2NE5~^d?Pj<D|<|-d6G`xx7_5_b3crU|C2*&%8 z>zFP>bUe`unVzddf6DN+Wtfkd1P^9-hKA=d{4K%D32vrfk9(@7KV~{v&|a6nz!IHb z36Z!obthl8Yl7clc$|ihGMqthXM$TGjCaFgHT^x)i-~SYw2MQ(rr|V(hZ5YK;OwR)j!F%16H9U*qEdYy8 zW42Q0dK|i(raes0rqG87&TpcI=+f{chNB6-Oz>%jeKb5AVZ0kwm*^Wrf5G(i(tNk#}3!}}Br*I&JvUQKj$qAM}ILD7lM&J0f=IE3Ik zja5EA*Kj?CyAWKL;DZd$_h`B%(-nzsO|-%ER1KG8I4>FV(U#z0499BN$?yS!+Y{WX zalS|14SP+~Io;KvxQys#MEh~*jvBte@Vf+eA^49*Dj#h%e2d|h1P_n!;4JQ7x{0QL zX4;qNc@#R4;f5MM!|?APVm{Ur+>ha^8vc#p?SqKkOLRk~-I_kl^gM!35o}}lp_|v~ zw+z2Y@EOCp6mI(eC6GjCI#)NK>T?upZKz7uB^_%q!&ZWSCwMZ$r!@Ql!)HFg1pG;G zH-vGU+oS1;Os^q2o9HSW`g0BUV|Wt5KN5UDM0I+;hPyNTD#2F;4BOmcrk85E3)4YF z7io(N;$w!BHQa&WdtMx31%ih&oTTA!h7SQOwz-BxM=(82(~X(_NQB1g*Y3po37#%R z>kG>3?k#k9u6m#PF^d0j=GH!Eih)yMX7t_r&9l-r4N$>@N7cg8-!-X0C za{=a~(#x22#t85#5OChXK5dA9RCAIK(7^R}<`H_zw*~WOx906Cd_L>kqmFP{9_PUp7_z}Z}30_O^bcW|@_zJ_n%)@*fBiPf6=}DSC$Mi;`FA-gn z;o%xS%5Va~j|l#^j+*jl4S&z@YXbIqTxSFZe=k^w@U7%4nqJFv4GLYRBhF$fhiw;4ut0*YF$(!%hF=M88gSN2Xh9dLoDZoZwi3%QD>|zD~7Mn!F(JfcnHIgY5w)UT1@XH`Uj%J zneL`TmtuG!!FLHR#;_^Xr5PSfaK%nIiI-|YKIo=@Jsr9T)6IwuCwjA>aeb80aB+r< z68sv$vluR_;eSHa!S(BG%tvp4;bUgk8%#ea$$Qf^rqhTXM4{_2oTK5h49_HZFu_l1 zs!m_fa3;gOXVXppkwj-Py;su*n66EshY`Gr;dL6`#PH);IK*)Tk7sy^hCdQ8-Sq!~ z=merWGd)4m3pn&jfGn*wAo@+Bw^dj0FB-D+xtegc-a*}i4^6{4FE{XNtF`SEH>VYm{(4GB(>FkJ}!A_R%f#SGs` zz8nh+7Qs{$~o&{h1!4X$#Xk=!V2xfC4$9mwtj-f%h``f@M9H73B4ydFEFn=R0wgMHl)z0M6MGg zo)v5A(A&5laCt4(z*d5%FkFsdk8>x}XQv^3lIZSCyO?%<#qe5!a|y1>utme$8JtRJTr~$g4c7}TpJfDIcW4N=13o#r_@OFZiGu*^iU(j2b{$~>QGl%F=Ojp*S zi!*$bV7s`o_PW|LTvWsVh+`f%qt6I#KyVoW(*^y55`3s$V>*uLK}27xpz@KU;Rg)2 zBX}0U-!lB8hI1G$Enu(907_g?rU?=5ihDJEf$7|dm=Ap4>UF)%p*L&z62p54en9;Q zV|asxFEjk%M7p346z}@It|Ckun!d>NTNJu6!57P`d`!~tIfk1OJdNP586KkHy8@;Q zdLN=cB6YTWoX7Acf^QRCi{UT{zXAEb$Mkff%QeA#{8vs5 zF;s_s%5X0M;}-fd@y7&DTd2jTxWTrk@XSjVv3(lZ8*Itei^iypwuTKJmx17o4@M@= z3J!5VgrrA@r>9ux0h90qB#lqEO}F?6sbQSl2){ct+{oK#YvXqxt~xEgvwi}&@sWJ@ zNu$jsTZQ&Lu#xLw;_t4FEs>O&6H+2SKk0n#a=;?J-Q!^!KY39E%Os>2ATC6%PmA<+ z4Gzk8Uot-5Wb16bV&rbJHM7<;s(fv0Yi(h?{k5%i@lP&@Fo>n@-1xPvsMR&3y3LZ4 z6)ZaM?7Z_}nyrr2x@qU_&9*43b?VNDt+rY=Yw*r@x7!+6Z4W|>k9OEXtXqwvJ8TDk(4D-EQaIgSK}HSyvf-kJ-Mn{;{*%aoZ)Q z^}g}wl&z=LYIHqq>rwT$9?;)JXM!7qkf=V8>#pz`{y-eT zW#&Wcxat4|BJi(JCb=4;;}yOZyNf`;e7CPC^t$4qFf!?UzPpq0!H>4; zp3nlpi#+2)?2fNR&b$#6IkQzq(OzWI&tn@xn3CAg#VAqYsxKR|VnZK_LiiGJDbbbv z!kKw6=uI3A4CXQv@L(cdD=LC_7X1k|TAs1h^fWiu1K-2!&&vi0Y@Z<`n6z&-l=GzI#VEW7Jt&pb_ztEhpe$ zt{5yV^2o#~!I1o%e7C>R@|>-5$rYjoj-Dt{9h>jI?Akf}oGsOEJ#3V?V0+oR$LMjv z_ObP6k|pjzE13{GI``g@r}_ErUyZc8wsIx!{>}5z1SSzt82LV0i~!FdqsM_5>$D7A#}^^WD33?2*WRw6n=QTddWSY_nPtt+2CA zXdo`2Y>hJxq>Hu3iv(sk$=T(&m;iw#XDKYd`jrqkfU94{=Nx>#hR-+f`4&7MKQ5Pk z($Bm6AZorly)i^e$`X50c?jpZ^8n*TCieA-OmzPtJUlFOR_EvEABRPSv8siNmj1-& zzwkL1pAR$?<=^A;VSGM<&&Tlj1U~v3Zcc-?kDR&zctfqS?g92|Rv{~`Kg8#Kze-gv0*NN4S4qT`wQ z@Se#z8vxjPKL8_KVZk-P9C8jaj{j||>7V=fasIgY$hTb;o;((x&i!mS{;@48^#RNh z4WH7M&}yc!?jKvdzyVN^FZPYXIo(_q%XQz#q#vOxkvnhxWBbx-En+NrWUFqg+r;?h zk?pfWO`@LU=QK11{A>HPMpan4Gap%f#a}eA%sw)%%VB3RC=yc)?Y4(3LY(SG(0{hF zrR?POgOumEidrm(ohOX0|JfpJ5bT5hY^RGa2o*zV>l5j9t~1_$45=Dp%ztbf>+3uM z{i~kWCf^r!otv44>xnJgUGtXJ(spL1wSA(q0=&FlxP6kdl+pKz?Ir6uW7!j1+m7x` ztL2+QqAN4ApB{D=1y^+Ju+ssr#MT9QyK~rT@!kDbz?kv?-9GI66MR|q6TD2Uc+sf% z)YisY6iJ{Vn#7s{%|5D4pqQ1J4n_T}Z4L3NL}K3g&uY07{jG zSH8QimKjq#(sy@WAk-B$u0FNZYS;G$kkgOUvRJH<|D1}f<~ngmNL`1(z?pY^vB;U1 zzXN{<_-%c6|Lz_WAex3K*`>x50n_voqes52X7SYk_%6*jFths2>&C2nTUBc}V@^*DGuLe8$`Nl^gz3pKuO>7T; zlh)fIPrQKbsXtVT?KJ}aWzf>~_U6{erGMIAx9&Gyvf4*@UaJbVNyqZtJ>f;ZyNQ64 zGItkoSTbHq{K+0-P%VfPDTdOrrC>T;a9%Kvxr;BcbfDvjY@~b`Lw-z$;oWo#m@^ zxQw(!zLx6UcoVuNhkB&J&fZvdziJPVYl0>TgMu;?e>aw zmj?;FgI{D~2e@=g194JDWT<$(gkF1J4J6-TjI!HX)Vs4!j98rO{>g$dSKSXT{N>>O z2huGOxGh5uE8c{{{OW~_b9Q^}R>cAFU6OGCj><={)`ZPP3ujCp(ea>2Z^bn&LE>$d z3g&vr$RxYifD7fj!;MxBdvMvwR6Djn?c*9oYlpqGC%^g(nDG4SWAS+!KBwXHBz!)I z&*Skq9-mj@^Ada}J`P{Mh0ho9c@8XFST^`v5}&V7IX=f!7qwl)bDQehuxKwn`yg5r zpNr#j34Hd$=W_U50iP@3b7nQ8lG9!xv@d#1@Hq^h!||CEgE4k%e5Ud(#wSjDvzjZR z2Yi)tJkmQKCe)JKq}7vrQL6mG#v`Y_p0%M-qmaF-|LT@p3x~ZW*J1Q21hqdHa|+pm zeM?pr5kVOx>Sh_c3fb#ch=H);Na_zK-pC}Zik!JG5N7#m(6Ykz3byP}qf%jejq;Xf zLD;K7x6cp22FAd`_NMMM2ycoM0|0bj9cZmyBdf5zvh`adudqEZdT^-hWzzfz0rh&; zhp0ih5l{x*5%u6l7l=NeBlVOe^H2Tx`#ap50@V*l|VjXN0DQa&3SBBw5A!l=pfko}j2bm_^ zPp}6Y@Dyi=Q3vP+ktXU_>w3}q-1~Y-z#l(=Y1j2JutVi;GaePSH>}!T7Y7O1ST!eJ zOhRrzi1AA?dpY=E7A94*$s)x4`rM@iQGcZc`)Q*7jIKw18zfJz;W*LOHqA%j5VRj5 z{9xT)=_nkN25<~xjYq}ob;}2pH!VO~<#H*1X|yR0zjRg9c(b^@iZ#NRD!ensN5$>c zY}pNsy~XY21}$mMy-F6X&Z@^g_F}BAj}xOBtn0%?rvmgSqeOjsT^}LpR~yY;(8=tw z&va5$$xaS6JT7~A-=l%@D2)^Nr-N|4?n-{*(8|nrZ#Qy$?PIKijDCKw6TECp_Oth}<&`i_`q}FQE>TNc z9^cdVrHIBi8h-w`QG^IH+=vpUzY*te53F*fCXYN@jO2{=#Wi8>L1P`zp^h-d@eXFrIDN7ro0}t^GLRFVTK- zDez}$KTh~#wI3z?!6qNx_vH4{ehB!U-1fR4P5@1`j|(bT`yv~;0osoe9d>9xMELis z@qprle?|LPf3P~&Cls~34HK_{2zcX?yG{Es!e6a?I2{3_VTvuy+)lf_K;>+NaW1*h+z-q@5yd zmbAg!s6I~Gz0&?7?cdUt-cDSYw7sPrzukfDTT*1f8EO4?kf5Km%cZ>}ZO~4te@oi0 zq`f6=NIKPzm3D`;|4Q3(7uC<$<)IgcWI@s0 zrQIuSp>L_YfwY6AUFnf8ewQ|KFM(U6y&-L_?_|T$9+lRSLFF$?yG+`<(l*&g_2Z>Y zm-ex=o{swom@n<$(uT-IG+Npn(u(yW9-qp^mMrZiX|ts*euUzdmi8@ayGq-HtjBUl z3hKy;AZe)?i{)=wul%P+Dexu9AfV(H z%Uu~@zvOmHdr9gQ86y2I(!MY4JZV=;ds4&~>wk+Z*rO_>{Yf_XrL=ctd4TL#khBe? z9VTsiX?sc=BdzLSnDqC8#pCZ^*+8HiQB`T{N!vu)qtdpPwxhJ&q>Yw#u(TtjjhFVK zw5ifUhv@kClOt0-EL6aswu$C!gtXDprfj70Na;6{wt}?9rTtfOInw?lZRSRK{O^?o z8>C$#g{nh4q<>u6-=%#hZ3%g{t08TKw9(RzmUf=B%cV{CkuOdf6D!**H_!67i|cYr zUIDB6@rxhTEB|;Q^3#k{mF=Gwb4YhjA-j=L#nHjY2(m}`*J|m&pfSBIXd?{&D)!2? z6IvB0{*S6t{|E0=#ojP9tKIYQ7D3dRsP+Zwja^mjH9c!(E7`A8^c7a>@h8$+wo`f3 zWwJ|UdDJ8FKa~CuY2TAJ`8L&O-yxeQ%V$bEmF!EFptjVnnUyq| z+BE4$b}&A!YOiDqdfC`r)n21-NH*zJ2eTfMpZ9=lj7r~Q@-uFcjgTD-xkrAghaf9?|+*-@5{l;s1+ zX3FwBSFhvn0ndAXi>!4Bq#lO(zhI^`V{bu z%h&7`jGV3ZJWuQeDvp;{9691KPx`6S!aFv6q)Y$2wD1NGA34(Zxk&M7Q?Xcrq#q%z zQ}WT|do1y?Lfoeik2L9LNek}}@Zs|-1+FD6ymiM%r1WE@tt!jsNk3KE2C_Uu`q^k< z?;I>E0xwYmA<_BN?g%yF1Ea^X#HdB`S{U+l}D{i6U-W??i;-ozx z1@ol8R@#%YJX894(*7XJ1G8lV(q_r>28DBit1Qn$AC`pQ6$%L7g~3O-^rNNyO_rxfKV8~v zS)MI@pFb(iWmz5}{TONM$)jzp^h3mqiqkp#gF<{{$cppQ!cAm+v&*yq5(D$;!?;80b(jJoKkt0z|1*q_ zd9q-ww8vz5hV-+gJub_AZcw0F(w>mz5z>#5_M|LNk$#%AKge=VrYy*oHcM7mZpsFv z4U&6*l=Nezts=`4q@N;fRau@U{Y+`A$?_cXTUh*VQA5G10qMs}TU`Z`ewMT~jD6q0 z{#8>}C*P(pY0}n`<$2Qg%cJ_*vOGrm$1JXxH>y_oH(oYvw>>nSC(bSlK9A$ zzR$lDAMO_5qn7j||CRe!X;~2`E0U!Z-y9H+H0fta8%V{LJn8%WM-9M@9DGDbKStVe zvV5NO*GgL+^ADBTvcU3~0#%TLNa@E(TUnN;Nk2>4AX%O#eZMCZr<#f*{a9&(Ww~dq zEXb0!x~%YdN&$kTtt-nTq#q+~Jz1V2{d8&T%kmuQ`{YwR_*xG>!pZkoVq`^IS&<<9 zRB2z9<>#dj{|E!mdF^C*tn`zmZ7<6oNRmOwL^m}G^7Y=W29BfJFS49ZG>L4p9}SyNix|V%kg6Ls@4n2(+vL` z_A=HuqsMhHDaI(_oj0ZnFON*55t;{H44Ehr#F9xN6L0Lxvj-Xr|F$=@W>AbQGTCGv zl38n<67e(1ZHA6YA2*dq^gP3ggHmlY!O*8Ef>o1?{C9cZ8QkCWnm0xO~fA z#z?&lcez98b@(lNs4)r(j8nIvDqXya5cNS=0OJ$o5Dt_Lt??+b&NKX#0tSXatYH=D zNFXzhvXVk3jZ7vPm=Zx+j4F4)1d<6M6N$!%x?>N4tRs*{CW}lS89!sxU3(`OD;O~` zmqn{r+gc04w z!nI_w$mEgngRduoAc#x|nJ6-GWag29$%BO(8ad(l2SLmW$}@$mp#hh1fzYig|JVaV zMn6A7#-it!=czR`{U7LQoFPovh!?_0!BHmQOoDyJJwNhVby$d_!^pk`U4#QhtW?Oc zSmRO9U0CDdFfJSSf)>|edW`IU?S4kw-*z9E13c_wj6sheUl9|ZZ9CPMHjU^PlqaAJ z)~!&(5rZbj*ax1+(u{UQwE?MEfiEbJp8Wi_L#8~xJSO@1ILPoFDQ>T+WrTP#-S;jP=NYMc5@z4sbtd0 zWRb~1Q+D2@XFIB-$%geYG!SouK88IFp2U&9PnaMy##$(cV-bte$Yhd%NfR7wp2Fmj z2}Dyir9e;T$qOP_OaO<@E3np7b;PJ=d#TFjsTMasfn^dk`dMnX3?5TJt;%Z^Xib${ zUQq5=U{V#I9FOf9ou1nL%cd3B58~t%8El?U;b=-2`D`Co%IY*@1ytM4FEUD69Sw|d zyCbk{)c9xFX!vT7ctje5@*%UaWFnSUafnj~mPMnJN=`gF8RTS>c}OO3>2wgKAdn8v zdkj7C$?d2zjNNV(ha) zkn?ED#>YLM$~5i>D#z$ycXWbnbGjY8cw@8OA+8?K%SPkzY5wfyrP{Yldw%4g7nFy* zAdXLganzDm(DP{Z7@Zsr|FY2q#0p9?+BzI%%K8*ow5mGDusUH}5oF*hMR+M>(#gab zp-^bVIAM|G(Cg%4jzC+;c%z)t(J-(;WOa=iVcZe1V#&-S6Gg_)=ursjlF6i@F)|B5 z1JTB2Q3H7vCWTBInLIS1esi8pt7mm`5Oq1K?v(K23^Z^* zNqBJCDa<@$VKFdkjZhyj8D!3rNx?cJ&j&MvT(YrGa9N~^Qyz{g5?eD;3p)ZmmZi@Q zrkuRO4|+j)MAGy5$T80^k1DXbgJt||nl*jmJ1;BX61E6*Jef?a(YC0g%%H#p&qh~K zB3@7)?|lLP;j`rr>(D`)WmqY>E1)$<8k#&bWwQ!oLTU0)tLwO@f#g_8L!dwv%R zUb`ti^ZjRen|#+9zXZz-qnN`VvNZ_i-nb(M5lJSF44flH;X^V(#^vIe+#bSY7{VBt z#T|j6mI4+OKo8WMHM*fsW#S* zef|(F1=db+IrN|cDOBa>jfEu~fq^fmh50H0eep5w2oppm+}P|Z5(h+IB|v0O!MhQ z#qgo+_kYSE>3-1PNHXzc){=quw@_!qmUQ?PQE}kH9Lfgy6*y*8wPnP!Lntk0A-X`G zRe4Z>V@#Fj8KM5rtq8;F4;ddMUMGmxaPeJW{*}V#gXgy#^n&v67nDc6pgfMs^&X@e z&Nix)gzkkH)4>>NC1H)v!`HC=iXu32(7^c@ywJ!3nQJ056!U^|I8aJK5I9hT$uru5 z=^R^NHdTmyw(fKqYKQb;xmoV06202 z3mn+0I^7rq)zBBKFloj@Vc^UpOa>Xa2ohe7aR*G<=mJ+7_ho<6sXC~@ss5>~h7-6O zf&>|DOM`i6Oc!3Vv00c*G_`%^Kf9KcG^${^aT(HAL{-ClLy)pD1vYtAeI8r%tbIXs zNP&f|WVJ>-+ZiAD$W1(=UQixVVBCt2vEzl`&U2+5yNVXckT>|Vc79aFQPb*Z5=l4e z1B~-k9ren5dbad1(TMm2x;WfjKOgC^oDXp<9%LVHOt0o>=8S6Tu+%d41v|Y?H*&3If7UJR(LyFzjiW z#z(=9nnp@>ho6yE-Qi=T)pR(Fe$^etos5=(#{Ha8piD6KRd)!tc#*gt9hNL8S}Te~ z4^de%2a5R78ro}ZjHvFYV`PX1)>d}}+M`-K7FKc7cmPlj0IyYdR4SYbW$^+jYh=}O zI4Y)_m>hWR*9Pk0Co95Xfla-Zqp}fO0|o+L*Qfzm4mbR3!XA-P!{I0!1(2m108H8f9xi z1bBZ0##SrB7*@+s1Kfo$0%v4fhb749QJWGORmb71043^?46oDS=b2$QvqiQw>ePl9 z*+N*p>_d~{f9Uc?YHgT+kUEYanx~kTb^LgE4e7sH8|Gxma>NuLgl4@JmQOej;$5Fg+3?Sj{l-f}-9(?s!3$OpDqm_+Xbs>Q< z#=g3a@(}9Rx)2c;Y$;JtQr%3g4=sl`05Sr|xQ-C7Ba{B~z*mn{crCjd)Br?jLKJ%r!b1go ze@J!Lr<2wMb~5HSfbPPZp9Zk@qZ+CiO)x~z7NqaJ>d#*BuJ8XiHYhq#AiPp~I+1+EvoP6Znd)@8F>s=?1zyWP^esNFIce!hnv zzhZXFAo%H7+-{i#Kjll2OM|gP;>QLL z9|4t?41b6RR+R;Zgs_Cl;w^sFc77G&SZN&+VYgZuj2=8_>>yBx{Z~=v1}n?Pk9>dZ@WJ4V4crfMC(9>Inl$*Wcc47S*xblbs(xNqhxn^4 zP(AkT;Ld&f!b{6Tb6Kypbbskph+*7m?mbT+4)6d#~;-UpJ>PGvhX`b zmThs6fp6g{6Mh^e;FoMH4dRUNqa8H^MD=}9{RE!uqZ}4niKu0L9C2>=uAyc1UHFY1 zD60ao(KlxIalB_eY24}K2=?0nQk%n3sLE(i`6mP!)%!Zy)E5EYhmu<3;3)xq93>*K zJ$NcKz|z__*kLJK$Yv?j$QE+aSlHK58RBj3>v$8cSY2;A+Q1*NcomEjzG7(k+F1Ce zqm+EP?oG#Q)!~bUmN@vy8AH7?`(@n_b&D+|!l=^E@d`v8-p>(OFTo9iO%_k7;wcTD zY-4Q}|1v(7GQEmg$}}lrDbuJ_wtt*o4D9>N?&qjsYY=5T?&k=H zo;B_7cnQoXG8_9l>Vo$(8Rq~;MvG!l_Jk8@a>8;u4!8r6@0GBH1?uo$kv5BcyVy@Ms-PhP-9$l&6-&R96mQ64+F z2V^TnsPEy$Rro1dBEdK~&=FZlOkiL;jfi$d zYl9VCH9~69uGULbtl#%DGg+4Q5BUCKUa!x7KF>4fHs_p~-I?diB&UChBXeAyjH2I+ z3F!$|31K$vkrM7ftOmLLTTNL=hk6GND0My9X+8+)bFLD30K7#SY3YC3ndEGDX_wL* z4a51+h0MASl-m3uv+y1}Z^kxv%+NnOS~_JTo1P+zZwunz=9wAV*T&)M0 z=&vZ#9c;Ju>{G-cv;TU1_IXzK->cPg z?11kq#7vOaKPhu6B_IC5e1!R!pB7W0#>5Ex&T!9)ndvv^3$3D?$t5Qn-?NBT^VAJ` z%t>uX>6hdcN)=tnq7du?Z%=h}p-&y{8l`fAjH+?XB15Q-^qwyfZV>xOE@PNw$`~+Y(h%rh8k$jzENMKlp}ZwAlOmmMqh&B^xPhcWPL^NsqA3eM`yWdxVeGz}??#R^FrogQW=_ zI6mUUUi3NQhA79h`Q#>jB6o=UmFm&w#W*%sC4a8e2l{OF3s$k89_90bp67?zFw4)! z5*dEi2v;w+I&tJJ6yQGg=;A%h@xI)rDb;rk*ojXDKEMEnz)tg3sUBuE%X>e~I+>3N zK<9pKd^hXkCri%;afGho!#zb6$k8%MDe;%$D!qe`-^;fC*2#H_%!TfAEoqi^r+LII zznPg=fh`S4GqM-64#l>~G$-e<&+NNd4?C&DNveo)90hEfq%%3yboH{21GjL# zUTXe?HDIZeD8x(28o^St_ZDvWr%dnJdf0%Jv(?L@8Us@1tl4bkVS;o&kY{ zb}dnM{sj;)k4ciac|{6{J6i(;dNzT$`F6IRcyj6*ml{6ZrIuP>s`OrAjylpuU6RJk zxK$4uD$_9bfL4>_2zd;#3FP(<@#|__%sg?c{+V@Py^GiPF&_ubd$;OQqb1wGMI6Xf z;2SCe4DRn8O16M}gybV?PPt9rm@6IqINL*&X4P%_MC;hvjs2n2`4>b#^ZIRi0>4Xp z-mXuvHU}QmYKLsT1Toi4x?Rt*4@t}_sdGDGw0Z7!{fXt@SgzHT9EH9uh-1t%VSf6j z&1Ye~%R1KE7CTLS1ChUkV?FoLJM}>G(H;8!h%_&ZujoELmV&jw<2gDu&ZWYE$re$x zdo^w*Q5EENMdf!WBtJ!S-squj*6wB|L_xovs^6sEVNa-6Fvo8nHoM7i^4om82b#4f z*DBHdiS_l%4O`XsbWd24OGCQ46T2TW-`}Z+Pfw2I-A2Ik5R;*&TlMVlShhOJr3Q*m z(H;Ng<5ZuWPjLj1#yUwcA2Qp_J$LEjtPZT9sLUK_Fm-o1XU`7&d*rPADWcHqzf141 z2VyCwL_(&%?Ff%~ZjPR7`7c^VdVUu8E=9~YKmVP+)*c|t5Bcrj+akg|^E>@>YhHMk zGcWp?oV)c2R=Ps$59vtXd5G)HguC@*%OAtsBmTz_8_bHk^%%>)JKO&k^ZMO-@Yyms zzs&akfZy$G+_Q>Gua{ACZ*NNLRdh@_c&k6v|?d{6t?nc@Al z>Obc-rKi5CTBE!h3iMsUypW$aGk06|;QL+5D?U0o9==x}Q*cBUHfLs= z3$FPlY61hpc9v|r;CRlnuHmXj*zK1I+e|*Lh4|Tq*bn;mO_`Q?y4X5Q`aZ&8GQi~C z=ggD<_R$QU?-ImQX3~ASZbDvzOPvn7YsEOJy!>#(g;8yL@wnz1G7l&SVsk=a%WIHWKoi??%%KcJv z8t!BH8`$=iQ>3KJwljIn@cZ>~y$_og->)w`RlV&}XMobjoKB-uv9APk#7C!PZ1eQ} zdRXsF7PC(ZJZ!oa@bsDYJ(v0=@R(Br zU2qIPD^IjXkrSwL4arqQI(nO5|3RM`3H{Zro&ep`;0Rj^XR3JH-D*1MPIH7UY4|;! ze8a8s_yKSKM(1ex51-3AC_Hjdgt`ye*q_}))Fz&PNUxR-A`{0kPTOaOF4V(L_3m{m z14ce>_u-K?SvYxQeCFnb`l0juJc02W&?#B0{_$A$TzqM#7}=g}XY!cw4{!{I-gK*{ z!9`ElwPtK{#{+uA8UDB2>P=AQY(CQF%*OOm9rnd~W}A71tT*~!q+*cl&YEpYWBKV2 zc-O7Mz`CH2ew)*aKF+axYw-7d(r%Tc$+k23%oU6DF})9)w=UBE!=&84h-=RHr*1X$ zGq>946q2#c=Zo}+Nazc<+5)gWfb2yQ72Isce*KV~PB=2-GcKghh2ld2A^WWK(Pu%KV zt6Z)UjxpN@zIUtLU}xMO!)&{^whz>Ud}+8iQ2TJ(_7Sj~+pdq8p^Nn? zOe?NniWlqSM@b^OQ4OH82Ya}_C6VxCa81TGOBU-TJ^WSLOdP2P^$u2XcM^1(`ybNB zNHmD(k~YC5dR~uC61_i857yP)+s&aR+TWwNTAMYa^`M^dOvc{o6ltGQQFH1;IzN+R z^a+7c_6BRK^AVbD`%=~B^(FdPJM{+->Crv>r7rXRVqMT9P~+5*-8c{b*y+a~rH~ah zTxP@FD92t3Vqnf2T0LX#TdFUNBsN(6V^zDZQLBmxJ(REEu&=X;3z9RrD_wWkH|{C4 zzlSQWKkQr3#;>pO+@4-{*catJ1OCDuDv{+|fv*Bz$$BfDz54&1-2@WO;A%H3;URn} z61HUdj(?4y96rCD*=qFp_`Kxp%JN-{uM=N;R^Ive+Q?g;wZk>9oyyp<#}!%5mq=KS z&zn`?etdan^dPwR(+hOePcP8<=>{Wvi=f|EfIcPrJ(6?z!6D z;c35`c9l{W5#ezhl34!yj@{iO#g5(GBSFXR?vawK&E#kGxbcD4?1Dpk5BI2)k#HWs zY;)MEgpZV2`>bB$_MB}dKSzWZzVkUfPPodkcRBop!$UUP=_YNq)9rd*4>3zO>x(3l zWgOhB3mxM)L%{LEjPb zogGb*sM0>Lf$)*=x1bd*{3A%BGvOn&gqF%c8ZCSe&PAM-7EIkaJ@N_Qb51EH|@KDVmvzJsX z3IAb-e)S}|*p=vP3#WjQXyF&YxoF{CV2b(l1#)mFdM8V!ODHlx%To~biG=Mbc!yi`oR3FJ;n_NpXV zo%9VTC5^C;bwTsc_L`uGy+}wF3-$bxAtAGHf8d$Jn7~Uwi}W|V9#n8dHN(8MOtqth zJAvG@=gntoXBS5ii#hs$p8C;YlZQvzUs5@Q#r#HFXIU!`niAN292Bv~!fU}4v~c|b8if{a1!1)C?-o(nQsxc3tDJ^V zaT4|{aj6u6<2;zxL92P_ApF@f<_kmSJKqg=M`{1>GzBF*t>Uxe6S zc92hke>XJJYW%_rKo>gDj*9qtS8r;8QMjE;|GeFZX1HsMU5?s{ zZ=3BGj<-4ug+B)}_G-IJ-3XXB5tT*^*ukV@gBQLRglSzA9FgOvMUI|i-GJx3~qFEGkp20=s3=_U8mD58GB5lTkh)qU zi1&bGNWs5(of%GCFB51aE}0#Zl-T6dBx8VwyGuQf z7Jd?RNE-OIzj2PC%=N%M9^2}N+!rlPe@QW zx{os&TKGW_M+@h_M^GD`iKWsA39%l1kjAd!{4ZhzC}e{lz6nSLG5B3D6@LnD_|zV= zX828DHR3bQZorxo@Gl8qhp8+RxJFArdpVeb7G4KJ=w|r#$Yx@Y7-6{bdAI7IvSxT0 zZ_tz39)k}6>l6!b;YE32(zL>RTZwzoy(u`%3-M%D3-2NXKLvkw=v_kcbAh5R;U!=o zI+7jrm1yvL;1CrEe+2TFy~3T2PQ#b&v?~k3e*&`it?<|vZGUz!Qi75LUUsV#fl1-h zz#+6Bp8N{`Gy3_*=`P-$*JqbotwiU+Clf|}3!Mp{qO(J*5@LN6XbKXp2Ki{={lJG# z!*#qIuL#`?O8|H(JCg|nqc{DTxAS>;A>JVj;d4M9l?jI(Eqozi=neRT@QWaf&JImW zhD^sSykjV?Zf76V^pbD0ur{+^QTcycg7< zg;QW7TKEd$?DJ?)c8pzO@43X*qf{(B1gu17$JizI9@)i54I6~t0WFef@8RIM1jz&M z(2Z0eJQYkq3*Q8;L5Ja=5j2*wTP8Zp1yyz+Spv$X`r-vTljQ}C#d>@^i{2 z!=D|dmT>iqPI_aFRx=`q7?_74Y{W*#;kCq^+tAsuXNgG%{^3>!@e5A@edF5V?SzSs zM+@%(;?IPMBMj@O)B_gc7k&~%Dljs!dRi(m{3p@`lhML2fKGIFAYKCWMPIm8A&n6J zHJF0V4(dy=zwKW%0>AJ9FcO`H%f4g@1YbhYFFF1_U)e@>bX=n5&w+DkobWCXL}y3K zC2BqwgzyV50dvsVfqe<^e-GkRES&!hM-AEwPXhjMgo%Ur5)?7^-Y&Pg7|0|F!hZ#F zTJ?X+-T;{&N%(KyaXz53G<-f`cR4)=;DtcaWQX4+EI;Mn9I~Vrz8QRp4#R6AKQa;c zW{bmv6iiC8K?&!!t#3*fN@WB&-6e_EQraL+WZw6y2NY=TX!=qS*=pg(g2%?+e*Fgzd9@Y9D zNTYfGx_S;+I{@=~cB_2hk8^rNETa=+rYtZZv+&(O8c_ka03Vuvh^ChCaM?=IB;Yg; zm?hAM;7j}2=|k{lAj9!IoCZ>{@C!VI)|bep5)*{ZFg zBW#doLS_I-6oZ=`?LC$!;DGq$QI*Sp=qOz0=vH{Yqva`;>m6G zkTmi@-?c!xLspr{B9f7GldyY)oi}SK*%)h$*|lu&^6evh11LlbmpWQ_+k?yA(V*w1 zW$)yiHZqc~?yByrN!O?#%P$l+ch>sX7Oh2uC<|(@OjUMPrYpNDRh6fzcztkv$@&oY z$~YEOIh3~{e}i{}Z-akB(T3uNU_+>(w4tma+7N4~Xh<|PH?%giHMBRR8qy724W7ol zMsK69v8XZ77;G$QENu)&8l#QnjTMdY#^%PB#}W2&*Uv8z!v{?YHc8UR8dTugYH)s4A{1sR~tvtIDd%t7290szg;wRclqUs=cbSDqW?jJ=OWu z-fDk!QFU>3usT#-T3uEht&UY!R41yNt6Qtvs@tnm)zaghn!FlsjjyICQWK~N)|Awg z)`V-KHRUxGHSwC}nwFZjnq*C?rn9E2M%Cuk=GXda{k4JG;@XnhP;I!jthT&1RvWKP z)V9>N)+TG)YddSxwW`ijmtW_t^Vb#C71sspLUpBeWp&ZISY1V3qOQ5FwXUtMy)IRk zuIsAv)aTWE>wWc+qWVC6u)d_ev_4!PtuL>ysE^k-*SFNS)hFvy^_}%y^(v8<$WQnZ z{zM>AoG3|z65&KyqC62x#1n}`OQJQAOtdFD6X}Fn>sgz>)@#k6;e pa6eb%kXq+i=UwMpSH3R3F0szPzI&FJu2&m88)Sx?+@8I@_&*`Wm7)Lu delta 106124 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

xH|L2@L8PZU6jF8cR6=|D(-hMEWH|*b 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 LexFZyEdPH2aAR1x diff --git a/electron/native/nvidia-cuda-compositor/run-mp4-pipeline.mjs b/electron/native/nvidia-cuda-compositor/run-mp4-pipeline.mjs index 255c98aa..43324b05 100644 --- a/electron/native/nvidia-cuda-compositor/run-mp4-pipeline.mjs +++ b/electron/native/nvidia-cuda-compositor/run-mp4-pipeline.mjs @@ -1052,6 +1052,15 @@ const sourcePtsPath = join(workDir, `${baseName}.source-pts.csv`); const videoInfo = getVideoInfo(inputPath); const webcamInfo = webcamInput ? getVideoInfo(webcamInput) : null; +if (requestedOutputWidth > 0 !== requestedOutputHeight > 0) { + fail("--width and --height must be specified together"); +} +if ( + requestedOutputWidth > 0 && + (requestedOutputWidth % 2 !== 0 || requestedOutputHeight % 2 !== 0) +) { + fail("--width and --height must be even numbers for NV12 encoding"); +} const outputWidth = requestedOutputWidth > 0 ? requestedOutputWidth : videoInfo.width; const outputHeight = requestedOutputHeight > 0 ? requestedOutputHeight : videoInfo.height; const timelineSegments = readTimelineSegments(timelineMap); @@ -1265,10 +1274,6 @@ const encodeArgs = [ annexBPath, "--output", encodedPath, - "--width", - String(outputWidth), - "--height", - String(outputHeight), "--fps", String(fps), "--input-frames", @@ -1283,6 +1288,9 @@ const encodeArgs = [ "--chunk-mb", String(chunkMb), ]; +if (requestedOutputWidth > 0 && requestedOutputHeight > 0) { + encodeArgs.push("--width", String(outputWidth), "--height", String(outputHeight)); +} if (sourcePts.path && sourcePts.frames >= sourceWindowFrames) { encodeArgs.push("--source-pts", sourcePts.path); } diff --git a/electron/native/nvidia-cuda-compositor/src/main.cu b/electron/native/nvidia-cuda-compositor/src/main.cu index 8c5ea9dc..28c72123 100644 --- a/electron/native/nvidia-cuda-compositor/src/main.cu +++ b/electron/native/nvidia-cuda-compositor/src/main.cu @@ -302,6 +302,12 @@ Options parseOptions(int argc, char** argv) { if (options.inputPath.empty()) { fail("--input is required"); } + if ((options.width > 0) != (options.height > 0)) { + fail("--width and --height must be specified together"); + } + if (options.width > 0 && (options.width % 2 != 0 || options.height % 2 != 0)) { + fail("--width and --height must be even numbers for NV12 encoding"); + } return options; } diff --git a/src/lib/exporter/exportBitrate.test.ts b/src/lib/exporter/exportBitrate.test.ts index 1d46dc09..c8ef1715 100644 --- a/src/lib/exporter/exportBitrate.test.ts +++ b/src/lib/exporter/exportBitrate.test.ts @@ -60,6 +60,29 @@ describe("export bitrate policy", () => { ).toBe(27_000_000); }); + it("scales modern native static-layout source exports at 60fps", () => { + const sharedOptions = { + width: 1920, + height: 1080, + quality: "source" as const, + encodingMode: "quality" as const, + useModernNativeStaticLayout: true, + }; + + const thirtyFpsBitrate = getMp4ExportBitrate({ + ...sharedOptions, + frameRate: 30, + }); + const sixtyFpsBitrate = getMp4ExportBitrate({ + ...sharedOptions, + frameRate: 60, + }); + + expect(thirtyFpsBitrate).toBe(27_000_000); + expect(sixtyFpsBitrate).toBeGreaterThan(thirtyFpsBitrate); + expect(sixtyFpsBitrate).toBe(38_183_766); + }); + it("does not raise fast exports when the requested bitrate is already lower than the cap", () => { expect( getMp4ExportBitrate({ diff --git a/src/lib/exporter/exportBitrate.ts b/src/lib/exporter/exportBitrate.ts index 40110b6f..84d87133 100644 --- a/src/lib/exporter/exportBitrate.ts +++ b/src/lib/exporter/exportBitrate.ts @@ -43,6 +43,10 @@ function getBaseMp4ExportBitrate(width: number, height: number, quality: ExportQ } function getFrameRateBitrateMultiplier(frameRate: ExportMp4FrameRate): number { + // This only scales requestedBitrate above REFERENCE_FRAME_RATE, so 24fps + // and 30fps share the same multiplier. useModernNativeStaticLayout can + // still change the final bitrate because pixelRateScale uses frameRate + // against REFERENCE_PIXEL_RATE for the native layout floor/cap. return Math.sqrt(Math.max(1, frameRate / REFERENCE_FRAME_RATE)); } From b83911cc5a401624a0ec3fce1f90b735ec5342f0 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Thu, 28 May 2026 15:33:00 +0700 Subject: [PATCH 5/8] fix(timeline): smooth clip trim resize --- .../timeline/components/wrapper/TimelineWrapper.tsx | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/components/video-editor/timeline/components/wrapper/TimelineWrapper.tsx b/src/components/video-editor/timeline/components/wrapper/TimelineWrapper.tsx index f09b4001..58e55c3a 100644 --- a/src/components/video-editor/timeline/components/wrapper/TimelineWrapper.tsx +++ b/src/components/video-editor/timeline/components/wrapper/TimelineWrapper.tsx @@ -11,11 +11,7 @@ import { TimelineContext } from "dnd-timeline"; import type { Dispatch, ReactNode, SetStateAction } from "react"; import { useCallback, useRef } from "react"; import type { TimelineRegionSpan } from "../../core/timelineTypes"; -import { - clampRange, - resolveDragEnd, - resolveResizeEnd, -} from "../../dnd/engine"; +import { clampRange, resolveDragEnd, resolveResizeEnd } from "../../dnd/engine"; interface TimelineWrapperProps { children: ReactNode; @@ -162,9 +158,10 @@ export default function TimelineWrapper({ ? (event.activatorEvent as PointerEvent).clientX + (event.delta?.x ?? 0) : undefined; if (span) showTooltip(span, screenX); - onLiveSpanPreviewChange?.(event.active.id as string, span ?? null); + // dnd-timeline mutates the active item's DOM during resize; React preview + // renders here can reset that inline width/edge position and make trims stutter. }, - [onLiveSpanPreviewChange, showTooltip], + [showTooltip], ); const hideTooltip = useCallback(() => showTooltip(null), [showTooltip]); From 32bb6e4025025012e025f9478d723d0d29f77d72 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Thu, 28 May 2026 16:41:03 +0700 Subject: [PATCH 6/8] fix(linux): guard cursor overlay when portal embeds cursor --- electron/electron-env.d.ts | 9 +- electron/ipc/register/project.ts | 8 +- electron/ipc/register/settings.ts | 2 +- electron/ipc/types.ts | 1 + electron/preload.ts | 2 + src/components/video-editor/SettingsPanel.tsx | 10 +++ src/components/video-editor/VideoEditor.tsx | 16 +++- src/hooks/useScreenRecorder.test.ts | 59 +++++++++++++ src/hooks/useScreenRecorder.ts | 82 +++++++++++++++++++ 9 files changed, 181 insertions(+), 8 deletions(-) diff --git a/electron/electron-env.d.ts b/electron/electron-env.d.ts index 32ed313e..6f6ff2ab 100644 --- a/electron/electron-env.d.ts +++ b/electron/electron-env.d.ts @@ -675,6 +675,7 @@ interface Window { options?: { preserveProjectPath?: boolean; hideOverlayCursorByDefault?: boolean; + nativeCaptureUnavailable?: boolean; }, ) => Promise<{ success: boolean; webcamPath: string | null }>; setCurrentRecordingSession: ( @@ -683,6 +684,7 @@ interface Window { webcamPath?: string | null; timeOffsetMs?: number; hideOverlayCursorByDefault?: boolean; + nativeCaptureUnavailable?: boolean; }, options?: { preserveProjectPath?: boolean }, ) => Promise<{ success: boolean }>; @@ -693,6 +695,7 @@ interface Window { webcamPath?: string | null; timeOffsetMs?: number; hideOverlayCursorByDefault?: boolean; + nativeCaptureUnavailable?: boolean; }; }>; getCurrentVideoPath: () => Promise<{ success: boolean; path?: string }>; @@ -838,7 +841,11 @@ interface Window { /** Returns the app version from package.json */ getAppVersion: () => Promise; /** Hide the OS cursor before browser capture starts. */ - hideOsCursor: () => Promise<{ success: boolean }>; + hideOsCursor: () => Promise<{ + success: boolean; + unsupported?: boolean; + platform?: string; + }>; /** Recording preferences (mic, system audio) */ getRecordingPreferences: () => Promise<{ success: boolean; diff --git a/electron/ipc/register/project.ts b/electron/ipc/register/project.ts index a65fd907..93e1d6df 100644 --- a/electron/ipc/register/project.ts +++ b/electron/ipc/register/project.ts @@ -533,7 +533,7 @@ export function registerProjectHandlers() { return { success: false, error: String(error), message: 'Failed to open projects folder.' } } }) - ipcMain.handle('set-current-video-path', async (_, path: string, options?: { preserveProjectPath?: boolean; hideOverlayCursorByDefault?: boolean }) => { + ipcMain.handle('set-current-video-path', async (_, path: string, options?: { preserveProjectPath?: boolean; hideOverlayCursorByDefault?: boolean; nativeCaptureUnavailable?: boolean }) => { setCurrentVideoPath(normalizeVideoSourcePath(path) ?? path) approveUserPath(currentVideoPath) const resolvedSession = await resolveRecordingSession(currentVideoPath) @@ -548,6 +548,9 @@ export function registerProjectHandlers() { hideOverlayCursorByDefault: normalizeBoolean(options?.hideOverlayCursorByDefault) || normalizeBoolean(resolvedSession.hideOverlayCursorByDefault), + nativeCaptureUnavailable: + normalizeBoolean(options?.nativeCaptureUnavailable) || + normalizeBoolean(resolvedSession.nativeCaptureUnavailable), } setCurrentRecordingSession(nextSession) @@ -573,7 +576,7 @@ export function registerProjectHandlers() { return { success: true, webcamPath: nextSession.webcamPath ?? null } }) - ipcMain.handle('set-current-recording-session', async (_, session: { videoPath: string; webcamPath?: string | null; timeOffsetMs?: number; hideOverlayCursorByDefault?: boolean }, options?: { preserveProjectPath?: boolean }) => { + ipcMain.handle('set-current-recording-session', async (_, session: { videoPath: string; webcamPath?: string | null; timeOffsetMs?: number; hideOverlayCursorByDefault?: boolean; nativeCaptureUnavailable?: boolean }, options?: { preserveProjectPath?: boolean }) => { const normalizedVideoPath = normalizeVideoSourcePath(session.videoPath) ?? session.videoPath setCurrentVideoPath(normalizedVideoPath) setCurrentRecordingSession({ @@ -581,6 +584,7 @@ export function registerProjectHandlers() { webcamPath: normalizeVideoSourcePath(session.webcamPath ?? null), timeOffsetMs: normalizeRecordingTimeOffsetMs(session.timeOffsetMs), hideOverlayCursorByDefault: normalizeBoolean(session.hideOverlayCursorByDefault), + nativeCaptureUnavailable: normalizeBoolean(session.nativeCaptureUnavailable), }); await rememberApprovedLocalReadPath(currentRecordingSession!.videoPath) await rememberApprovedLocalReadPath(currentRecordingSession!.webcamPath) diff --git a/electron/ipc/register/settings.ts b/electron/ipc/register/settings.ts index e84f6317..5b4498a8 100644 --- a/electron/ipc/register/settings.ts +++ b/electron/ipc/register/settings.ts @@ -114,7 +114,7 @@ export function registerSettingsHandlers() { // --------------------------------------------------------------------------- ipcMain.handle("hide-cursor", () => { if (process.platform !== "win32") { - return { success: true }; + return { success: false, unsupported: true, platform: process.platform }; } return { success: hideCursor() }; diff --git a/electron/ipc/types.ts b/electron/ipc/types.ts index 58f5425b..9680da73 100644 --- a/electron/ipc/types.ts +++ b/electron/ipc/types.ts @@ -48,6 +48,7 @@ export type RecordingSessionData = { webcamPath?: string | null; timeOffsetMs?: number; hideOverlayCursorByDefault?: boolean; + nativeCaptureUnavailable?: boolean; }; export type PauseSegment = { diff --git a/electron/preload.ts b/electron/preload.ts index 932db07b..2cfb155b 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -687,6 +687,7 @@ contextBridge.exposeInMainWorld("electronAPI", { options?: { preserveProjectPath?: boolean; hideOverlayCursorByDefault?: boolean; + nativeCaptureUnavailable?: boolean; }, ) => { return ipcRenderer.invoke("set-current-video-path", path, options); @@ -697,6 +698,7 @@ contextBridge.exposeInMainWorld("electronAPI", { webcamPath?: string | null; timeOffsetMs?: number; hideOverlayCursorByDefault?: boolean; + nativeCaptureUnavailable?: boolean; }, options?: { preserveProjectPath?: boolean }, ) => { diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx index cff898a5..4ddaafd7 100644 --- a/src/components/video-editor/SettingsPanel.tsx +++ b/src/components/video-editor/SettingsPanel.tsx @@ -3295,6 +3295,7 @@ export function SettingsPanel({ @@ -3303,11 +3304,20 @@ export function SettingsPanel({ + {nativeCaptureUnavailableSession ? ( +

+ {tSettings( + "effects.cursorOverlayUnavailable", + "Cursor overlay is unavailable for this recording because the captured video already contains the system cursor.", + )} +
+ ) : null}
{ - setSessionShowCursorOverride(null); - setShowCursor(nextShowCursor); - }, []); + const handleShowCursorChange = useCallback( + (nextShowCursor: boolean) => { + if (nextShowCursor && sessionNativeCaptureUnavailable) { + setNativeCaptureUnavailableModalOpen(true); + return; + } + + setSessionShowCursorOverride(null); + setShowCursor(nextShowCursor); + }, + [sessionNativeCaptureUnavailable], + ); const remountPreview = useCallback(() => { setIsPreviewReady(false); diff --git a/src/hooks/useScreenRecorder.test.ts b/src/hooks/useScreenRecorder.test.ts index 85811467..509b049b 100644 --- a/src/hooks/useScreenRecorder.test.ts +++ b/src/hooks/useScreenRecorder.test.ts @@ -3,8 +3,10 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { createBrowserRecordingOptions, createProcessedMicrophoneConstraints, + getScreenCaptureCursorSetting, normalizeBrowserMicrophoneProfile, resolveBrowserCaptureCursorPolicy, + resolveLinuxPortalCursorPresentation, shouldUseNativeWindowsCaptureForSource, } from "./useScreenRecorder"; @@ -145,6 +147,7 @@ describe("resolveBrowserCaptureCursorPolicy", () => { streamCursor: "never", hideOsCursorBeforeRecording: true, hideEditorOverlayCursorByDefault: true, + nativeCaptureUnavailable: false, }); }); @@ -155,8 +158,64 @@ describe("resolveBrowserCaptureCursorPolicy", () => { streamCursor: "always", hideOsCursorBeforeRecording: false, hideEditorOverlayCursorByDefault: true, + nativeCaptureUnavailable: true, }); }); + + it("does not fake OS cursor hiding on Linux portal capture", () => { + expect(resolveBrowserCaptureCursorPolicy({ platform: "linux" })).toEqual({ + streamCursor: "never", + hideOsCursorBeforeRecording: false, + hideEditorOverlayCursorByDefault: true, + nativeCaptureUnavailable: true, + }); + }); +}); + +describe("resolveLinuxPortalCursorPresentation", () => { + it("enables the Recordly overlay only when the portal confirms cursor-hidden capture", () => { + expect( + resolveLinuxPortalCursorPresentation({ + requestedCursor: "never", + actualCursor: "never", + }), + ).toEqual({ + hideEditorOverlayCursorByDefault: false, + nativeCaptureUnavailable: false, + }); + }); + + it("keeps the overlay disabled when the portal embeds or omits cursor settings", () => { + expect( + resolveLinuxPortalCursorPresentation({ + requestedCursor: "never", + actualCursor: "always", + }), + ).toEqual({ + hideEditorOverlayCursorByDefault: true, + nativeCaptureUnavailable: true, + }); + expect( + resolveLinuxPortalCursorPresentation({ + requestedCursor: "never", + actualCursor: null, + }), + ).toEqual({ + hideEditorOverlayCursorByDefault: true, + nativeCaptureUnavailable: true, + }); + }); +}); + +describe("getScreenCaptureCursorSetting", () => { + it("normalizes only supported screen-capture cursor settings", () => { + expect(getScreenCaptureCursorSetting({ cursor: "motion" } as MediaTrackSettings)).toBe( + "motion", + ); + expect( + getScreenCaptureCursorSetting({ cursor: "hidden" } as MediaTrackSettings), + ).toBeNull(); + }); }); describe("shouldUseNativeWindowsCaptureForSource", () => { diff --git a/src/hooks/useScreenRecorder.ts b/src/hooks/useScreenRecorder.ts index 30ed7c62..b6f34be9 100644 --- a/src/hooks/useScreenRecorder.ts +++ b/src/hooks/useScreenRecorder.ts @@ -46,10 +46,12 @@ export type BrowserMicrophoneProfile = | "no-noise-suppression" | "raw"; type BrowserCaptureCursorMode = "always" | "never"; +type BrowserCaptureCursorSetting = BrowserCaptureCursorMode | "motion"; export type BrowserCaptureCursorPolicy = { streamCursor: BrowserCaptureCursorMode; hideOsCursorBeforeRecording: boolean; hideEditorOverlayCursorByDefault: boolean; + nativeCaptureUnavailable: boolean; }; const DEFAULT_BROWSER_MICROPHONE_PROFILE: BrowserMicrophoneProfile = "processed"; const BROWSER_MICROPHONE_PROFILES = new Set([ @@ -190,8 +192,10 @@ export function normalizeBrowserMicrophoneProfile(value?: string | null): Browse export function resolveBrowserCaptureCursorPolicy({ nativeWindowsCaptureStartFailed = false, + platform, }: { nativeWindowsCaptureStartFailed?: boolean; + platform?: string; } = {}): BrowserCaptureCursorPolicy { if (nativeWindowsCaptureStartFailed) { // If WGC already failed, avoid the telemetry overlay path that can lag on @@ -200,6 +204,19 @@ export function resolveBrowserCaptureCursorPolicy({ streamCursor: "always", hideOsCursorBeforeRecording: false, hideEditorOverlayCursorByDefault: true, + nativeCaptureUnavailable: true, + }; + } + + if (platform === "linux") { + // Linux screen capture runs through xdg-desktop-portal/PipeWire. Ask the + // portal to omit the cursor, but do not pretend we can globally hide the + // OS cursor from Electron when the portal/compositor ignores that request. + return { + streamCursor: "never", + hideOsCursorBeforeRecording: false, + hideEditorOverlayCursorByDefault: true, + nativeCaptureUnavailable: true, }; } @@ -207,6 +224,37 @@ export function resolveBrowserCaptureCursorPolicy({ streamCursor: "never", hideOsCursorBeforeRecording: true, hideEditorOverlayCursorByDefault: true, + nativeCaptureUnavailable: false, + }; +} + +export function getScreenCaptureCursorSetting( + settings: MediaTrackSettings | null | undefined, +): BrowserCaptureCursorSetting | null { + const cursor = (settings as { cursor?: unknown } | null | undefined)?.cursor; + return cursor === "always" || cursor === "never" || cursor === "motion" ? cursor : null; +} + +export function resolveLinuxPortalCursorPresentation({ + actualCursor, + requestedCursor, +}: { + actualCursor: BrowserCaptureCursorSetting | null; + requestedCursor: BrowserCaptureCursorMode; +}): Pick< + BrowserCaptureCursorPolicy, + "hideEditorOverlayCursorByDefault" | "nativeCaptureUnavailable" +> { + if (requestedCursor === "never" && actualCursor === "never") { + return { + hideEditorOverlayCursorByDefault: false, + nativeCaptureUnavailable: false, + }; + } + + return { + hideEditorOverlayCursorByDefault: true, + nativeCaptureUnavailable: true, }; } @@ -372,6 +420,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { ); const requestedBrowserMicrophoneProfile = useRef(null); const hideEditorOverlayCursorByDefault = useRef(false); + const nativeCaptureUnavailableForCursorOverlay = useRef(false); const notifyRecordingFinalizationFailure = useCallback(async (message: string) => { setFinalizing(false); @@ -680,6 +729,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { const start = performance.now(); console.log("[PERF:RENDERER] Finalize Session & Switch to Editor: STARTED"); const shouldHideOverlayCursor = hideEditorOverlayCursorByDefault.current; + const nativeCaptureUnavailable = nativeCaptureUnavailableForCursorOverlay.current; try { if (webcamPath) { await window.electronAPI.setCurrentRecordingSession({ @@ -687,10 +737,12 @@ export function useScreenRecorder(): UseScreenRecorderReturn { webcamPath, timeOffsetMs: webcamTimeOffsetMs.current, hideOverlayCursorByDefault: shouldHideOverlayCursor, + nativeCaptureUnavailable, }); } else { await window.electronAPI.setCurrentVideoPath(videoPath, { hideOverlayCursorByDefault: shouldHideOverlayCursor, + nativeCaptureUnavailable, }); } } catch (error) { @@ -699,6 +751,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { try { await window.electronAPI.setCurrentVideoPath(videoPath, { hideOverlayCursorByDefault: shouldHideOverlayCursor, + nativeCaptureUnavailable, }); } catch (fallbackError) { console.error("Failed to persist fallback video path:", fallbackError); @@ -1166,6 +1219,8 @@ export function useScreenRecorder(): UseScreenRecorderReturn { webcamPath, timeOffsetMs: webcamTimeOffsetMs.current, hideOverlayCursorByDefault: hideEditorOverlayCursorByDefault.current, + nativeCaptureUnavailable: + nativeCaptureUnavailableForCursorOverlay.current, }); console.log( @@ -1364,6 +1419,7 @@ export function useScreenRecorder(): UseScreenRecorderReturn { try { const platform = await window.electronAPI.getPlatform(); hideEditorOverlayCursorByDefault.current = false; + nativeCaptureUnavailableForCursorOverlay.current = false; const existingSource = await window.electronAPI.getSelectedSource(); const selectedSource = existingSource ?? (platform === "linux" ? LINUX_PORTAL_SOURCE : null); @@ -1563,9 +1619,12 @@ export function useScreenRecorder(): UseScreenRecorderReturn { const browserCursorPolicy = resolveBrowserCaptureCursorPolicy({ nativeWindowsCaptureStartFailed, + platform, }); hideEditorOverlayCursorByDefault.current = browserCursorPolicy.hideEditorOverlayCursorByDefault; + nativeCaptureUnavailableForCursorOverlay.current = + browserCursorPolicy.nativeCaptureUnavailable; const wantsAudioCapture = microphoneEnabled || systemAudioEnabled; const browserCaptureSource = await resolveBrowserCaptureSource(selectedSource); @@ -1749,6 +1808,27 @@ export function useScreenRecorder(): UseScreenRecorderReturn { throw new Error("Media stream is not available."); } + if (useLinuxPortal) { + const actualCursor = getScreenCaptureCursorSetting(videoTrack.getSettings()); + const cursorPresentation = resolveLinuxPortalCursorPresentation({ + actualCursor, + requestedCursor: browserCursorPolicy.streamCursor, + }); + hideEditorOverlayCursorByDefault.current = + cursorPresentation.hideEditorOverlayCursorByDefault; + nativeCaptureUnavailableForCursorOverlay.current = + cursorPresentation.nativeCaptureUnavailable; + if (cursorPresentation.nativeCaptureUnavailable) { + console.warn( + "Linux portal did not confirm cursor-hidden capture; disabling Recordly cursor overlay for this recording.", + { + actualCursor, + requestedCursor: browserCursorPolicy.streamCursor, + }, + ); + } + } + try { await videoTrack.applyConstraints({ frameRate: { ideal: TARGET_FRAME_RATE, max: TARGET_FRAME_RATE }, @@ -1854,6 +1934,8 @@ export function useScreenRecorder(): UseScreenRecorderReturn { timeOffsetMs: webcamTimeOffsetMs.current, hideOverlayCursorByDefault: hideEditorOverlayCursorByDefault.current, + nativeCaptureUnavailable: + nativeCaptureUnavailableForCursorOverlay.current, }); } } finally { From 107139b734cf34230afe6aa748284dcaa5f25af1 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Thu, 28 May 2026 16:51:47 +0700 Subject: [PATCH 7/8] fix(linux): clear cursor overlay availability state --- electron/ipc/register/project.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/electron/ipc/register/project.ts b/electron/ipc/register/project.ts index 93e1d6df..7af983b0 100644 --- a/electron/ipc/register/project.ts +++ b/electron/ipc/register/project.ts @@ -549,8 +549,9 @@ export function registerProjectHandlers() { normalizeBoolean(options?.hideOverlayCursorByDefault) || normalizeBoolean(resolvedSession.hideOverlayCursorByDefault), nativeCaptureUnavailable: - normalizeBoolean(options?.nativeCaptureUnavailable) || - normalizeBoolean(resolvedSession.nativeCaptureUnavailable), + normalizeBoolean( + options?.nativeCaptureUnavailable ?? resolvedSession.nativeCaptureUnavailable, + ), } setCurrentRecordingSession(nextSession) From b00b20f373b9a9dfaba9dd4a371a0ed3320bba30 Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Thu, 28 May 2026 17:16:04 +0700 Subject: [PATCH 8/8] chore(release): prepare v1.3.2 --- package-lock.json | 4 ++-- package.json | 2 +- src/i18n/locales/fr/editor.json | 5 +++++ src/i18n/locales/ko/editor.json | 5 +++++ src/i18n/locales/nl/editor.json | 5 +++++ src/i18n/locales/pt-BR/editor.json | 5 +++++ src/i18n/locales/zh-CN/editor.json | 5 +++++ src/i18n/locales/zh-TW/editor.json | 7 ++++++- 8 files changed, 34 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5841b3d8..586fce89 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "recordly", - "version": "1.3.1", + "version": "1.3.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "recordly", - "version": "1.3.1", + "version": "1.3.2", "hasInstallScript": true, "dependencies": { "@phosphor-icons/react": "^2.1.10", diff --git a/package.json b/package.json index 3bbf0de6..2e832388 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "url": "https://github.com/webadderallorg/Recordly/issues" }, "private": true, - "version": "1.3.1", + "version": "1.3.2", "type": "module", "scripts": { "dev": "vite --config vite.config.ts", diff --git a/src/i18n/locales/fr/editor.json b/src/i18n/locales/fr/editor.json index d3494ed1..cb4b4d13 100644 --- a/src/i18n/locales/fr/editor.json +++ b/src/i18n/locales/fr/editor.json @@ -113,6 +113,11 @@ "project": { "untitled": "Sans titre" }, + "nativeCaptureUnavailable": { + "title": "Rien n'est cassé, mais nous ne pourrons pas afficher une superposition animée du curseur.", + "description": "Votre appareil ne prend pas en charge la capture native. Cela peut arriver pour plusieurs raisons que nous n'avons pas encore identifiées. Recordly continuera de fonctionner, mais le lissage du curseur sera impossible.", + "confirm": "D'accord" + }, "exportStatus": { "exporting": "Exportation", "renderingFile": "Rendu de votre fichier.", diff --git a/src/i18n/locales/ko/editor.json b/src/i18n/locales/ko/editor.json index 56eb6bc5..49678dee 100644 --- a/src/i18n/locales/ko/editor.json +++ b/src/i18n/locales/ko/editor.json @@ -114,6 +114,11 @@ "project": { "untitled": "제목 없음" }, + "nativeCaptureUnavailable": { + "title": "문제가 생긴 것은 아니지만, 애니메이션 커서 오버레이를 렌더링할 수 없습니다.", + "description": "이 장치는 네이티브 캡처를 지원하지 않습니다. 아직 확인하지 못한 여러 이유가 있을 수 있습니다. Recordly는 계속 작동하지만 커서 스무딩은 사용할 수 없습니다.", + "confirm": "확인" + }, "exportStatus": { "exporting": "내보내는 중", "renderingFile": "파일을 렌더링하고 있습니다.", diff --git a/src/i18n/locales/nl/editor.json b/src/i18n/locales/nl/editor.json index b174ca98..d58b9e52 100644 --- a/src/i18n/locales/nl/editor.json +++ b/src/i18n/locales/nl/editor.json @@ -114,6 +114,11 @@ "project": { "untitled": "Naamloos" }, + "nativeCaptureUnavailable": { + "title": "Er is niets kapot, maar we kunnen geen geanimeerde cursor-overlay renderen.", + "description": "Je apparaat ondersteunt geen native capture. Dit kan verschillende oorzaken hebben die we nog niet hebben achterhaald. Recordly blijft werken, maar cursor smoothing is dan niet mogelijk.", + "confirm": "Oké" + }, "exportStatus": { "exporting": "Exporteren", "renderingFile": "Je bestand wordt gerenderd.", diff --git a/src/i18n/locales/pt-BR/editor.json b/src/i18n/locales/pt-BR/editor.json index 175bf674..702939fd 100644 --- a/src/i18n/locales/pt-BR/editor.json +++ b/src/i18n/locales/pt-BR/editor.json @@ -113,6 +113,11 @@ "project": { "untitled": "Sem título" }, + "nativeCaptureUnavailable": { + "title": "Nada está quebrado, mas não poderemos renderizar uma sobreposição animada do cursor.", + "description": "Seu dispositivo não oferece suporte à captura nativa. Isso pode acontecer por vários motivos que ainda não identificamos. O Recordly continuará funcionando, mas a suavização do cursor ficará indisponível.", + "confirm": "Entendi" + }, "exportStatus": { "exporting": "Exportando", "renderingFile": "Renderizando seu arquivo.", diff --git a/src/i18n/locales/zh-CN/editor.json b/src/i18n/locales/zh-CN/editor.json index 4a0c4a5d..1bf3a608 100644 --- a/src/i18n/locales/zh-CN/editor.json +++ b/src/i18n/locales/zh-CN/editor.json @@ -113,6 +113,11 @@ "project": { "untitled": "未命名" }, + "nativeCaptureUnavailable": { + "title": "没有出错,但我们无法渲染动画光标叠加层。", + "description": "你的设备不支持原生捕获。这可能是由我们尚未确定的多种原因造成的。Recordly 仍可继续运行,但无法进行光标平滑处理。", + "confirm": "好的" + }, "exportStatus": { "exporting": "正在导出", "renderingFile": "正在渲染你的文件。", diff --git a/src/i18n/locales/zh-TW/editor.json b/src/i18n/locales/zh-TW/editor.json index e37768b3..6f2b0f82 100644 --- a/src/i18n/locales/zh-TW/editor.json +++ b/src/i18n/locales/zh-TW/editor.json @@ -113,6 +113,11 @@ "project": { "untitled": "未命名" }, + "nativeCaptureUnavailable": { + "title": "沒有出錯,但我們無法轉譯動畫游標覆蓋層。", + "description": "你的裝置不支援原生擷取。這可能是由我們尚未釐清的多種原因造成的。Recordly 仍可繼續運作,但無法進行游標平滑處理。", + "confirm": "好的" + }, "exportStatus": { "exporting": "正在匯出", "renderingFile": "正在渲染你的檔案。", @@ -134,4 +139,4 @@ "collapse": "摺疊時間軸" }, "openRecordingsFolder": "打開錄製資料夾" -} \ No newline at end of file +}