Skip to content

fix(webclient): fix XR panel snapping to face away from user when moved#629

Merged
yanziz-nvidia merged 2 commits into
mainfrom
fix/webclient-panel-face-away-snap
Jun 14, 2026
Merged

fix(webclient): fix XR panel snapping to face away from user when moved#629
yanziz-nvidia merged 2 commits into
mainfrom
fix/webclient-panel-face-away-snap

Conversation

@yanziz-nvidia

@yanziz-nvidia yanziz-nvidia commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Closes #546

Summary

  • Bug 1 (yaw accuracy): The old code used setFromUnitVectors(zAxis, dir3D) + setFromQuaternion('YXZ') to extract horizontal yaw. Because dir3D included the camera's height offset, the extracted Euler Y was not the true horizontal yaw. Replaced with Math.atan2(dx, dz) on the XZ plane.
  • Bug 2 (±π wrap): The face-camera damp() call had no angle wrapping. When the target yaw crossed the ±π boundary, damp() took the ~2π wrong-way path, spinning the panel to face backward. Normalized diff to [-π, π] before calling damp().
  • Bug 3 (Handle quaternion reset — root cause of 90° snap after drag): @pmndrs/handle's defaultApply copies state.current.quaternion to the target on every drag frame (useFrame priority -1, before face-camera at priority 0) and again on drag release. With rotate={false}, that quaternion is always the one captured at drag-start, so it continuously reset the face-camera rotation mid-drag and wiped it entirely on release — snapping the panel up to 90° off after every drag. Fixed by passing a custom apply function (applyPositionSkipRotation) to Handle that copies only position, leaving quaternion/rotation entirely under face-camera control.

Test plan

  • Enter XR session and drag the panel to the left or right — panel should rotate to face you as it moves
  • Release the handle — panel should stay facing you, not snap back to a wrong angle
  • Move/walk around the panel in the emulator — panel should track you continuously
  • Walk behind the panel — it should smoothly rotate to re-face you
  • Verify normal forward-facing behaviour is unchanged when standing still

🤖 Generated with Claude Code

…gged to the side

Two bugs in the face-camera rotation logic in CloudXRUI:

1. Missing angle wrapping before damp(): eulerHelper.y lives in [-π, +π].
   When the panel is near the side of the scene the target angle can flip
   from +π-ε to -π+ε — geometrically ~0° but numerically ~2π. damp() is a
   plain lerp so it interpolated the full ~2π the wrong way, spinning the
   panel to face backward. Fix wraps the diff to [-π, π] before calling
   damp() so it always takes the shortest rotation path.

2. 3D quaternion for a yaw-only problem: setFromUnitVectors(zAxis, dir3D)
   computed the shortest-path 3D rotation including height offset, so the
   extracted Euler Y was not the correct horizontal yaw when camera and panel
   heights differed. Replaced with Math.atan2(dx, dz) on the XZ plane which
   gives correct horizontal yaw directly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

CloudXRUI.tsx refactors the face-camera rotation implementation to remove quaternion and Euler conversions. The module now imports only essential Three.js types, retains position-vector helpers for computing projected coordinates on the XZ plane, and directly computes target yaw using atan2 from those projections. Angular deltas are normalized to the range [-π, π] for shortest-path interpolation, and the group rotation is dampened toward the computed target, replacing the prior quaternion-to-Euler (YXZ) extraction logic.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately describes the main fix: addressing XR panel snapping away from the user when moved, which is the core issue resolved in the PR.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/webclient-panel-face-away-snap

Comment @coderabbitai help to get the list of available commands and usage tips.

@yanziz-nvidia yanziz-nvidia marked this pull request as draft June 5, 2026 05:25
@yanziz-nvidia yanziz-nvidia marked this pull request as ready for review June 5, 2026 17:01
@yanziz-nvidia

Copy link
Copy Markdown
Contributor Author

@yanziz-nvidia yanziz-nvidia requested a review from nv-jakob June 5, 2026 18:05

@gareth-morgan-nv gareth-morgan-nv left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM. Maybe add a test?

Handle's defaultApply copies state.current.quaternion to the target on every
drag frame (useFrame priority -1) and again on drag release. With rotate={false},
state.current.quaternion is always the quaternion captured at drag-start, so it
continuously undoes whatever rotation face-camera (priority 0) applied, and
wipes all face-camera work entirely when the drag ends. This caused the panel
to snap to the rotation it had when the drag began — up to 90° away from the
correct facing direction.

Fix: pass a custom apply function (applyPositionSkipRotation) to Handle that
copies only position, leaving quaternion/rotation entirely under face-camera
control throughout and after the drag.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@yanziz-nvidia yanziz-nvidia force-pushed the fix/webclient-panel-face-away-snap branch from f46a423 to 5968908 Compare June 14, 2026 01:56
@yanziz-nvidia yanziz-nvidia changed the title fix(webclient): fix XR panel snapping to face away from user when dragged to the side fix(webclient): fix XR panel snapping to face away from user when moved Jun 14, 2026
@yanziz-nvidia yanziz-nvidia merged commit 8fefaeb into main Jun 14, 2026
48 checks passed
@yanziz-nvidia yanziz-nvidia deleted the fix/webclient-panel-face-away-snap branch June 14, 2026 03:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

IsaacTeleop WebXR client thumbsticks move and gets stuck

2 participants