diff --git a/apps/artcraft-launcher/src/main.rs b/apps/artcraft-launcher/src/main.rs index 3806d42..a818aea 100644 --- a/apps/artcraft-launcher/src/main.rs +++ b/apps/artcraft-launcher/src/main.rs @@ -161,12 +161,19 @@ fn native_options(hidden: bool) -> eframe::NativeOptions { /// Adrenalin installer leaves the integrated GPU on the OEM driver) it crashes inside /// `amdvlk64.dll` before the first frame. `WGPU_BACKEND` still overrides the default, and then /// wgpu picks the adapter itself. Direct3D 12 shaders compile with FXC ([`pin_dx12_compiler`]). +/// +/// Direct3D 12 presents through DirectComposition rather than straight to the window. The +/// borderless window's drop shadow moves its client area down a pixel, and a swapchain made from +/// the window is then stretched over it vertically by the compositor, blurring every horizontal +/// edge and line of text. `WGPU_DX12_PRESENTATION_SYSTEM` still overrides it. #[cfg(windows)] fn wgpu_options() -> eframe::WgpuConfiguration { - use eframe::wgpu::{Backends, Dx12Compiler, PowerPreference}; + use eframe::wgpu::{Backends, Dx12Compiler, Dx12SwapchainKind, PowerPreference}; let mut config = eframe::WgpuConfiguration::default(); pin_dx12_compiler(&mut config, Dx12Compiler::from_env()); if let eframe::egui_wgpu::WgpuSetup::CreateNew(setup) = &mut config.wgpu_setup { + setup.instance_descriptor.backend_options.dx12.presentation_system = + Dx12SwapchainKind::from_env().unwrap_or(Dx12SwapchainKind::DxgiFromVisual); if let Some(backends) = Backends::from_env() { setup.instance_descriptor.backends = backends; } else { diff --git a/crates/ui-egui/src/theme.rs b/crates/ui-egui/src/theme.rs index 57067fd..e8214ec 100644 --- a/crates/ui-egui/src/theme.rs +++ b/crates/ui-egui/src/theme.rs @@ -287,7 +287,9 @@ pub fn install_fonts(ctx: &egui::Context, cjk: Option) { ("GeistMono-Bold", GEIST_MONO, &[(*b"wght", 700.0)], mono_bold()), ]; for (name, bytes, coords, family) in faces { - let tweak = FontTweak { coords: VariationCoords::new(coords.iter().copied()), ..Default::default() }; + // No subpixel binning: these fonts carry no hinting instructions, so a glyph drawn at a + // fractional x smears each stem across two pixels, leaving small text blurry at 100 %. + let tweak = FontTweak { coords: VariationCoords::new(coords.iter().copied()), subpixel_binning: Some(false), ..Default::default() }; fonts.font_data.insert(name.to_owned(), Arc::new(FontData::from_static(bytes).tweak(tweak))); let mut stack = vec![name.to_owned()]; stack.extend(fallback.iter().cloned()); diff --git a/crates/ui-egui/src/views.rs b/crates/ui-egui/src/views.rs index bf844fe..522f664 100644 --- a/crates/ui-egui/src/views.rs +++ b/crates/ui-egui/src/views.rs @@ -411,9 +411,11 @@ impl LauncherUi { // A faint wash in the app's colour fades in under the pointer. let fill = t.bg.lerp_to_gamma(app_color, 0.05 * lift); painter.rect(rect, CornerRadius::ZERO, fill, t.hairline(), egui::StrokeKind::Inside); - // On hover, a 2 px rule in the app's colour wipes in from the left along the top. + // On hover, a 2 px rule in the app's colour wipes in from the left along the top, inside the + // hairlines the card shares with its neighbours (the site's rule sits within its grid gaps). if lift > 0.0 { - painter.rect_filled(Rect::from_min_size(rect.min, vec2(rect.width() * lift, 2.0)), CornerRadius::ZERO, app_color); + let inside = rect.shrink(1.0); + painter.rect_filled(Rect::from_min_size(inside.min, vec2(inside.width() * lift, 2.0)), CornerRadius::ZERO, app_color); } // The top strip: the app's number in its colour, and its pages.