diff --git a/src/components/video-editor/SettingsPanel.tsx b/src/components/video-editor/SettingsPanel.tsx index 0e131cd7..71ef0530 100644 --- a/src/components/video-editor/SettingsPanel.tsx +++ b/src/components/video-editor/SettingsPanel.tsx @@ -2734,7 +2734,7 @@ export function SettingsPanel({ .maxDirectionalBlurPx } min={0} - max={32} + max={64} step={0.1} onChange={(value) => onZoomMotionBlurTuningChange?.({ @@ -2778,7 +2778,7 @@ export function SettingsPanel({ .maxRadialBlurStrength } min={0} - max={0.5} + max={1} step={0.005} onChange={(value) => onZoomMotionBlurTuningChange?.({ diff --git a/src/components/video-editor/VideoEditor.tsx b/src/components/video-editor/VideoEditor.tsx index fd3a3141..7f088dcc 100644 --- a/src/components/video-editor/VideoEditor.tsx +++ b/src/components/video-editor/VideoEditor.tsx @@ -4361,7 +4361,8 @@ export default function VideoEditor() { ? (smokeExportConfig.fps ?? settings.mp4FrameRate ?? mp4FrameRate) : (settings.mp4FrameRate ?? mp4FrameRate); const pipelineModel = smokeExportConfig.enabled - ? (smokeExportConfig.pipelineModel ?? "modern") + ? (smokeExportConfig.pipelineModel ?? + (smokeExportConfig.useNativeExport ? "modern" : "legacy")) : (settings.pipelineModel ?? exportPipelineModel); const useExperimentalNativeExport = pipelineModel === "modern" && diff --git a/src/components/video-editor/editorPreferences.test.ts b/src/components/video-editor/editorPreferences.test.ts index ca1378dd..ef40d7b8 100644 --- a/src/components/video-editor/editorPreferences.test.ts +++ b/src/components/video-editor/editorPreferences.test.ts @@ -75,8 +75,17 @@ describe("editorPreferences", () => { expect(DEFAULT_EDITOR_PREFERENCES.cursorSway).toBe(0.25); }); - it("defaults MP4 exports to the Lightning pipeline", () => { - expect(DEFAULT_EDITOR_PREFERENCES.exportPipelineModel).toBe("modern"); + it("bakes in the stronger split motion blur tuning defaults", () => { + expect(DEFAULT_EDITOR_PREFERENCES.zoomMotionBlurTuning).toMatchObject({ + panVelocityThreshold: 0, + zoomVelocityThreshold: 0, + maxDirectionalBlurPx: 48.2, + maxRadialBlurStrength: 0.755, + }); + }); + + it("defaults MP4 exports to the legacy pipeline", () => { + expect(DEFAULT_EDITOR_PREFERENCES.exportPipelineModel).toBe("legacy"); }); it("loads stored editor control preferences", () => { diff --git a/src/components/video-editor/projectPersistence.ts b/src/components/video-editor/projectPersistence.ts index 9adb3608..f6550040 100644 --- a/src/components/video-editor/projectPersistence.ts +++ b/src/components/video-editor/projectPersistence.ts @@ -177,7 +177,7 @@ export function normalizeExportPipelineModel(value: unknown): ExportPipelineMode return value; } - return "modern"; + return "legacy"; } export function normalizeExportMp4FrameRate(value: unknown): ExportMp4FrameRate { @@ -360,10 +360,10 @@ export function normalizeProjectEditor(editor: Partial): Pro ? clamp(rawZoomMotionBlurTuning.zoomVelocityThreshold, 0, 0.4) : DEFAULT_ZOOM_MOTION_BLUR_TUNING.zoomVelocityThreshold, maxDirectionalBlurPx: isFiniteNumber(rawZoomMotionBlurTuning.maxDirectionalBlurPx) - ? clamp(rawZoomMotionBlurTuning.maxDirectionalBlurPx, 0, 32) + ? clamp(rawZoomMotionBlurTuning.maxDirectionalBlurPx, 0, 64) : DEFAULT_ZOOM_MOTION_BLUR_TUNING.maxDirectionalBlurPx, maxRadialBlurStrength: isFiniteNumber(rawZoomMotionBlurTuning.maxRadialBlurStrength) - ? clamp(rawZoomMotionBlurTuning.maxRadialBlurStrength, 0, 0.5) + ? clamp(rawZoomMotionBlurTuning.maxRadialBlurStrength, 0, 1) : DEFAULT_ZOOM_MOTION_BLUR_TUNING.maxRadialBlurStrength, panResponsePerSecond: isFiniteNumber(rawZoomMotionBlurTuning.panResponsePerSecond) ? clamp(rawZoomMotionBlurTuning.panResponsePerSecond, 1, 30) diff --git a/src/components/video-editor/types.ts b/src/components/video-editor/types.ts index e6a7c6f0..4110cb06 100644 --- a/src/components/video-editor/types.ts +++ b/src/components/video-editor/types.ts @@ -116,9 +116,9 @@ export interface ZoomMotionBlurTuning { export const DEFAULT_ZOOM_MOTION_BLUR_TUNING: ZoomMotionBlurTuning = { panVelocityThreshold: 0, - zoomVelocityThreshold: 0.025, - maxDirectionalBlurPx: 11, - maxRadialBlurStrength: 0.175, + zoomVelocityThreshold: 0, + maxDirectionalBlurPx: 48.2, + maxRadialBlurStrength: 0.755, panResponsePerSecond: 11, zoomResponsePerSecond: 9, zoomSafeZoneRadiusPx: 6, diff --git a/src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts b/src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts index 2d5d3c41..7008a9c1 100644 --- a/src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts +++ b/src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts @@ -308,6 +308,29 @@ describe("ModernVideoExporter native static-layout eligibility", () => { ).toBe("unsupported-background-video"); }); + it("skips native static-layout when motion blur is enabled", () => { + const exporter = createExporter({ + zoomMotionBlur: 0.8, + zoomTemporalMotionBlur: 0.6, + cursorMotionBlur: 0.4, + }); + + expect( + exporter.getNativeStaticLayoutSkipReasons( + { + audioMode: "edited-track", + strategy: "offline-render-fallback", + }, + videoInfo, + 59, + ), + ).toEqual([ + "unsupported-zoom-motion-blur", + "unsupported-zoom-temporal-motion-blur", + "unsupported-cursor-motion-blur", + ]); + }); + it("collects every native static-layout blocker for beta diagnostics", () => { const exporter = createExporter({ width: 1921, diff --git a/src/lib/exporter/modernVideoExporter.ts b/src/lib/exporter/modernVideoExporter.ts index 55f47923..c2457e59 100644 --- a/src/lib/exporter/modernVideoExporter.ts +++ b/src/lib/exporter/modernVideoExporter.ts @@ -1409,6 +1409,18 @@ export class ModernVideoExporter { reasons.push("unsupported-background-video"); } + if ((this.config.zoomMotionBlur ?? 0) > 0) { + reasons.push("unsupported-zoom-motion-blur"); + } + + if ((this.config.zoomTemporalMotionBlur ?? 0) > 0) { + reasons.push("unsupported-zoom-temporal-motion-blur"); + } + + if ((this.config.cursorMotionBlur ?? 0) > 0) { + reasons.push("unsupported-cursor-motion-blur"); + } + const hasZoomRegions = (this.config.zoomRegions ?? []).length > 0; const needsTimelineMap = this.shouldUseNativeStaticLayoutTimelineMap( videoInfo,