diff --git a/crates/ui-egui/src/app.rs b/crates/ui-egui/src/app.rs
--- a/crates/ui-egui/src/app.rs
+++ b/crates/ui-egui/src/app.rs
@@ -215,9 +215,11 @@ impl LauncherUi {
         self.toasts.clear();
     }
 
-    /// Input on its way to egui (the shell's `raw_input_hook`): with fewer animations asked for,
-    /// a mouse wheel scrolls at once instead of gliding.
+    /// Input on its way to egui (the shell's `raw_input_hook`): a mouse wheel notch scrolls as far
+    /// as the Mouse wheel scroll speed setting says, and with fewer animations asked for, it
+    /// scrolls at once instead of gliding.
     pub fn raw_input(&self, ctx: &egui::Context, raw: &mut egui::RawInput) {
+        self.settings.scroll_speed.apply(ctx, raw);
         if self.reduce_motion {
             motion::unsmooth_wheel(ctx, raw);
         }
@@ -515,6 +517,9 @@ impl LauncherUi {
             motion::apply(&ctx, self.reduce_motion);
             self.applied_motion = Some(self.reduce_motion);
         }
+        // For a host without a `raw_input_hook` (the tests' harness); the hook sets it in time
+        // for the frame's own wheel events.
+        self.settings.scroll_speed.set_line_speed(&ctx);
         let tokens = Tokens::get(&ctx);
         if self.entries.iter().any(|e| e.job.is_some()) || self.checking {
             ctx.request_repaint_after(Duration::from_millis(50));
diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs
--- a/crates/ui-egui/src/dialogs.rs
+++ b/crates/ui-egui/src/dialogs.rs
@@ -6,7 +6,7 @@ use artcraft_launcher_core::{Os, PackageKind};
 use egui::{RichText, vec2};
 
 use crate::app::{Dialog, Host, LauncherUi};
-use crate::settings::{CheckEvery, Settings};
+use crate::settings::{CheckEvery, ScrollSpeed, Settings};
 use crate::theme::{self, ThemeChoice, Tokens};
 use crate::widgets::{self, Cell, Kind};
 
@@ -365,5 +365,10 @@ impl LauncherUi {
             widgets::cells(ui, &mut theme_choice, &ThemeChoice::ALL.map(|c| (c, Cell { label: c.label(), tip: c.label(), count: None })));
         });
         self.settings.theme = theme_choice;
+        let mut speed = self.settings.scroll_speed;
+        row(ui, tl!("Mouse wheel scroll speed"), 240.0, &mut |ui| {
+            widgets::cells(ui, &mut speed, &ScrollSpeed::ALL.map(|s| (s, Cell { label: s.label(), tip: s.label(), count: None })));
+        });
+        self.settings.scroll_speed = speed;
     }
 }
diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv
--- a/crates/ui-egui/src/i18n/cs.tsv
+++ b/crates/ui-egui/src/i18n/cs.tsv
@@ -224,6 +224,10 @@ month	Dec	12.
 	Match system	Podle systému
 	Dark	Tmavý
 	Light	Světlý
+	Mouse wheel scroll speed	Rychlost posouvání kolečkem myši
+scroll speed	Slow	Pomalá
+scroll speed	Normal	Normální
+scroll speed	Fast	Rychlá
 	Full changelog	Úplný přehled změn
 	link	odkaz
 	No apps match	Žádné aplikace neodpovídají hledání
diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv
--- a/crates/ui-egui/src/i18n/de.tsv
+++ b/crates/ui-egui/src/i18n/de.tsv
@@ -243,6 +243,10 @@ month	Dec	Dez.
 	Match system	Wie das System
 	Dark	Dunkel
 	Light	Hell
+	Mouse wheel scroll speed	Scrollgeschwindigkeit des Mausrads
+scroll speed	Slow	Langsam
+scroll speed	Normal	Normal
+scroll speed	Fast	Schnell
 	Full changelog	Vollständiges Änderungsprotokoll
 	link	Link
 	No apps match	Keine passenden Apps
diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv
--- a/crates/ui-egui/src/i18n/es.tsv
+++ b/crates/ui-egui/src/i18n/es.tsv
@@ -237,6 +237,10 @@ month	Dec	dic.
 	Match system	Igual que el sistema
 	Dark	Oscuro
 	Light	Claro
+	Mouse wheel scroll speed	Velocidad de desplazamiento de la rueda del ratón
+scroll speed	Slow	Lenta
+scroll speed	Normal	Normal
+scroll speed	Fast	Rápida
 	Full changelog	Registro de cambios completo
 	link	enlace
 	No apps match	Ninguna aplicación coincide
diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv
--- a/crates/ui-egui/src/i18n/fr.tsv
+++ b/crates/ui-egui/src/i18n/fr.tsv
@@ -241,6 +241,10 @@ month	Dec	déc.
 	Match system	Comme le système
 	Dark	Sombre
 	Light	Clair
+	Mouse wheel scroll speed	Vitesse de défilement de la molette
+scroll speed	Slow	Lente
+scroll speed	Normal	Normale
+scroll speed	Fast	Rapide
 	Full changelog	Journal des modifications complet
 	link	lien
 	No apps match	Aucune application ne correspond
diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv
--- a/crates/ui-egui/src/i18n/hu.tsv
+++ b/crates/ui-egui/src/i18n/hu.tsv
@@ -244,6 +244,10 @@ month	Dec	dec.
 	Match system	Rendszerbeállítás szerint
 	Dark	Sötét
 	Light	Világos
+	Mouse wheel scroll speed	Egérgörgő görgetési sebessége
+scroll speed	Slow	Lassú
+scroll speed	Normal	Normál
+scroll speed	Fast	Gyors
 	Full changelog	Teljes változásnapló
 	link	hivatkozás
 	No apps match	Nincs találat
diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv
--- a/crates/ui-egui/src/i18n/ja.tsv
+++ b/crates/ui-egui/src/i18n/ja.tsv
@@ -246,6 +246,10 @@ month	Dec	12月
 	Match system	システムに合わせる
 	Dark	ダーク
 	Light	ライト
+	Mouse wheel scroll speed	マウスホイールのスクロール速度
+scroll speed	Slow	遅い
+scroll speed	Normal	標準
+scroll speed	Fast	速い
 	Full changelog	完全な変更履歴
 	link	リンク
 	No apps match	一致するアプリがありません
diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv
--- a/crates/ui-egui/src/i18n/pl.tsv
+++ b/crates/ui-egui/src/i18n/pl.tsv
@@ -245,6 +245,10 @@ month	Dec	gru
 	Match system	Zgodnie z systemem
 	Dark	Ciemny
 	Light	Jasny
+	Mouse wheel scroll speed	Szybkość przewijania kółkiem myszy
+scroll speed	Slow	Wolna
+scroll speed	Normal	Normalna
+scroll speed	Fast	Szybka
 	Full changelog	Pełna lista zmian
 	link	link
 	No apps match	Brak pasujących aplikacji
diff --git a/crates/ui-egui/src/i18n/pt-BR.tsv b/crates/ui-egui/src/i18n/pt-BR.tsv
--- a/crates/ui-egui/src/i18n/pt-BR.tsv
+++ b/crates/ui-egui/src/i18n/pt-BR.tsv
@@ -231,6 +231,10 @@ month	Dec	dez.
 	Match system	Igual ao sistema
 	Dark	Escuro
 	Light	Claro
+	Mouse wheel scroll speed	Velocidade de rolagem da roda do mouse
+scroll speed	Slow	Lenta
+scroll speed	Normal	Normal
+scroll speed	Fast	Rápida
 	Full changelog	Histórico completo de alterações
 	link	link
 	No apps match	Nenhum aplicativo encontrado
diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv
--- a/crates/ui-egui/src/i18n/ru.tsv
+++ b/crates/ui-egui/src/i18n/ru.tsv
@@ -240,6 +240,10 @@ month	Dec	дек.
 	Match system	Как в системе
 	Dark	Тёмная
 	Light	Светлая
+	Mouse wheel scroll speed	Скорость прокрутки колесом мыши
+scroll speed	Slow	Низкая
+scroll speed	Normal	Обычная
+scroll speed	Fast	Высокая
 	Full changelog	Полный список изменений
 	link	ссылка
 	No apps match	Нет подходящих приложений
diff --git a/crates/ui-egui/src/i18n/tests.rs b/crates/ui-egui/src/i18n/tests.rs
--- a/crates/ui-egui/src/i18n/tests.rs
+++ b/crates/ui-egui/src/i18n/tests.rs
@@ -185,6 +185,19 @@ fn complete_catalogs_translate_every_tagline() {
     }
 }
 
+/// The Mouse wheel scroll speed row and the speed names, which qualify "speed" and so have their
+/// own context, in every complete catalog.
+#[test]
+fn complete_catalogs_name_the_scroll_speeds() {
+    for lang in Lang::all().filter(|l| l.complete_menus()) {
+        assert!(super::has(lang, "Mouse wheel scroll speed"), "{}", lang.code());
+        for speed in crate::scroll_speed::ScrollSpeed::ALL {
+            assert!(lang.catalog().contextual("scroll speed", speed.key()).is_some(), "{}: {}", lang.code(), speed.key());
+        }
+    }
+    assert_eq!(super::tr_ctx(Lang::RU, "scroll speed", "Slow"), "Низкая");
+}
+
 #[test]
 fn product_names_stay_in_english() {
     for lang in Lang::all() {
diff --git a/crates/ui-egui/src/i18n/zh-CN.tsv b/crates/ui-egui/src/i18n/zh-CN.tsv
--- a/crates/ui-egui/src/i18n/zh-CN.tsv
+++ b/crates/ui-egui/src/i18n/zh-CN.tsv
@@ -160,6 +160,10 @@ month	Dec	12月
 	Match system	跟随系统
 	Dark	深色
 	Light	浅色
+	Mouse wheel scroll speed	鼠标滚轮滚动速度
+scroll speed	Slow	慢
+scroll speed	Normal	正常
+scroll speed	Fast	快
 	Full changelog	完整更新日志
 	link	链接
 	No apps match	没有匹配的应用
diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs
--- a/crates/ui-egui/src/lib.rs
+++ b/crates/ui-egui/src/lib.rs
@@ -26,6 +26,7 @@ pub mod icons;
 pub mod model;
 mod motion;
 mod notes;
+mod scroll_speed;
 pub mod settings;
 pub mod theme;
 mod views;
diff --git a/crates/ui-egui/src/scroll_speed.rs b/crates/ui-egui/src/scroll_speed.rs
new file mode 100644
--- /dev/null
+++ b/crates/ui-egui/src/scroll_speed.rs
@@ -0,0 +1,130 @@
+//! How far a mouse wheel notch scrolls (#386).
+//!
+//! egui scrolls `line_scroll_speed` points per wheel line: 40 on the desktop, 8 on the web. On
+//! macOS the system already accelerates line deltas, and in a browser a line is scaled for the
+//! web. But on Windows and Linux winit reports one line per notch, where browsers and most
+//! other programs move about 100 pixels, so 40 felt slow. Wheel input reported in points (most
+//! trackpads) keeps its own speed, and ⌘/Ctrl-wheel zoom keeps egui's rate.
+
+use egui::{Event, MouseWheelUnit, RawInput};
+use serde::{Deserialize, Serialize};
+
+/// The user's choice, relative to the platform's normal speed.
+#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub enum ScrollSpeed {
+    Slow,
+    #[default]
+    Normal,
+    Fast,
+}
+
+/// egui's own `line_scroll_speed`, which its wheel zoom rate is tuned against.
+const EGUI_LINE_POINTS: f32 = if cfg!(target_arch = "wasm32") { 8.0 } else { 40.0 };
+
+/// Points one wheel line scrolls at Normal speed.
+const NORMAL_LINE_POINTS: f32 = if cfg!(target_arch = "wasm32") {
+    // The browser's line deltas, which egui already scales for the web.
+    8.0
+} else if cfg!(target_os = "macos") {
+    40.0
+} else {
+    100.0
+};
+
+/// The catalog context of the speed names: they qualify "speed".
+const CONTEXT: &str = "scroll speed";
+
+impl ScrollSpeed {
+    pub const ALL: [Self; 3] = [Self::Slow, Self::Normal, Self::Fast];
+
+    /// The English name, the catalog key.
+    pub fn key(self) -> &'static str {
+        match self {
+            Self::Slow => "Slow",
+            Self::Normal => "Normal",
+            Self::Fast => "Fast",
+        }
+    }
+
+    /// The name in the language the UI is drawn in.
+    pub fn label(self) -> &'static str {
+        crate::i18n::tr_ctx(crate::i18n::current(), CONTEXT, self.key())
+    }
+
+    /// Points one wheel line scrolls.
+    pub fn line_points(self) -> f32 {
+        NORMAL_LINE_POINTS
+            * match self {
+                Self::Slow => 0.5,
+                Self::Normal => 1.0,
+                Self::Fast => 2.0,
+            }
+    }
+
+    /// Makes egui scroll this far per wheel line, from this frame's input on (call it before egui
+    /// reads `raw`). egui scales line deltas before turning ⌘/Ctrl-wheel motion into zoom, so
+    /// those events are scaled back to keep zooming at egui's own rate.
+    pub(crate) fn apply(self, ctx: &egui::Context, raw: &mut RawInput) {
+        self.set_line_speed(ctx);
+        let zoom_modifier = ctx.options(|o| o.input_options.zoom_modifier);
+        let zoom_scale = EGUI_LINE_POINTS / self.line_points();
+        for event in &mut raw.events {
+            if let Event::MouseWheel { unit: MouseWheelUnit::Line, delta, modifiers, .. } = event
+                && modifiers.matches_any(zoom_modifier)
+            {
+                *delta *= zoom_scale;
+            }
+        }
+    }
+
+    /// Makes egui scroll this far per wheel line (from the next frame when called during one).
+    pub(crate) fn set_line_speed(self, ctx: &egui::Context) {
+        let points = self.line_points();
+        if ctx.options(|o| o.input_options.line_scroll_speed) != points {
+            ctx.options_mut(|o| o.input_options.line_scroll_speed = points);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    fn wheel(unit: MouseWheelUnit, dy: f32, command: bool) -> Event {
+        let modifiers = egui::Modifiers { command, ..egui::Modifiers::NONE };
+        Event::MouseWheel { unit, delta: egui::vec2(0.0, dy), phase: egui::TouchPhase::Move, modifiers }
+    }
+
+    #[test]
+    fn scrolling_follows_the_choice_and_zoom_keeps_egui_rate() {
+        let ctx = egui::Context::default();
+        for speed in ScrollSpeed::ALL {
+            let mut raw = RawInput {
+                events: vec![
+                    wheel(MouseWheelUnit::Line, 1.0, true),
+                    wheel(MouseWheelUnit::Line, 1.0, false),
+                    wheel(MouseWheelUnit::Point, 30.0, true),
+                ],
+                ..Default::default()
+            };
+            speed.apply(&ctx, &mut raw);
+            assert_eq!(ctx.options(|o| o.input_options.line_scroll_speed), speed.line_points());
+            let dy: Vec<f32> = raw.events.iter().filter_map(|e| if let Event::MouseWheel { delta, .. } = e { Some(delta.y) } else { None }).collect();
+            // A ⌘/Ctrl line is scaled back so egui's zoom sees its own points per line; a plain
+            // line and a point delta are untouched.
+            assert!((dy[0] * speed.line_points() - EGUI_LINE_POINTS).abs() < 1e-3, "{speed:?}: {dy:?}");
+            assert_eq!((dy[1], dy[2]), (1.0, 30.0));
+        }
+        assert_eq!(ScrollSpeed::Slow.line_points() * 4.0, ScrollSpeed::Fast.line_points());
+    }
+
+    #[test]
+    fn normal_is_faster_than_egui_only_where_a_notch_is_one_line() {
+        let normal = ScrollSpeed::Normal.line_points();
+        if cfg!(any(target_os = "windows", target_os = "linux")) {
+            assert!(normal > EGUI_LINE_POINTS, "{normal}");
+        } else {
+            assert_eq!(normal, EGUI_LINE_POINTS);
+        }
+    }
+}
diff --git a/crates/ui-egui/src/settings.rs b/crates/ui-egui/src/settings.rs
--- a/crates/ui-egui/src/settings.rs
+++ b/crates/ui-egui/src/settings.rs
@@ -6,6 +6,7 @@ use artcraft_launcher_core::PackageKind;
 use serde::{Deserialize, Serialize};
 
 use crate::i18n::t;
+pub use crate::scroll_speed::ScrollSpeed;
 use crate::theme::ThemeChoice;
 
 #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
@@ -114,6 +115,8 @@ pub struct Settings {
     pub last_check: Option<i64>,
     /// Catalog ids of apps hidden from the main lists (`photocraft`, …).
     pub hidden: std::collections::BTreeSet<String>,
+    /// How far a mouse wheel notch scrolls.
+    pub scroll_speed: ScrollSpeed,
 }
 
 impl Settings {
@@ -186,6 +189,7 @@ impl Default for Settings {
             notified: BTreeMap::new(),
             last_check: None,
             hidden: std::collections::BTreeSet::new(),
+            scroll_speed: ScrollSpeed::Normal,
         }
     }
 }
diff --git a/crates/ui-egui/tests/ui.rs b/crates/ui-egui/tests/ui.rs
--- a/crates/ui-egui/tests/ui.rs
+++ b/crates/ui-egui/tests/ui.rs
@@ -14,7 +14,7 @@ use artcraft_launcher_core::protocol::{
 use artcraft_launcher_core::release::{Asset, Release};
 use artcraft_launcher_core::status::InstallSource;
 use artcraft_launcher_core::{Arch, Installed, Os, Platform, SUITE, version};
-use artcraft_launcher_ui_egui::settings::ViewMode;
+use artcraft_launcher_ui_egui::settings::{ScrollSpeed, ViewMode};
 use artcraft_launcher_ui_egui::{Host, LauncherUi, Settings};
 use egui_kittest::Harness;
 use egui_kittest::kittest::{NodeT, Queryable};
@@ -1471,6 +1471,60 @@ fn with_animations_on_the_wheel_glides() {
     assert!((moved - notch).abs() < 0.5, "moved {moved} of {notch}");
 }
 
+// Issue #386: a wheel notch moved egui's 40 points, which felt slow on Windows, where a notch
+// is reported as one line and other programs move about 100 pixels. The Mouse wheel scroll
+// speed setting decides how far a notch goes.
+#[test]
+fn a_wheel_notch_scrolls_as_far_as_the_scroll_speed_setting_says() {
+    let mut h = short_window(Rc::new(Cell::new(true)));
+    for speed in [ScrollSpeed::Normal, ScrollSpeed::Fast, ScrollSpeed::Slow] {
+        if let Some(l) = h.state_mut() {
+            l.settings.scroll_speed = speed;
+        }
+        h.run_steps(2);
+        let start = grid_top(&h);
+        // A notch, or the part of one that moves 100 points: the short window has room for that.
+        let lines = (100.0 / speed.line_points()).min(1.0);
+        let notch = lines * speed.line_points();
+        turn_wheel(&mut h, lines);
+        h.run_steps(2);
+        let moved = start - grid_top(&h);
+        assert!((moved - notch).abs() < 0.5, "{speed:?}: moved {moved} of {notch}");
+        // Back to the top for the next speed.
+        h.hover_at(egui::pos2(590.0, 300.0));
+        for _ in 0..8 {
+            turn_wheel(&mut h, -4.0);
+        }
+        h.run_steps(2);
+    }
+    // At Normal, the platform's own speed: egui's on macOS, faster where a notch is one line.
+    let normal = ScrollSpeed::Normal.line_points();
+    if cfg!(any(target_os = "windows", target_os = "linux")) {
+        assert!(normal > 40.0, "{normal}");
+    } else {
+        assert_eq!(normal, 40.0);
+    }
+    assert_eq!(ScrollSpeed::Fast.line_points(), 2.0 * normal);
+    assert_eq!(ScrollSpeed::Slow.line_points(), 0.5 * normal);
+}
+
+#[test]
+fn the_scroll_speed_is_picked_in_settings() {
+    let (mut h, _) = harness(ViewMode::Grid, egui::Theme::Dark, true);
+    h.run_steps(6);
+    h.get_by_label("Settings").click();
+    h.run_steps(4);
+    h.get_by_label("Mouse wheel scroll speed");
+    h.get_by_label("Fast").click();
+    h.run_steps(2);
+    assert_eq!(h.state().as_ref().unwrap().settings.scroll_speed, ScrollSpeed::Fast);
+    assert_eq!(h.ctx.options(|o| o.input_options.line_scroll_speed), ScrollSpeed::Fast.line_points());
+    h.get_by_label("Slow").click();
+    h.run_steps(2);
+    assert_eq!(h.state().as_ref().unwrap().settings.scroll_speed, ScrollSpeed::Slow);
+    assert_eq!(h.ctx.options(|o| o.input_options.line_scroll_speed), ScrollSpeed::Slow.line_points());
+}
+
 /// Moves the pointer from one card to the next. Returns how many frames are drawn before the
 /// window is still again.
 fn frames_to_hover_the_next_card(h: &mut Harness<'_, Option<LauncherUi>>) -> u64 {
