From 9cb671d069d2a4c14ab00668a217171f2c04ab57 Mon Sep 17 00:00:00 2001 From: Renan Sousa Date: Fri, 11 Sep 2026 21:23:02 -0300 Subject: [PATCH] Limit capture by samples per point, not by pixel width The capture width is capped at a fixed 2400 pixels, so a larger built in display gets a softer fold than a smaller one: the same pixels are spread over more points. A 1728 point display resolves 1.39 samples per point where a 1512 point display resolves 1.59, and the difference is visible in the fold even with the same chip behind it. Cap the ratio at 1.6 instead, with a 2800 pixel guard rail above it. Sharpness is then the same on every built in display. The smaller display is unchanged in practice, because 1.6 is where its old limit already landed, and a 1728 point display goes from 2400 to 2764 pixels wide. Everything downstream is already proportional, so nothing else needs to move: the blur sigmas scale with the small texture width, and the shader works entirely in normalized coordinates. Co-Authored-By: Claude Opus 5 --- MOTION.md | 2 +- Sources/LiveDesktop.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MOTION.md b/MOTION.md index 0006b30..c31f94c 100644 --- a/MOTION.md +++ b/MOTION.md @@ -27,7 +27,7 @@ The new projection keeps the top and bottom edges at their original height. Its Three cached Gaussian blur levels at nominal widths of 6, 16, and 36 pixels per 786-pixel reference width provide continuous progressive blur. Blur strength varies with closure and fades toward the lower tenth of the desktop. Subtle top-corner shading and side feathering complete the single effect. The side gaps are filled with the nearest desktop edge, stretched from a broad blur of the reduced frame, or with black, as chosen in Settings. The fill and the desktop are blurred as one surface: every blur level is computed from a composite that places the fill in a side margin around the reduced frame, so blurred content spreads across the fold's edge toward the top while the lower edge stays sharp. Each captured frame adds one scale and one copy into that composite. The blurred fill also runs a quarter-size broad blur and one stretch; the black fill clears the margin instead. On an M1 Max the blurred fill's chain measured about 0.2 ms per captured frame, up from 0.11 ms. An inverse projection in the fragment shader preserves the fold geometry while covering the full overlay. -The effect covers the built-in screen's full display frame, including the menu bar and Dock. A non-activating panel joins fullscreen Spaces without taking keyboard focus. Space changes keep the same capture area and bring the panel back to the front. +Capture is limited to 1.6 samples per point rather than to a fixed pixel width, with a 2800 pixel guard rail above it. A fixed width gave a larger built-in display a softer fold than a smaller one, because the same pixels were spread over more points: a 1728 point display resolved 1.39 samples per point where a 1512 point display resolved 1.59. Expressing the limit as a ratio makes sharpness the same on every built-in display, and leaves the smaller one unchanged in practice because 1.6 is where its old limit already landed. The effect covers the built-in screen's full display frame, including the menu bar and Dock. A non-activating panel joins fullscreen Spaces without taking keyboard focus. Space changes keep the same capture area and bring the panel back to the front. ## Motion timing diff --git a/Sources/LiveDesktop.swift b/Sources/LiveDesktop.swift index 3466320..72527e5 100644 --- a/Sources/LiveDesktop.swift +++ b/Sources/LiveDesktop.swift @@ -222,7 +222,7 @@ final class LiveDesktop: NSObject, ObservableObject { configuration.sourceRect = CGRect( x: area.minX - screen.frame.minX, y: screen.frame.maxY - area.maxY, width: area.width, height: area.height) - let scale = min(screen.backingScaleFactor, 2400 / area.width) + let scale = min(screen.backingScaleFactor, 2800 / area.width, 1.6) configuration.width = Int(area.width * scale) / 2 * 2 configuration.height = Int(area.height * scale) / 2 * 2 configuration.minimumFrameInterval = CMTime(value: 1, timescale: 60)