From 38f576c296017827bb16e2c21166204e5a499c49 Mon Sep 17 00:00:00 2001 From: Panos <25664832+mechpanos@users.noreply.github.com> Date: Fri, 4 Sep 2026 17:08:43 +0300 Subject: [PATCH] perf: warm the interaction handle index during open The first hover over the canvas after opening a large drawing froze the UI for a second: hover-detail query=0.2 handles=986.1 ... candidates=253 hover-dwell 986.6ms `interaction_handle_index` and the insert-hatch map it reads are built lazily, and first use is that hover. Neither can move to the loader thread: they read `hatches`, `meshes` and `block_meshes`, which are installed on the real `Scene` only after the loader has finished. Build them at the end of the open instead, where the user is already waiting. This does not make the work cheaper -- open grows by roughly the second the hover used to cost -- but a second inside an operation that is already seconds long reads very differently from a second-long freeze on a mouse move. Co-Authored-By: Claude Opus 5 --- src/app/update/file.rs | 2 ++ src/scene/mod.rs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/app/update/file.rs b/src/app/update/file.rs index 3defb1f27..53db29cc0 100644 --- a/src/app/update/file.rs +++ b/src/app/update/file.rs @@ -1438,6 +1438,8 @@ pub(super) fn on_open_file(&mut self) -> Task { if let Some(prepared) = prepared_geometry { self.tabs[i].scene.install_prepared_open_geometry(prepared); } + // Pay for the interaction index here, not on the first hover. + self.tabs[i].scene.warm_interaction_caches(); self.tabs[i] .scene .replace_selection(rustc_hash::FxHashSet::default()); diff --git a/src/scene/mod.rs b/src/scene/mod.rs index f1b8cf7df..228cfc276 100644 --- a/src/scene/mod.rs +++ b/src/scene/mod.rs @@ -7874,6 +7874,22 @@ impl Scene { } } + /// Build the interaction handle index and the insert-hatch map now, while + /// the drawing is still opening. + /// + /// Both are built lazily on first use, and first use is the user's first + /// hover over the canvas — where the cold build cost 992 ms mid-gesture + /// (`hover-detail ... handles=986.1`). They cannot move to the loader + /// thread: they read `hatches` / `meshes` / `block_meshes`, which are + /// installed on the real `Scene` after the loader is done. + /// + /// This does not make the work cheaper, it moves it to where the user is + /// already waiting. A second on an open that is already seconds long reads + /// very differently from a second-long freeze on a mouse move. + pub(crate) fn warm_interaction_caches(&self) { + let _ = self.interaction_handle_index(); + } + fn interaction_handle_index( &self, ) -> Arc {