From 32708ce12273df0f34eb4e96c76c7ba1c0cdd8ea Mon Sep 17 00:00:00 2001 From: wiiiii123 Date: Wed, 6 May 2026 07:04:01 +0700 Subject: [PATCH] fix(export): allow native cursor overlay routing --- electron/ipc/export/native-video.test.ts | 28 ++++++++++ ...rnVideoExporter.nativeStaticLayout.test.ts | 52 +++++++++++++++++++ src/lib/exporter/modernVideoExporter.ts | 14 +++-- 3 files changed, 86 insertions(+), 8 deletions(-) diff --git a/electron/ipc/export/native-video.test.ts b/electron/ipc/export/native-video.test.ts index b0f8f1db..250622b6 100644 --- a/electron/ipc/export/native-video.test.ts +++ b/electron/ipc/export/native-video.test.ts @@ -440,6 +440,34 @@ describe("buildExperimentalNvidiaCudaStaticLayoutArgs", () => { ]), ); }); + + it("passes cursor telemetry and atlas assets to the CUDA wrapper", () => { + const args = buildExperimentalNvidiaCudaStaticLayoutArgs( + createNvidiaCudaSkipOptions({ + cursorTelemetryPath: "cursor-telemetry.json", + cursorSize: 96, + cursorAtlasPath: "cursor-atlas.png", + cursorAtlasMetadataPath: "cursor-atlas.tsv", + }), + "output.mp4", + "work", + ); + + expect(args).toEqual( + expect.arrayContaining([ + "--cursor-json", + "cursor-telemetry.json", + "--cursor-height", + "96", + "--cursor-style", + "external", + "--cursor-atlas-png", + "cursor-atlas.png", + "--cursor-atlas-metadata", + "cursor-atlas.tsv", + ]), + ); + }); }); describe("buildNativeStaticLayoutTimelineSegments", () => { diff --git a/src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts b/src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts index 4405ee31..0d906b91 100644 --- a/src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts +++ b/src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts @@ -130,6 +130,58 @@ describe("ModernVideoExporter native static-layout eligibility", () => { ).toBeNull(); }); + it("allows cursor overlay native static-layout without the experimental native flag", () => { + const exporter = createExporter({ + experimentalNativeExport: false, + showCursor: true, + cursorTelemetry: [ + { timeMs: 0, cx: 0.25, cy: 0.35 }, + { timeMs: 1_000, cx: 0.5, cy: 0.55 }, + ], + }); + + expect( + exporter.getNativeStaticLayoutSkipReason( + { + audioMode: "copy-source", + audioSourcePath: "recording.mp4", + }, + videoInfo, + 60, + ), + ).toBeNull(); + }); + + it("reports frame overlays as the remaining native overlay blocker", () => { + const exporter = createExporter({ frame: "macbook" }); + + expect( + exporter.getNativeStaticLayoutSkipReason( + { + audioMode: "copy-source", + audioSourcePath: "recording.mp4", + }, + videoInfo, + 60, + ), + ).toBe("unsupported-frame-overlay"); + }); + + it("reports background blur as the remaining native overlay blocker", () => { + const exporter = createExporter({ backgroundBlur: 12 }); + + expect( + exporter.getNativeStaticLayoutSkipReason( + { + audioMode: "copy-source", + audioSourcePath: "recording.mp4", + }, + videoInfo, + 60, + ), + ).toBe("unsupported-background-blur"); + }); + it("rejects native static-layout when speed edits do not have a native timeline map", () => { const speedRegions: SpeedRegion[] = [ { id: "speed-1", startMs: 1_000, endMs: 4_000, speed: 1.5 }, diff --git a/src/lib/exporter/modernVideoExporter.ts b/src/lib/exporter/modernVideoExporter.ts index 3ad79d22..2e7fc53b 100644 --- a/src/lib/exporter/modernVideoExporter.ts +++ b/src/lib/exporter/modernVideoExporter.ts @@ -1207,14 +1207,12 @@ export class ModernVideoExporter { return "unsupported-webcam-source"; } - const hasCursorOverlay = - this.config.showCursor === true && (this.config.cursorTelemetry ?? []).length > 0; - if ( - this.config.frame || - this.config.backgroundBlur > 0 || - (hasCursorOverlay && this.config.experimentalNativeExport !== true) - ) { - return "dynamic-overlay-present"; + if (this.config.frame) { + return "unsupported-frame-overlay"; + } + + if (this.config.backgroundBlur > 0) { + return "unsupported-background-blur"; } return this.isDefaultCropRegion() ? null : "non-default-crop";