Skip to content

Allow rotating ortho view #8614

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 147 commits into from
Jul 15, 2025
Merged

Allow rotating ortho view #8614

merged 147 commits into from
Jul 15, 2025

Conversation

MichaelBuessemeyer
Copy link
Contributor

@MichaelBuessemeyer MichaelBuessemeyer commented May 12, 2025

Documentation about rotation & 3d scene

https://www.notion.so/scalableminds/3D-Rotations-3D-Scene-210b51644c6380c2a4a6f5f3c069738a
This documentation explains the quirky of how rotations are handled in more details.

URL of deployed dev instance (used for testing):

  • https://___.webknossos.xyz

Steps to test:

  • Review the docs file above

  • UI

    • Check in the navbar the position input. Right to the text input, there should be a new button.
    • Hover that button. It is the new rotation pop over
    • Play round with the pop over, slide the sliders. No value jumping should occur. When the rotation changes, the viewports should adjust accordingly
    • Also use the manual number input
    • Try the reset buttons individually. This should reset only the axis's value to 0.
    • Try the reset all button. It should reset the whole rotation to 0,0,0
    • Check the URL. When the rotation value changes, the rotation stored in the url hash should as well (deferred by 2 seconds or so)
  • Keyboard shortcuts:

    • Use the shortcuts to rotate the cameras / planes: shift + up/down/left/right & alt + left/right. Holding should continue the rotation.
    • Use the shortcuts to directly rotate by 90°. Same as above just with ctrl pressed additionally. Holding should !not! continue the rotation.
  • Tools

    • In view mode check the line measurement tool & use it. The area measurement tool should not be available once the rotation is no longer 0,0,0.
    • create an annotation of a dataset with anisotropic voxel scaling.
    • once a rotation is configured, all tools except for the line measurement tool and the skeleton tool should no longer be available.
    • test the line measurement tool again
    • Skeleton tool testing
      • try creating some nodes while a rotation is active.
      • create multiple trees. Each tree should be traced with a different rotation active. Moreover, also trace some in different viewports.
      • try moving nodes around
      • in the layers tab - skeleton- disable "Auto-rotate to Nodes"
      • activate some previously traced nodes. The rotation should not change.
      • activate the "Auto-rotate to Nodes" setting. Again activate the trees / nodes. The rotation should now change to the rotation is was previously when the tree was traced.
        • This can easily be detected when the nodes are close to each other. All nodes of the tree should be visible as they were tracing in the same planar orientation. The viewports in which the "plane of nodes" should be visible should be the same as during the tracing.
      • Deactivate the "Auto-center nodes" setting. Now again active the trees / nodes. The cameras should still rotate towards the nodes but not move there to center the active node.
      • splitting trees and so on should also still work
      • Reset the orientation. Give the volume tools a try. They should work as expected.
      • Proofreading.
        • create an annotation with a hdf5 (or zarr) mapping and go into the proofreading tool.
        • Now do some proofreading actions. This should work
        • configure some rotation. Again do some proofreading actions. Everything should still work as expected.
    • As the semantics of the getGlobalPosition from clicked position changed. Please give each other tracing tool a quick try whether it still works as expected.
  • 3D viewport

    • Please check the 3d viewport buttons.
    • Configure a rotation
    • Use the 4 orientation buttons of the 3d viewport. They should focus the clicked plane / look from the top-right corner down at the cross section. Just as when no rotaiton is configured.
    • Reset the rotation. Check the buttons again. They should behave as on the master.
  • Tabs

    • Give the segment, skeleton and so on tabs a quick little testing whether the basics still work. Just avoid unwanted easily catchable bugs.
  • Arbitrary view

    • Check the tracing in arbitrary view. rotating there should still work as well as creating nodes and so on.
    • Including flight & oblique mode
  • And of cause: Other things you thing might be broken by this PR

  • URL / Links

    • Please check that links inlude the rotation in the hash and that it is applied on page load.
    • Configure some rotation
    • Copy the full URL into another tab and view it
    • It should automatically show the configured rotation and the 3d viewport should still look like the 3d button of it was just clicked (-> looking at the planes correctly and not in wrong / weird way / angle)

TODOs:

  • fix rendering correct data in ortho viewports (avoid rendering data offset by clipping distance)
  • Do not use rotation value of just activated skeleton node
    • Discuss what the actual rotation value of a newly created node should be
  • Fully adapt context menu (disabled options too complex to support in current interaction if rotation is active)
  • fix scalebar info when rotated
  • adapt bucket picking (reuse picker for arbitrary mode)
  • Fix rendering wrong slice due to offset calculation floating point inaccuracies.
  • Fix dataset navigation via space
  • put rotation value into url
  • adapt shader
    • optimizations are turned off when
  • The URL zoom state is increasing with every created skeleton node xD
    • Nope, my mistake. The active node id is part of the url
  • Fix centering new nodes. Currently the animation slowly offsets the rotated plane backwards and thus multiple click lead to a "slice switch" -> thus the user stays not on the same plane.
  • adapt mouse interactions
    • mapping of mouse position to voxel position
    • fix skeleton tool interactions
      • move skeleton node
    • fix measurement tools interactions
      • Line measurement
      • area measurement
        • A little more complicated: Deferred for now -> Disable while rotated.
  • Fix brushing in wrong slice ://
  • first iteration should only support skeleton tool
  • Brushing is off by one
  • UI
    • disable all tools beside skeleton & measurement once rotation is active
    • expose rotation value
    • "warn" user when angles are not axis aligned
      • The rotation button in the position view now has an orange warning border in case the dataset is currently rotated
  • Put correct buckets on GPU.
  • active tool mouse cursor is somehow broken?!
    • Seemed to be browser hiccups
  • Fix dynamicSpaceDirection setting while rotation is active
  • Consider optimizing the code by avoiding creating new threejs objects and use mjs instead
  • Create issue for rotation aware prefetcher & delete this prs rotation aware prefetcher try
  • Check whether dynamic space orientation still works
    • "df switching" works
  • Fix rotation UI: Some rotations are ambiguous and just sliding the sliders causes jumps in the sliders
  • Fix measurement tooltip to not follow the screen while moving in plane
  • disable or support rendering of segmentation data in rotated viewport (how to interpolate?)
    • works for now, not sure about interpolation
    • fix pattern rendering
      • its kinda fixed but the pattern does not rotate correctly with the data leading to unexpected "pattern moving" while rotating
      • Accepted for now
  • Interpolate active node rotation via quaternions; rotates pretty wonky currently
    • Test rotating to nodes in arbitrary view mode
  • Adapt 3d viewport rotation buttons
    • 3d button does not yield the desired result
  • No data is rendered in fly mode when rotation is exactly [0, 0, 0]
  • Bug: Node selection + rotation activation leads to strange rotations being activated
  • refactor getUnrotatedWorldCoordUVW
  • On l4_sample with #3598,3476,994,0,0.933,30,0,0,50 there can be a "black row"
  • test ctrl + alt + left and ctrl + alt + right keyboard shortcut for 90° rotation. Doesn't work on my system as it is a window manager reserved shortcut.
  • Fix line measurement tool when rotation is active.
    • Is buggy in anisotropic datasets

Issues:


(Please delete unneeded items, merge only when none are left open)

Copy link
Contributor

coderabbitai bot commented May 12, 2025

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.
📝 Walkthrough

Walkthrough

This update introduces free rotation in orthogonal viewports, refactoring core 3D transformation logic, UI, and state management to support arbitrary camera orientation in orthogonal mode. It adds rotation-aware shaders, disables incompatible tools when rotated, exposes rotation controls in the UI, and updates tests and reducers for consistent rotation handling throughout the application.

Changes

File(s) / Group Change Summary
viewer/model/accessors/flycam_accessor.ts, viewer/model/helpers/rotation_helpers.ts Refactored flycam rotation accessors to use radians, matrices, and add helpers for conversion between Euler angles and matrices; added new rotation helpers module.
viewer/model/reducers/flycam_reducer.ts Unified rotation/movement logic with THREE.js Euler/Matrix4, storing normalized rotation in state, and updating movement to apply flycam rotation.
viewer/constants.ts, viewer/controller/camera_controller.ts Added mappings and base rotations for orthogonal views; updated camera controller to apply flycam rotation to orthogonal cameras.
viewer/controller/scene_controller.ts, viewer/geometries/plane.ts Refactored plane positioning and rotation to use flycam rotation and dataset scale factor, with reactive updates and improved matrix handling.
viewer/model/accessors/view_mode_accessor.ts Replaced planar offset calculations with full 3D transformations using flycam rotation/translation; global position now includes both rounded and floating coordinates.
viewer/controller/combinations/*, viewer/controller/url_manager.ts, viewer/model/actions/skeletontracing_actions.ts Updated all position and node creation handlers to use rounded/floating positions and pass rotation consistently; updated setActiveNodeAction to accept suppressRotation.
viewer/model/sagas/skeletontracing_saga.ts, volumetracing_saga.tsx, prefetch_saga.ts Made tracing and prefetching rotation-aware; added logic to apply node rotation on activation and to disable prefetching and tracing when rotated.
viewer/model/accessors/disabled_tool_accessor.ts, view/action-bar/tools/toolbar_view.tsx, view/context_menu.tsx Disabled volume, area, and bounding box tools and context menu items when rotated, providing user explanations.
viewer/view/action-bar/dataset_position_view.tsx, dataset_rotation_popover_view.tsx, action_bar_view.tsx Refactored position view to functional component, added rotation popover with sliders and reset; updated action bar to use new component.
viewer/view/components/setting_input_views.tsx, left-border-tabs/layer_settings_tab.tsx, messages.tsx Added UI for rotation setting and new setting key/messages; updated slider component for rotation controls.
viewer/model_initialization.ts, default_state.ts, store.ts Added rotation to default flycam state and user config; always initializes rotation from dataset.
viewer/api/api_latest.ts, controller/viewmodes/arbitrary_controller.tsx, plane_controller.tsx Updated API and controllers to support new rotation logic, keyboard controls, and passing suppress flags for rotation/centering.
viewer/geometries/materials/plane_material_factory.ts, shaders/*.glsl.ts Added uniforms for flycam rotation and inverted voxel size, updated shader logic for rotation, coordinate transformation, and filtering; added getUnrotatedWorldCoordUVW.
viewer/view/distance_measurement_tooltip.tsx, statusbar.tsx, right-border-tabs/abstract_tree_tab.tsx, comment_tab/comment.tsx Updated tooltip and tab logic to use new rotation and position handling; refactored components to functional/hooks.
test/* Updated and extended tests to cover new rotation logic, node creation under rotation, and updated expectations for position/rotation.
viewer/model/helpers/nml_helpers.ts, model/sagas/volumetracing_saga.tsx Updated serialization and tracing to use degrees for rotation.
viewer/types/schemas/url_state.types.ts Removed obsolete type definition file.
viewer/geometries/arbitrary_plane.ts Removed unused setPosition method.
viewer/geometries/helper_geometries.ts Prevented duplicate edge points in contour geometry.
viewer/view/plane_view.ts Renamed local variables for consistency.

Assessment against linked issues

Objective Addressed Explanation
Adapt bucket picking for rotated orthogonal viewports (#7569)
Adapt shader logic for rotated orthogonal viewports (#7569)
Adapt mouse interactions: mapping mouse position to voxel position (#7569)
Disable or support segmentation/volume tools and rendering in rotated viewports; UI warnings/exposure (#7569)
Expose rotation value and controls in UI for orthogonal viewports (#7569)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Removal of frontend/javascripts/types/schemas/url_state.types.ts This file was a workaround for schema generation and is not directly related to orthogonal viewport rotation features.
Refactor of viewer/view/plane_view.ts (variable renaming) Variable renaming for camelCase consistency is unrelated to rotation or orthogonal viewport objectives.
Minor change in geometries/helper_geometries.ts (duplicate edge point prevention) Preventing duplicate edge points in contour geometry is not directly related to orthogonal viewport rotation.
Removal of setPosition in geometries/arbitrary_plane.ts Removing an unused method is unrelated to the objectives of orthogonal viewport rotation.

Possibly related PRs

Suggested reviewers

  • philippotto

Poem

In orthogonal lands, the viewports now spin,
With shaders and matrices, let rotations begin!
The tools take a rest when the view is askew,
While sliders and popovers give angles their due.
The rabbit hops freely, with vectors in tow—
Orthogonal, arbitrary, all in a row!
🐇✨


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor Author

@MichaelBuessemeyer MichaelBuessemeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for all the feedback. Here are my answers.

I'll ask for the next review hopefully soon. I just noticed that the line measurement tool does not work for datasets with anisotropic voxel scale. At least scale [1,1,1] works but the normal l4_sample voxel scale does not.

Copy link
Contributor Author

@MichaelBuessemeyer MichaelBuessemeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I fixed the line measurement tool for anisotropic datasets while they are viewed with rotation.

The bug was due to not correctly calcuating a global position back into the screen viewport space to check whether the user moved the viewport back / forth to hide the tooltip. Now the calculation is correct. I also added tests for the calculation of global positions which I used for debugging this. My initial understanding that the calculation of a global position from an event was wrong. I still kept the tests as they seemed useful to me.

Sooooo now that this is done, I'd say this ready for another review round and of cause a testing session :D

@MichaelBuessemeyer
Copy link
Contributor Author

Oh and a frontend test seems to timeout consistently. I'll take a look at this but this should not block your review

@MichaelBuessemeyer
Copy link
Contributor Author

@philippotto in my latest commit I "fixed" a test by removing a take statement. I am honestly confused why this is suddenly necessarry. Do you maybe have an idea?
Here are the logs from the test from the two branches. Each end enriched with some debug error loggings and logActions form wk_dev turned on. It shows that somehow on this branch the saga execution stops after the SET_VERSION_NUMBER.
Compared to the master, where additional actions are dispatched; inlcuding the expected FINISH_MAPPING_INITIALIZATION action.

on master, working:

stderr | frontend/javascripts/test/sagas/proofreading.spec.ts > Proofreading > should update the mapping when the server has a new update action with a merge operation
before tryToIncorporateActions
working on mergeAgglomerate with activeMapping:  {
  mappingName: 'sampleHdf5Mapping',
  mapping: Map(8) {
    1 => 10,
    2 => 10,
    3 => 10,
    4 => 11,
    5 => 11,
    6 => 12,
    7 => 12,
    1337 => 1337
  },
  mappingColors: undefined,
  hideUnmappedIds: false,
  mappingStatus: 'ENABLED',
  mappingType: 'HDF5',
  isMergerModeMapping: undefined
}
triggering setMappingAction
dispatching updating version action
dispatched updating action
after tryToIncorporateActions
before FINISH_MAPPING_INITIALIZATION

stdout | frontend/javascripts/test/sagas/proofreading.spec.ts > Proofreading > should update the mapping when the server has a new update action with a merge operation
SET_MAPPING
  dispatching {
    type: 'SET_MAPPING',
    layerName: 'volumeTracingId',
    mappingName: 'sampleHdf5Mapping',
    mappingType: 'HDF5',
    mapping: Map(8) {
      1 => 10,
      2 => 10,
      3 => 10,
      4 => 10,
      5 => 10,
      6 => 12,
      7 => 12,
      1337 => 1337
    },
    mappingColors: undefined,
    hideUnmappedIds: undefined,
    showLoadingIndicator: undefined,
    isMergerModeMapping: undefined
  }
SET_VERSION_NUMBER
  dispatching { type: 'SET_VERSION_NUMBER', version: 1 }

stdout | frontend/javascripts/test/sagas/proofreading.spec.ts > Proofreading > should update the mapping when the server has a new update action with a merge operation
SET_TOOL
  dispatching {
    type: 'SET_TOOL',
    tool: [class MoveTool extends AbstractAnnotationTool] {
      id: 'MOVE',
      readableName: 'Move Tool'
    }
  }
  Cancel old bucket watcher
  ENSURE_TRACINGS_WERE_DIFFED_TO_SAVE_QUEUE
    dispatching {
      type: 'ENSURE_TRACINGS_WERE_DIFFED_TO_SAVE_QUEUE',
      callback: [Function: callback]
    }

stdout | frontend/javascripts/test/sagas/proofreading.spec.ts > Proofreading > should update the mapping when the server has a new update action with a merge operation
FINISH_MAPPING_INITIALIZATION
  dispatching { type: 'FINISH_MAPPING_INITIALIZATION', layerName: 'volumeTracingId' }
  ENSURE_TRACINGS_WERE_DIFFED_TO_SAVE_QUEUE
    dispatching {
      type: 'ENSURE_TRACINGS_WERE_DIFFED_TO_SAVE_QUEUE',
      callback: [Function: callback]
    }
CLEAR_MAPPING
  dispatching { type: 'CLEAR_MAPPING', layerName: 'volumeTracingId' }

stderr | frontend/javascripts/test/sagas/proofreading.spec.ts > Proofreading > should update the mapping when the server has a new update action with a merge operation
  after FINISH_MAPPING_INITIALIZATION

on this branch

stderr | frontend/javascripts/test/sagas/proofreading.spec.ts > Proofreading > should update the mapping when the server has a new update action with a merge operation
before tryToIncorporateActions
working on mergeAgglomerate with activeMapping:  {
  mappingName: 'sampleHdf5Mapping',
  mapping: Map(8) {
    1 => 10,
    2 => 10,
    3 => 10,
    4 => 11,
    5 => 11,
    6 => 12,
    7 => 12,
    1337 => 1337
  },
  mappingColors: undefined,
  hideUnmappedIds: false,
  mappingStatus: 'ENABLED',
  mappingType: 'HDF5',
  isMergerModeMapping: undefined
}
triggering setMappingAction
dispatching updating version action
dispatched updating action
after tryToIncorporateActions
before FINISH_MAPPING_INITIALIZATION

stdout | frontend/javascripts/test/sagas/proofreading.spec.ts > Proofreading > should update the mapping when the server has a new update action with a merge operation
SET_MAPPING
  dispatching {
    type: 'SET_MAPPING',
    layerName: 'volumeTracingId',
    mappingName: 'sampleHdf5Mapping',
    mappingType: 'HDF5',
    mapping: Map(8) {
      1 => 10,
      2 => 10,
      3 => 10,
      4 => 10,
      5 => 10,
      6 => 12,
      7 => 12,
      1337 => 1337
    },
    mappingColors: undefined,
    hideUnmappedIds: undefined,
    showLoadingIndicator: undefined,
    isMergerModeMapping: undefined
  }
SET_VERSION_NUMBER
  dispatching { type: 'SET_VERSION_NUMBER', version: 1 }

 ❯ frontend/javascripts/test/sagas/proofreading.spec.ts (4 tests | 1 failed | 3 skipped) 20943ms
   ↓ Proofreading > should merge two agglomerates and update the mapping accordingly
   ↓ Proofreading > should split two agglomerates and update the mapping accordingly
   × Proofreading > should update the mapping when the server has a new update action with a merge operation 20941ms
     → Test timed out in 20000ms.
If this is a long-running test, pass a timeout value as the last argument or configure it globally with "testTimeout".
   ↓ Proofreading > should update the mapping when the server has a new update action with a split operation

@MichaelBuessemeyer
Copy link
Contributor Author

@philippotto FYI: The new assertion that the active tool is still the proofreading tool after the test I fixed on this branch is working on this branch and failing on the master. On master the active tool indeed switches back to the the move tool.
Here is the assertion error from the master:

should update the mapping when the server has a new update action with a merge operation
AssertionError: expected [Function MoveTool] to be [Function ProofreadTool] // Object.is equality

- Expected
+ Received

- [Function ProofreadTool]
+ [Function MoveTool]

 ❯ frontend/javascripts/test/sagas/proofreading.spec.ts:309:26
    307| 
    308|       const activeTool = yield select((state) => state.uiInformation.activeTool);
    309|       expect(activeTool).toBe(AnnotationTool.PROOFREAD);
       |                          ^
    310|     });

So the fix of removing the take statement should indeed be correct

@philippotto
Copy link
Member

philippotto commented Jul 11, 2025

testing went mostly well 🎉 however, I found one bug:

  • scrolling while keeping alt pressed should always zoom into the current mouse position. this only works when the rotation is 0,0,0 (or if the mouse is in the center of the viewport). if this is not the case, the zooming is weird because it does not keep the projection of the current viewport intact (the image data changes then because the current position changes, too).

Copy link
Contributor Author

@MichaelBuessemeyer MichaelBuessemeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the thorough review @philippotto.
And thanks for finding this bug. I did know that alt + scroll is a feature.

Please give it another try. I just pushed the fix (see commit 01bbc9a). The fix includes a new flycam action for which I also added tests. I needed the new flycam action as the part of the zoom to mouse position was to modify the position of the flycam with an absolute translation that ignored the current rotation of the flycam and scaling / zoom value and so on. No action does this.

Of cause: I could also have used the setPosition action and handed it the flycamPos + offset. If you prefer this, please just tell me, but I don't really see the benefit for this except maybe no new action.

Once the CI is done, I'll redeploy for easier testing

@@ -93,7 +95,7 @@ function getMousePosition() {
return calculateGlobalPos(state, {
x: mousePosition[0],
y: mousePosition[1],
}).rounded;
}).floating;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I figured this might be a little better to have a bit more accuracy.

Copy link
Contributor Author

@MichaelBuessemeyer MichaelBuessemeyer Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is only used for the zoom to mouse position

Copy link
Member

@philippotto philippotto left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome stuff! thanks for pulling this to the finish line 🥇

@MichaelBuessemeyer MichaelBuessemeyer enabled auto-merge (squash) July 15, 2025 07:17
@MichaelBuessemeyer MichaelBuessemeyer merged commit 254d094 into master Jul 15, 2025
5 checks passed
@MichaelBuessemeyer MichaelBuessemeyer deleted the ortho-view-rotation-v2 branch July 15, 2025 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow to rotate freely in orthogonal viewports
2 participants