diff --git a/ROADMAP.md b/ROADMAP.md
--- a/ROADMAP.md
+++ b/ROADMAP.md
@@ -2,7 +2,7 @@
 
 **Stage: pre-alpha** · next: alpha, ~5% and ~110–180 h away (the alpha gate's three failing workflows)
 
-> **Last reviewed:** 2026-10-24 · **Last updated:** 2026-10-25 · **Change:** trivial (Auto Pan stereo balance, Clip List Auto Rename, Strip Silence rectangles, Strip Silence Rename, Strip Silence Extract and Separate, Clip Looping dialog, AudioSuite Vari-Fi speed ramps, Auto Pan plugin, Subharmonic plugin, Ring Modulator plugin, Float32 file headroom) · **Target:** Avid Pro Tools Ultimate 2026.4.1
+> **Last reviewed:** 2026-10-24 · **Last updated:** 2026-10-25 · **Change:** trivial (Cancel Zoom Toggle, Auto Pan stereo balance, Clip List Auto Rename, Strip Silence rectangles, Strip Silence Rename, Strip Silence Extract and Separate, Clip Looping dialog, AudioSuite Vari-Fi speed ramps, Auto Pan plugin, Subharmonic plugin, Ring Modulator plugin, Float32 file headroom) · **Target:** Avid Pro Tools Ultimate 2026.4.1
 
 SoundCraft is a clean-room, pure-Rust digital audio workstation that aims at full parity with
 Avid Pro Tools, and then beyond it: faster, open, scriptable and agent-controllable. This page is
@@ -122,6 +122,7 @@ mutated and truncated movies. Field reports from the first public week are track
 
 ## Progress log
 
+- **2026-10-25:** Alt+Shift+E (`view.zoom_toggle_cancel`) and an Alt-click on the Zoom Toggle button cancel Zoom Toggle and keep the current view: the zoom, the scroll and the track heights stay as they are, and the button is no longer lit. The next Zoom Toggle zooms in from that view and goes back to it. No readiness percentage change.
 - **2026-10-25:** Auto Pan moves the balance of a stereo track: the left channel's level falls as the position moves right and the right channel's as it moves left, at constant power, and each channel stays on its own side. At the center the track passes unchanged, so a wide or out-of-phase stereo image keeps its width, and the envelope follower follows the louder channel. No readiness percentage change.
 - **2026-10-24:** Clip List › Auto Rename (`clip.auto_rename`) sets the names that editing gives the clips it separates from the selected clips: a name, a starting number, a number of places (zeros before the number) and a suffix. The piece after each cut takes the next name, the piece before it keeps its name, and all the pieces count up one number sequence. Pieces that Strip Silence names with its own Rename fields, or removes, take no Auto Rename name. Copied clips keep their scheme when they are pasted, saved sessions hold the schemes, and Import Session Data brings them along. No readiness percentage change.
 - **2026-10-24:** While the Strip Silence window is open, the Edit window draws a rectangle around each range that Strip would keep on the selected tracks, padded by Clip Start Pad and Clip End Pad, and the rectangles follow the sliders as they move. They are removed when the window closes. `edit.strip_silence_preview` returns the same ranges without changing the session. No readiness percentage change.
@@ -175,6 +176,7 @@ mutated and truncated movies. Field reports from the first public week are track
 
 | Date | Change | Summary |
 |---|---|---|
+| 2026-10-25 | trivial | Progress log: Cancel Zoom Toggle; readiness estimates unchanged |
 | 2026-10-25 | trivial | Progress log: Auto Pan stereo balance; readiness estimates unchanged |
 | 2026-10-24 | trivial | Progress log: Clip List Auto Rename; readiness estimates unchanged |
 | 2026-10-24 | trivial | Progress log: Strip Silence rectangles; readiness estimates unchanged |
diff --git a/crates/engine/src/cmd/zoom_toggle.rs b/crates/engine/src/cmd/zoom_toggle.rs
--- a/crates/engine/src/cmd/zoom_toggle.rs
+++ b/crates/engine/src/cmd/zoom_toggle.rs
@@ -1,4 +1,5 @@
-//! Zoom Toggle: zoom in on the edit selection, then back out to the view before.
+//! Zoom Toggle: zoom in on the edit selection, then back out to the view before. Cancel Zoom Toggle turns it off
+//! and keeps the current view.
 use super::{CommandSpec, always, f64_or};
 use soundcraft_model::{TrackHeight, ZoomToggle};
 use soundcraft_time::MAX_POSITION;
@@ -7,7 +8,16 @@ use crate::{Engine, Result, cmd};
 use serde_json::{Value, json};
 
 pub fn specs() -> Vec<CommandSpec> {
-    vec![cmd!(noundo "view.zoom_toggle", "Zoom Toggle", [], None, "{width_px?: 1200, height_px?: 600}", always, toggle)]
+    vec![
+        cmd!(noundo "view.zoom_toggle", "Zoom Toggle", [], None, "{width_px?: 1200, height_px?: 600}", always, toggle),
+        cmd!(noundo "view.zoom_toggle_cancel", "Cancel Zoom Toggle", [], Some("Alt+Shift+E"), "{}", always, cancel),
+    ]
+}
+
+/// Forget the view Zoom Toggle would go back to, leaving the zoom, scroll and track heights as they are.
+fn cancel(e: &mut Engine, _: &Value) -> Result<Value> {
+    let was_on = e.session_mut().edit.zoom_toggle.take().is_some();
+    Ok(json!({"on": false, "canceled": was_on}))
 }
 
 fn toggle(e: &mut Engine, p: &Value) -> Result<Value> {
@@ -73,6 +83,24 @@ mod tests {
         assert_eq!(view(&e), (500.0, 1000, vec![Medium, Fit(299), Medium]));
     }
 
+    #[test]
+    fn cancel_keeps_the_zoomed_view_and_the_next_toggle_zooms_in_again() {
+        let mut e = engine(json!({"tracks": ["Audio 1", "Audio 3"], "start": 48_000, "end": 96_000}));
+        e.execute("view.zoom_toggle", &json!({"width_px": 1000.0, "height_px": 500.0})).unwrap();
+        let zoomed = view(&e);
+        assert_eq!(e.execute("view.zoom_toggle_cancel", &json!({})).unwrap(), json!({"on": false, "canceled": true}));
+        assert_eq!(e.session().edit.zoom_toggle, None);
+        assert_eq!(view(&e), zoomed, "cancel keeps the view Zoom Toggle zoomed in to");
+        assert_eq!(e.execute("view.zoom_toggle_cancel", &json!({})).unwrap(), json!({"on": false, "canceled": false}));
+        assert_eq!(view(&e), zoomed);
+        e.execute("view.zoom_set", &json!({"samples_per_px": 200.0})).unwrap();
+        assert_eq!(e.execute("view.zoom_toggle", &json!({"width_px": 1000.0, "height_px": 500.0})).unwrap(), json!({"on": true}));
+        e.execute("view.zoom_toggle", &json!({})).unwrap();
+        assert_eq!(view(&e), (200.0, 48_000, vec![Fit(249), Medium, Fit(249)]), "the toggle goes back to the view it saw after the cancel");
+        let spec = crate::cmd::command_specs().iter().find(|c| c.id == "view.zoom_toggle_cancel").unwrap();
+        assert_eq!(spec.shortcut, Some("Alt+Shift+E"));
+    }
+
     #[test]
     fn hostile_sizes_and_stored_views_stay_in_range() {
         let mut e = engine(json!({"tracks": ["Audio 1"], "start": 0, "end": MAX_POSITION}));
diff --git a/crates/ui-egui/src/edit_window.rs b/crates/ui-egui/src/edit_window.rs
--- a/crates/ui-egui/src/edit_window.rs
+++ b/crates/ui-egui/src/edit_window.rs
@@ -78,6 +78,11 @@ impl EditLayout {
     pub fn scroll_by(&mut self, dy: f32, view_h: f32) {
         self.scroll_y = (self.scroll_y + dy).clamp(0.0, (self.content_h - view_h + 40.0).max(0.0));
     }
+
+    /// Clears the vertical scroll position Zoom Toggle would restore, so Cancel Zoom Toggle keeps the current scroll.
+    pub(crate) fn forget_zoom_back(&mut self) {
+        self.zoom_back = None;
+    }
 }
 
 pub fn rect([x0, y0, x1, y1]: [f32; 4]) -> Rect {
@@ -469,8 +474,13 @@ fn hscrollbar(app: &mut SoundApp, ui: &mut Ui, sb: Rect, tl: Rect) {
     }
 }
 
-/// Zoom Toggle sized to the track area on screen.
+/// Zoom Toggle sized to the track area on screen. With Alt held (an Alt-click on the button) it cancels Zoom Toggle
+/// instead and keeps the current view.
 pub fn zoom_toggle(app: &mut SoundApp) {
+    if app.docking_context.as_ref().is_some_and(|c| c.input(|i| i.modifiers.alt)) {
+        let _ = app.run("view.zoom_toggle_cancel", json!({}));
+        return;
+    }
     let [x0, y0, x1, y1] = app.edit_layout.timeline;
     let _ = app.run("view.zoom_toggle", json!({"width_px": x1 - x0, "height_px": y1 - y0}));
 }
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
@@ -597,6 +597,9 @@ impl SoundApp {
                     // Re-selecting a scrolling mode resumes the playhead follow.
                     self.edit_layout.follow_hold = false;
                 }
+                if id == "view.zoom_toggle_cancel" {
+                    self.edit_layout.forget_zoom_back();
+                }
                 if id == "track.clear_clip_indicators" {
                     self.meters.values_mut().chain([&mut self.main_meter]).for_each(|m| m.clip = false);
                 }
diff --git a/crates/ui-egui/tests/it/zoom_toggle.rs b/crates/ui-egui/tests/it/zoom_toggle.rs
--- a/crates/ui-egui/tests/it/zoom_toggle.rs
+++ b/crates/ui-egui/tests/it/zoom_toggle.rs
@@ -1,5 +1,5 @@
 use egui::os::OperatingSystem;
-use egui::{Key, vec2};
+use egui::{Key, Modifiers, vec2};
 use egui_kittest::{Harness, kittest::Queryable};
 use serde_json::json;
 use soundcraft_ui_egui::{Services, SoundApp};
@@ -41,3 +41,46 @@ fn e_fits_the_selection_to_the_edit_window_and_the_button_goes_back() {
         assert_eq!(view(h.state()), before, "{os:?}");
     }
 }
+
+#[test]
+fn alt_shift_e_and_an_alt_click_cancel_zoom_toggle_and_keep_the_zoomed_view() {
+    for os in [OperatingSystem::Mac, OperatingSystem::Windows, OperatingSystem::Nix] {
+        for alt_click in [false, true] {
+            let mut app = SoundApp::new(soundcraft_engine::demo::demo_engine(), None, Services::default());
+            let bass = app.engine.session().track_by_name("Bass").unwrap().id.0;
+            app.engine.execute("edit.select", &json!({"tracks": [bass], "start": 96_000, "end": 192_000})).unwrap();
+            let mut h = Harness::builder().with_size(vec2(1600.0, 1000.0)).with_os(os).build_ui_state(
+                |ui, app: &mut SoundApp| {
+                    app.logic(&ui.ctx().clone());
+                    app.ui(ui);
+                },
+                app,
+            );
+            h.run_steps(5);
+            let view = |a: &SoundApp| (a.engine.session().edit.zoom, a.edit_layout.rows.clone(), a.edit_layout.scroll_y);
+            let before = view(h.state());
+            h.get_by_label("Zoom Toggle (E)").click();
+            h.run_steps(1);
+            let zoomed = view(h.state());
+            assert_ne!(zoomed, before, "{os:?}");
+
+            if alt_click {
+                h.get_by_label("Zoom Toggle (E)").click_modifiers(Modifiers::ALT);
+            } else {
+                h.key_press_modifiers(Modifiers::ALT | Modifiers::SHIFT, Key::E);
+            }
+            h.run_steps(2);
+            let how = if alt_click { "Alt-click" } else { "Alt+Shift+E" };
+            assert_eq!(h.state().engine.session().edit.zoom_toggle, None, "{os:?} {how}");
+            assert_eq!(view(h.state()), zoomed, "{os:?} {how} keeps the zoomed view");
+
+            // The next toggle zooms in from here and goes back here, not to the view before the cancel.
+            h.get_by_label("Zoom Toggle (E)").click();
+            h.run_steps(1);
+            assert!(h.state().engine.session().edit.zoom_toggle.is_some(), "{os:?} {how}");
+            h.get_by_label("Zoom Toggle (E)").click();
+            h.run_steps(1);
+            assert_eq!(view(h.state()), zoomed, "{os:?} {how}");
+        }
+    }
+}
diff --git a/docs/ui-parity.md b/docs/ui-parity.md
--- a/docs/ui-parity.md
+++ b/docs/ui-parity.md
@@ -1,6 +1,6 @@
 # UI parity
 
-> **Last reviewed:** 2026-10-16 · **Last updated:** 2026-10-16 · **Change:** minor (Scroll Into View in the track name menu) · **Target:** Avid Pro Tools Ultimate 2026.4.1
+> **Last reviewed:** 2026-10-16 · **Last updated:** 2026-10-25 · **Change:** minor (Cancel Zoom Toggle) · **Target:** Avid Pro Tools Ultimate 2026.4.1
 
 How SoundCraft feels in the hands of a Pro Tools user: tools, modes, modifiers, shortcuts,
 windows, meters. Measured from `crates/model/src/session.rs` (tools, modes), the command
@@ -21,6 +21,7 @@ Legend: ✅ matches · 🟡 partial · ❌ missing.
 | Live waveform fade preview | ✅ | Waveform amplitude updates during fade-length and midpoint-curvature drags, sharing the curve's temporary envelope. Mono/stereo, waveform styles, zoom and clip gain remain effective; release preserves the displayed waveform with one undo step and cached peaks |
 | Edit modes: Shuffle, Slip, Spot, Grid (absolute/relative) | ✅ | Spot dialog present |
 | Grid and nudge values, all timebases | ✅ | Bars/Beats, Min:Secs, Timecode, Feet+Frames, Samples |
+| Zoom Toggle | 🟡 | E (Commands focus) and the button zoom to the edit selection with Fit To Window heights and back; Alt+Shift+E and Alt-click cancel it and keep the view. The Zoom Toggle preferences (Vertical Zoom, Horizontal Zoom, Track Height, Track View, Separate Grid Settings When Zoomed In, Zoom Toggle Follows Edit Selection, Remove Range Selection After Zooming In) are not present |
 | Keyboard focus modes (Commands, Clip List, Groups) | 🟡 | Commands focus single-key editing ✅; list focus partial |
 | Link timeline/edit, link track/edit, Tab to transient, insertion follows playback | ✅ | |
 | Mirrored MIDI, MIDI merge, layered editing | 🟡 | Stored and partly honoured |
@@ -69,6 +70,7 @@ Legend: ✅ matches · 🟡 partial · ❌ missing.
 
 | Date | Change | Summary |
 |---|---|---|
+| 2026-10-25 | minor | Zoom Toggle row: Alt+Shift+E and Alt-click cancel Zoom Toggle and keep the view. Readiness estimate unchanged |
 | 2026-10-16 | minor | Track name menu: Scroll Into View brings the track to the top of the Edit window and the left of the Mix. Readiness estimate unchanged |
 | 2026-10-13 | minor | A plugin opens when it's inserted (#486) |
 | 2026-10-13 | minor | Drag across checkboxes (#399) |
