eagle vision: tweaks to zoom/cursor/edge scrolling#7836
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
5 Skipped Deployments
|
packages/tldraw/src/lib/tools/ZoomTool/childStates/ZoomQuick.ts
Outdated
Show resolved
Hide resolved
packages/editor/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts
Outdated
Show resolved
Hide resolved
|
I still think the right zoom is minimum zoom (5%), preserving your cursor position, rather than zoom to fit. Its strange to zoom out and press this key and end up zooming back in, and on large rooms (where the whole canvas won't fit in 5% viewport) it feels strange to have the zoomed-out viewport centered on nothing. I would want to replicate the "zoomed out temporarily to minimum from my cursor location", though perhaps the right number isn't 5%? |
|
Ok, more work on this... I think we were conflating the zoom brush and the mode of the interaction. Splitting this up so that we can show the zoom brush immediately, while still preserving the "require move before ending at the new bounds". Also switching from pointer moves to pointer position offsets to account for wheeling. |
Rewrite ZoomQuick to use an internal 'idle'/'moving' state machine and preserve cursor position when zooming out. On enter, ZoomQuick now zooms to 10% of base zoom while keeping the pointer's page point stable, shows the zoom brush immediately, and only transitions to 'moving' after exceeding the drag threshold. While moving, the brush follows the cursor proportionally and edge-scrolling is enabled; exiting applies the appropriate zoom (returning to original viewport from idle or zooming to the new viewport from moving). EdgeScrollManager was adjusted to allow edge scrolling during zoom.zoom_quick. Tests (ZoomTool.test.ts) updated to match the new behavior and timing (added tick advances and many new assertions around idle/moving, brush sizing, exits, and cancel behavior). Update EdgeScrollManager.ts
b4b8195 to
acfd222
Compare
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| 🔵 In progress View logs |
image-pipeline-template | 44f0267 | Commit Preview URL Branch Preview URL |
Feb 11 2026, 11:26 AM |
packages/tldraw/src/lib/tools/ZoomTool/childStates/ZoomQuick.ts
Outdated
Show resolved
Hide resolved
Add validation to safely access zoomSteps[1], falling back to zoomSteps[0] if the array only has one element. This prevents undefined access and NaN zoom values when users configure a single-element zoomSteps array. Co-authored-by: Steve Ruiz <[email protected]>
Sounds like we need to some design discussion/writer's room in person like I mentioned on Discord. I'm finding the 10%/5% choice unsatisfying in lots of cases, can show you when we meet. Might be a HMR thing but I'm also finding that sometimes the tool gets stuck in Zoom mode — have you seen this? |
packages/editor/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts
Outdated
Show resolved
Hide resolved
I have, yeah. |
Prevent unintended edge-scrolling and tidy related logic: - Add early camera-lock check in EdgeScrollManager.updateEdgeScrolling to skip scrolling when camera is locked. - Move the camera-lock check out of moveCameraWhenCloseToEdge and into the central update path (refactor). - Add checks in SelectTool child states (Brushing, Resizing, Translating) to only call edgeScrollManager.updateEdgeScrolling when the user is dragging and not panning. - Update ZoomQuick: adjust drag/move detection to account for zoom level and avoid edge-scrolling while camera is locked during 'moving' state. - Remove redundant/obsolete tests in EdgeScrollManager.test.ts that asserted camera movement conditions. These changes prevent camera movement when inappropriate (not dragging, panning, or camera-locked), fix zoom-sensitive movement detection, and consolidate the lock check to a single place.
Remove the camera lock check and the call to editor.edgeScrollManager.updateEdgeScrolling(elapsed) from the ZoomQuick 'moving' case. Edge-scrolling is no longer handled here (presumably moved or made redundant), simplifying the moving-state logic and avoiding duplicate or conflicting updates.
|
Removing edge scrolling from this feature, since we can't get the user's mouse position after it leaves the window (the user has not clicked so we can't capture the pointer). We could track the mouseleave and get an estimated exit position based on the last known position and the last known velocity but that feels like a separate system. |
My rationale here is:
In practice, a user would probably zoom out to the level that lets them see everything on the screen and then stop there rather than going out to 5%. That would be a kind of expanded union of the common page shape bounds and the user's viewport, that would still preserve their pointer page position. :psyduck: |
Introduce a new TldrawOptions flag quickZoomPreservesScreenBounds (default true) to control whether the quick-zoom brush preserves its screen-pixel size when the overview zoom changes. Update ZoomQuick to store an overviewZoom, compute a more robust target zoom that fits page bounds while preserving the cursor, and conditionally register a reactive updater to resize the brush when the option is enabled. Also add a cleanup hook for the reactor, adjust brush sizing in getNextVpb based on the option, and make small API/import/parameter refinements.
|
API Changes Check Passed Great! The PR description now includes the required "### API changes" section. This helps reviewers and SDK users understand the impact of your changes. |
|
Ok, some changes summarized. This should replicate the "zoom out from my mouse cursor until everything is on screen". More realistic zoom levelThe old
Viewport while zooming /
|
|
Landing this. The remaining issues are UX opinions but I'm reasonably happy with them, enough to learn more in the hand. My one thing is whether the zoom really should just be 10% / 5% in order to be more static and predictable, rather than dynamic based on where the cursor is on the screen. |
|
we're discussing at the moment! |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| this.cleanupZoomReactor = react('zoom change in quick zoom', () => { | ||
| editor.getZoomLevel() | ||
| this.updateBrush() | ||
| }) |
There was a problem hiding this comment.
Reactor over-subscribes causing inconsistent brush-following behavior
Low Severity
The react() callback calls this.updateBrush(), which reads getCurrentPagePoint() and getCurrentScreenPoint() — both reactive atoms. This makes the reactor fire on every pointer move, not just zoom changes as the comment and name suggest. As a side effect, when quickZoomPreservesScreenBounds is true, the brush follows the cursor in idle state. But when false, no reactor exists and onPointerMove returns early in idle state (qzState !== 'moving'), so the brush freezes at its initial position until the drag threshold is crossed, then jumps. The quickZoomPreservesScreenBounds option unintentionally controls brush-following behavior in addition to brush-sizing.


couple tweaks to eagle vision 🦅
Change type
bugfiximprovementfeatureapiotherAPI changes
Added
quickZoomPreservesScreenBoundstoTldrawOptions(defaulttrue). When true, the quick-zoom brush maintains constant screen-pixel size as the user zooms the overview — zooming in shrinks the target viewport, zooming out expands it. Set tofalseto keep fixed page dimensions (original behavior).Release notes
Note
Medium Risk
Touches core viewport/camera behavior (quick-zoom camera math, brush sizing, and edge-scrolling conditions), so regressions could affect navigation/interaction feel across tools, though changes are well-covered by updated tests.
Overview
Quick zoom (
zoom.zoom_quick) is reworked to compute a zoom-to-fit overview (instead of a fixed 5% zoom), preserve the page point under the cursor when zooming out, and only “commit” to moving/teleporting after crossing a drag threshold (idle vs moving), returning to the original viewport if released while idle.Adds
quickZoomPreservesScreenBoundstoTldrawOptions(defaulttrue) to control whether the quick-zoom brush keeps a constant screen-pixel size as the user zooms the overview, plus UI/translation plumbing to show “Quick zoom” (shift+z) in the keyboard shortcuts dialog.Edge scrolling is tightened to respect camera lock in
EdgeScrollManager, and select-tool tick handlers now call edge scrolling only while actively dragging and not panning; ZoomTool cursor logic also avoids showing zoom-out while in quick-zoom even if Alt is held. Tests are updated/expanded to cover the new quick-zoom state machine, cursor/exit semantics, and the new option behavior.Written by Cursor Bugbot for commit 44f0267. This will update automatically on new commits. Configure here.