From e5e869e654fc4dd7d60f099078224ce997d7dd0d Mon Sep 17 00:00:00 2001 From: webadderall <131426131+webadderall@users.noreply.github.com> Date: Sat, 14 Mar 2026 20:51:25 +1100 Subject: [PATCH] feat(export): add native aspect ratio option for background-free exports --- src/components/video-editor/VideoEditor.tsx | 16 +++++++++++++--- src/components/video-editor/VideoPlayback.tsx | 14 +++++++++++++- src/utils/aspectRatioUtils.ts | 18 +++++++++++++----- 3 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/components/video-editor/VideoEditor.tsx b/src/components/video-editor/VideoEditor.tsx index a41298e5..fd7b3207 100644 --- a/src/components/video-editor/VideoEditor.tsx +++ b/src/components/video-editor/VideoEditor.tsx @@ -1156,9 +1156,10 @@ export default function VideoEditor() { videoPlaybackRef.current?.pause(); } - const aspectRatioValue = getAspectRatioValue(aspectRatio); const sourceWidth = video.videoWidth || 1920; const sourceHeight = video.videoHeight || 1080; + const sourceAspectRatio = sourceHeight > 0 ? sourceWidth / sourceHeight : 16 / 9; + const aspectRatioValue = getAspectRatioValue(aspectRatio, sourceAspectRatio); // Get preview CONTAINER dimensions for scaling const playbackRef = videoPlaybackRef.current; @@ -1241,7 +1242,10 @@ export default function VideoEditor() { exportWidth = sourceWidth; exportHeight = sourceHeight; - if (aspectRatioValue === 1) { + if (aspectRatio === 'native') { + exportWidth = Math.floor(sourceWidth / 2) * 2; + exportHeight = Math.floor(sourceHeight / 2) * 2; + } else if (aspectRatioValue === 1) { // Square (1:1): use smaller dimension to avoid codec limits const baseDimension = Math.floor(Math.min(sourceWidth, sourceHeight) / 2) * 2; exportWidth = baseDimension; @@ -1544,7 +1548,13 @@ export default function VideoEditor() {
{/* Video preview */}
-
+
{ + const previewVideo = videoPlaybackRef.current?.video; + if (previewVideo && previewVideo.videoHeight > 0) { + return previewVideo.videoWidth / previewVideo.videoHeight; + } + return 16 / 9; + })()), maxWidth: '100%', margin: '0 auto', boxSizing: 'border-box' }}> (({ ? { backgroundImage: `url(${resolvedWallpaper || ''})` } : { background: resolvedWallpaper || '' }; + const nativeAspectRatio = (() => { + const locked = lockedVideoDimensionsRef.current; + if (locked && locked.height > 0) { + return locked.width / locked.height; + } + const video = videoRef.current; + if (video && video.videoHeight > 0) { + return video.videoWidth / video.videoHeight; + } + return 16 / 9; + })(); + return ( -
+
{/* Background layer - always render as DOM element with blur */}
0 ? nativeAspectRatio : 16 / 9; case '16:9': return 16 / 9; case '9:16': return 9 / 16; case '1:1': return 1; @@ -26,9 +27,10 @@ export function getAspectRatioValue(aspectRatio: AspectRatio): number { export function getAspectRatioDimensions( aspectRatio: AspectRatio, - baseWidth: number + baseWidth: number, + nativeAspectRatio?: number, ): { width: number; height: number } { - const ratio = getAspectRatioValue(aspectRatio); + const ratio = getAspectRatioValue(aspectRatio, nativeAspectRatio); return { width: baseWidth, height: baseWidth / ratio, @@ -36,11 +38,17 @@ export function getAspectRatioDimensions( } export function getAspectRatioLabel(aspectRatio: AspectRatio): string { + if (aspectRatio === 'native') { + return 'Native'; + } return aspectRatio; } -export function formatAspectRatioForCSS(aspectRatio: AspectRatio): string { +export function formatAspectRatioForCSS(aspectRatio: AspectRatio, nativeAspectRatio = 16 / 9): string { + if (aspectRatio === 'native') { + return `${nativeAspectRatio > 0 ? nativeAspectRatio : 16 / 9}`; + } return aspectRatio.replace(':', '/'); }