From 24b4b4254aa7eb42e57e52c8ea090e0e13718410 Mon Sep 17 00:00:00 2001 From: Shreyas Date: Sun, 5 Apr 2026 17:51:32 +0100 Subject: [PATCH] fix: normalize dual frame preset for portrait projects --- .../video-editor/projectPersistence.test.ts | 9 ++++++ .../video-editor/projectPersistence.ts | 29 +++++++++++++------ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/components/video-editor/projectPersistence.test.ts b/src/components/video-editor/projectPersistence.test.ts index 9651fb4..fd2cb43 100644 --- a/src/components/video-editor/projectPersistence.test.ts +++ b/src/components/video-editor/projectPersistence.test.ts @@ -73,6 +73,15 @@ describe("projectPersistence media compatibility", () => { "dual-frame", ); }); + + it("falls back from dual frame to picture in picture for portrait aspect ratios", () => { + expect( + normalizeProjectEditor({ + aspectRatio: "9:16", + webcamLayoutPreset: "dual-frame", + }).webcamLayoutPreset, + ).toBe("picture-in-picture"); + }); }); it("creates stable snapshots for identical project state", () => { diff --git a/src/components/video-editor/projectPersistence.ts b/src/components/video-editor/projectPersistence.ts index 00dd1b9..1d78f29 100644 --- a/src/components/video-editor/projectPersistence.ts +++ b/src/components/video-editor/projectPersistence.ts @@ -1,7 +1,7 @@ import type { ExportFormat, ExportQuality, GifFrameRate, GifSizePreset } from "@/lib/exporter"; import type { ProjectMedia } from "@/lib/recordingSession"; import { normalizeProjectMedia } from "@/lib/recordingSession"; -import { ASPECT_RATIOS, type AspectRatio } from "@/utils/aspectRatioUtils"; +import { ASPECT_RATIOS, type AspectRatio, isPortraitAspectRatio } from "@/utils/aspectRatioUtils"; import { type AnnotationRegion, type CropRegion, @@ -185,6 +185,23 @@ export function resolveProjectMedia( export function normalizeProjectEditor(editor: Partial): ProjectEditorState { const validAspectRatios = new Set(ASPECT_RATIOS); + const normalizedAspectRatio: AspectRatio = validAspectRatios.has( + editor.aspectRatio as AspectRatio, + ) + ? (editor.aspectRatio as AspectRatio) + : "16:9"; + const normalizedWebcamLayoutPreset: WebcamLayoutPreset = + editor.webcamLayoutPreset === "picture-in-picture" + ? editor.webcamLayoutPreset + : editor.webcamLayoutPreset === "vertical-stack" + ? isPortraitAspectRatio(normalizedAspectRatio) + ? editor.webcamLayoutPreset + : DEFAULT_WEBCAM_LAYOUT_PRESET + : editor.webcamLayoutPreset === "dual-frame" + ? isPortraitAspectRatio(normalizedAspectRatio) + ? DEFAULT_WEBCAM_LAYOUT_PRESET + : editor.webcamLayoutPreset + : DEFAULT_WEBCAM_LAYOUT_PRESET; const normalizedZoomRegions: ZoomRegion[] = Array.isArray(editor.zoomRegions) ? editor.zoomRegions @@ -396,14 +413,8 @@ export function normalizeProjectEditor(editor: Partial): Pro trimRegions: normalizedTrimRegions, speedRegions: normalizedSpeedRegions, annotationRegions: normalizedAnnotationRegions, - aspectRatio: - editor.aspectRatio && validAspectRatios.has(editor.aspectRatio) ? editor.aspectRatio : "16:9", - webcamLayoutPreset: - editor.webcamLayoutPreset === "vertical-stack" || - editor.webcamLayoutPreset === "dual-frame" || - editor.webcamLayoutPreset === "picture-in-picture" - ? editor.webcamLayoutPreset - : DEFAULT_WEBCAM_LAYOUT_PRESET, + aspectRatio: normalizedAspectRatio, + webcamLayoutPreset: normalizedWebcamLayoutPreset, webcamMaskShape: editor.webcamMaskShape === "rectangle" || editor.webcamMaskShape === "circle" ||