diff --git a/src/components/video-editor/VideoPlayback.tsx b/src/components/video-editor/VideoPlayback.tsx index 2ba69ca..69363c5 100644 --- a/src/components/video-editor/VideoPlayback.tsx +++ b/src/components/video-editor/VideoPlayback.tsx @@ -753,7 +753,6 @@ const VideoPlayback = forwardRef( blurFilter.resolution = app.renderer.resolution; blurFilter.blur = 0; const motionBlurFilter = new MotionBlurFilter([0, 0], 5, 0); - videoContainer.filters = [blurFilter, motionBlurFilter]; blurFilterRef.current = blurFilter; motionBlurFilterRef.current = motionBlurFilter; @@ -801,7 +800,7 @@ const VideoPlayback = forwardRef( videoContainer.mask = null; maskGraphicsRef.current = null; if (blurFilterRef.current) { - videoContainer.filters = []; + videoContainer.filters = null; blurFilterRef.current.destroy(); blurFilterRef.current = null; } @@ -858,6 +857,7 @@ const VideoPlayback = forwardRef( state.appliedScale = appliedTransform.scale; }; + let lastMotionBlurActive: boolean | null = null; const ticker = () => { const { region, strength, blendedScale, transition } = findDominantRegion( zoomRegionsRef.current, @@ -1015,6 +1015,23 @@ const VideoPlayback = forwardRef( motionIntensity, motionVector, ); + + const isMotionBlurActive = (motionBlurAmountRef.current || 0) > 0 && isPlayingRef.current; + + if (isMotionBlurActive !== lastMotionBlurActive && videoContainerRef.current) { + if (isMotionBlurActive) { + if (blurFilterRef.current && motionBlurFilterRef.current) { + videoContainerRef.current.filters = [ + blurFilterRef.current, + motionBlurFilterRef.current, + ]; + lastMotionBlurActive = true; + } + } else { + videoContainerRef.current.filters = null; + lastMotionBlurActive = false; + } + } }; app.ticker.add(ticker); diff --git a/src/hooks/useScreenRecorder.ts b/src/hooks/useScreenRecorder.ts index 913386c..6d71cc5 100644 --- a/src/hooks/useScreenRecorder.ts +++ b/src/hooks/useScreenRecorder.ts @@ -122,11 +122,15 @@ export function useScreenRecorder(): UseScreenRecorderReturn { }, []); const selectMimeType = () => { + // H.264 first: hardware-accelerated on all modern devices, gives sharp + // real-time output. AV1/VP9 are great for distribution but too + // CPU-intensive for live 60 fps capture — they produce blurry frames + // when the software encoder can't keep up. const preferred = [ - "video/webm;codecs=av1", "video/webm;codecs=h264", - "video/webm;codecs=vp9", "video/webm;codecs=vp8", + "video/webm;codecs=vp9", + "video/webm;codecs=av1", "video/webm", ]; diff --git a/tsconfig.node.json b/tsconfig.node.json index 1caabef..3be14b6 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -7,5 +7,10 @@ "allowSyntheticDefaultImports": true, "strict": true }, - "include": ["vite.config.ts"] + "include": [ + "vite.config.ts", + "electron-builder.json5", + "playwright.config.ts", + "vitest.config.ts" + ] } diff --git a/vite.config.ts b/vite.config.ts index 725f24e..55b5596 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -9,25 +9,15 @@ export default defineConfig({ react(), electron({ main: { - // Shortcut of `build.lib.entry`. entry: "electron/main.ts", vite: { build: {}, }, }, preload: { - // Shortcut of `build.rollupOptions.input`. - // Preload scripts may contain Web assets, so use the `build.rollupOptions.input` instead `build.lib.entry`. input: path.join(__dirname, "electron/preload.ts"), }, - // Ployfill the Electron and Node.js API for Renderer process. - // If you want use Node.js in Renderer process, the `nodeIntegration` needs to be enabled in the Main process. - // See https://github.com/electron-vite/vite-plugin-electron-renderer - renderer: - process.env.NODE_ENV === "test" - ? // https://github.com/electron-vite/vite-plugin-electron-renderer/issues/78#issuecomment-2053600808 - undefined - : {}, + renderer: process.env.NODE_ENV === "test" ? undefined : {}, }), ], resolve: {