Clean up preview edges and blur controls

This commit is contained in:
young
2026-08-25 19:05:46 +10:00
parent 20596b6a30
commit 7da7e22ebe
14 changed files with 34 additions and 66 deletions
+8 -51
View File
@@ -171,9 +171,7 @@ import {
SNAP_TO_EDGES_RATIO_AUTO,
} from "./videoPlayback/cursorFollowCamera";
import { clampFocusToStage as clampFocusToStageUtil } from "./videoPlayback/focusUtils";
import {
layoutVideoContent as layoutVideoContentUtil,
} from "./videoPlayback/layoutUtils";
import { layoutVideoContent as layoutVideoContentUtil } from "./videoPlayback/layoutUtils";
import { updateOverlayIndicator } from "./videoPlayback/overlayUtils";
import { createVideoEventHandlers } from "./videoPlayback/videoEventHandlers";
import { getWebcamMediaTargetTimeSeconds, shouldSeekWebcamMedia } from "./videoPlayback/webcamSync";
@@ -1909,53 +1907,6 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
});
}, [pixiReady, videoReady, layoutVideoContent, cropRegion]);
useEffect(() => {
const previewFrame = previewFrameRef.current;
if (!previewFrame) {
return;
}
let frameId: number | null = null;
const applyPreviewFrameSquircle = () => {
const width = previewFrame.offsetWidth;
const height = previewFrame.offsetHeight;
if (width <= 0 || height <= 0) {
return;
}
const squirclePath = getSquircleSvgPath({
x: 0,
y: 0,
width,
height,
radius: 12,
});
previewFrame.style.clipPath = `path('${squirclePath}')`;
previewFrame.style.setProperty("-webkit-clip-path", `path('${squirclePath}')`);
};
applyPreviewFrameSquircle();
if (typeof ResizeObserver === "undefined") {
return;
}
const observer = new ResizeObserver(() => {
if (frameId !== null) {
cancelAnimationFrame(frameId);
}
frameId = requestAnimationFrame(applyPreviewFrameSquircle);
});
observer.observe(previewFrame);
return () => {
if (frameId !== null) {
cancelAnimationFrame(frameId);
}
observer.disconnect();
};
}, []);
useEffect(() => {
if (!pixiReady || !videoReady) return;
const container = containerRef.current;
@@ -2955,6 +2906,9 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
: resolvedWallpaperKind === "video"
? {}
: { background: resolvedWallpaper || "" };
// Overscan blurred wallpaper layers so the browser never samples transparent
// pixels beyond the preview bounds, which otherwise looks like a vignette.
const backgroundBlurOverscan = backgroundBlur > 0 ? Math.ceil(backgroundBlur * 2) : 0;
const fallbackVideoClassName = pixiRendererError
? "absolute inset-0 h-full w-full object-cover"
: "pointer-events-none absolute left-0 top-0 h-px w-px opacity-0";
@@ -2985,7 +2939,8 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
style={{
width: "100%",
aspectRatio: formatAspectRatioForCSS(aspectRatio, nativeAspectRatio),
borderRadius: "12px",
borderRadius: 0,
clipPath: "none",
}}
>
{/* Background layer */}
@@ -3000,6 +2955,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
playsInline
style={{
filter: backgroundBlur > 0 ? `blur(${backgroundBlur}px)` : "none",
inset: -backgroundBlurOverscan,
}}
/>
) : (
@@ -3008,6 +2964,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
style={{
...backgroundStyle,
filter: backgroundBlur > 0 ? `blur(${backgroundBlur}px)` : "none",
inset: -backgroundBlurOverscan,
}}
/>
)}
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Turtle"
},
"backgroundBlur": "Hintergrundunschärfe",
"backgroundBlur": "Unschärfe",
"zoomMotionBlur": "Zoom-Bewegungsunschärfe",
"temporalZoomMotionBlur": "Zeitliche Zoom-Bewegungsunschärfe",
"temporalZoomMotionBlurDescription": "Steuert das Verschlussfenster und die Bildausschnitte, die vom neueren Zoom-Bewegungsunschärfe-Durchlauf verwendet werden.",
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Turtle"
},
"backgroundBlur": "Background Blur",
"backgroundBlur": "Blur",
"zoomMotionBlur": "Zoom Motion Blur",
"temporalZoomMotionBlur": "Temporal Zoom Blur",
"temporalZoomMotionBlurDescription": "Control the shutter window and frame samples used by the newer zoom blur pass.",
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Turtle"
},
"backgroundBlur": "Desenfoque de fondo",
"backgroundBlur": "Desenfoque",
"zoomMotionBlur": "Desenfoque de movimiento del zoom",
"temporalZoomMotionBlur": "Temporal Zoom Blur",
"temporalZoomMotionBlurDescription": "Control the shutter window and frame samples used by the newer zoom blur pass.",
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Tortue"
},
"backgroundBlur": "Flou d’arrière-plan",
"backgroundBlur": "Flou",
"zoomMotionBlur": "Flou de mouvement du zoom",
"temporalZoomMotionBlur": "Temporal Zoom Blur",
"temporalZoomMotionBlurDescription": "Control the shutter window and frame samples used by the newer zoom blur pass.",
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Tartaruga"
},
"backgroundBlur": "Sfocatura sfondo",
"backgroundBlur": "Sfocatura",
"zoomMotionBlur": "Motion blur dello zoom",
"temporalZoomMotionBlur": "Sfocatura zoom temporale",
"temporalZoomMotionBlurDescription": "Controlla la finestra dell'otturatore e i campioni di frame usati dal nuovo passaggio di sfocatura zoom.",
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Turtle"
},
"backgroundBlur": "배경 블러",
"backgroundBlur": "블러",
"zoomMotionBlur": "확대 모션 블러",
"temporalZoomMotionBlur": "Temporal Zoom Blur",
"temporalZoomMotionBlurDescription": "Control the shutter window and frame samples used by the newer zoom blur pass.",
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Schildpad"
},
"backgroundBlur": "Achtergrondvervaging",
"backgroundBlur": "Vervaging",
"zoomMotionBlur": "Zoom-bewegingsonscherpte",
"temporalZoomMotionBlur": "Temporal Zoom Blur",
"temporalZoomMotionBlurDescription": "Control the shutter window and frame samples used by the newer zoom blur pass.",
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Turtle"
},
"backgroundBlur": "Desfoque de fundo",
"backgroundBlur": "Desfoque",
"zoomMotionBlur": "Desfoque de movimento do zoom",
"temporalZoomMotionBlur": "Temporal Zoom Blur",
"temporalZoomMotionBlurDescription": "Control the shutter window and frame samples used by the newer zoom blur pass.",
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Черепаха"
},
"backgroundBlur": "Размытие фона",
"backgroundBlur": "Размытие",
"zoomMotionBlur": "Размытие при зуме",
"temporalZoomMotionBlur": "Временное размытие зума",
"temporalZoomMotionBlurDescription": "Настройка плавности зума по времени и кадрам.",
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Turtle"
},
"backgroundBlur": "背景模糊",
"backgroundBlur": "模糊",
"zoomMotionBlur": "缩放运动模糊",
"temporalZoomMotionBlur": "Temporal Zoom Blur",
"temporalZoomMotionBlurDescription": "Control the shutter window and frame samples used by the newer zoom blur pass.",
+1 -1
View File
@@ -43,7 +43,7 @@
"amongus": "Among Us",
"turtle": "Turtle"
},
"backgroundBlur": "背景模糊",
"backgroundBlur": "模糊",
"zoomMotionBlur": "縮放動態模糊",
"temporalZoomMotionBlur": "Temporal Zoom Blur",
"temporalZoomMotionBlurDescription": "Control the shutter window and frame samples used by the newer zoom blur pass.",
+4 -2
View File
@@ -2225,8 +2225,10 @@ export class FrameRenderer {
if (this.config.backgroundBlur > 0) {
ctx.save();
ctx.filter = `blur(${this.config.backgroundBlur * 3}px)`;
ctx.drawImage(bgCanvas, 0, 0, w, h);
const blurPx = this.config.backgroundBlur * 3;
const overscan = Math.ceil(blurPx * 2);
ctx.filter = `blur(${blurPx}px)`;
ctx.drawImage(bgCanvas, -overscan, -overscan, w + overscan * 2, h + overscan * 2);
ctx.restore();
} else {
ctx.drawImage(bgCanvas, 0, 0, w, h);
+11 -2
View File
@@ -1380,6 +1380,7 @@ export class FrameRenderer {
this.backgroundBlurFilter.blur = this.config.backgroundBlur * 3;
this.backgroundBlurFilter.quality = 4;
this.backgroundBlurFilter.resolution = this.app?.renderer.resolution ?? 1;
this.backgroundBlurFilter.repeatEdgePixels = true;
this.backgroundSprite.filters = [this.backgroundBlurFilter];
}
} else if (this.backgroundTextureSource) {
@@ -1410,8 +1411,16 @@ export class FrameRenderer {
}
blurredCtx.save();
blurredCtx.filter = `blur(${this.config.backgroundBlur * 3}px)`;
blurredCtx.drawImage(sourceCanvas, 0, 0, blurredCanvas.width, blurredCanvas.height);
const blurPx = this.config.backgroundBlur * 3;
const overscan = Math.ceil(blurPx * 2);
blurredCtx.filter = `blur(${blurPx}px)`;
blurredCtx.drawImage(
sourceCanvas,
-overscan,
-overscan,
blurredCanvas.width + overscan * 2,
blurredCanvas.height + overscan * 2,
);
blurredCtx.restore();
return blurredCanvas;