Fix XrMenu rendering outside of XR sessions - #9155
Merged
Merged
Conversation
`initialize` hid the menu with `_setMenuVisible(false)`, but that early-outs on its no-change guard because `_menuVisible` is already `false`. The initial hide was therefore a no-op: the container kept `Entity`'s default `enabled = true`, `_updateMenuOpacity` never ran so the elements stayed at the opacities `_createButton` assigned, and `update` bails while `xr.active` is false — so the menu rendered opaque at the world origin for the whole pre-XR lifetime. `_onXrEnd` had the same problem from the other direction: it only requested the fade-out, which `update` can no longer advance once the session has ended, so a menu that was open at exit stayed frozen in the world. Add `_hideImmediate` to apply the hide synchronously and use it from both paths. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Build size reportThis PR does not change the size of the minified bundles.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Any app that mounts the
XrMenuscript renders the menu in the scene while not in XR — opaque, at the world origin. Reproduces in this repo's ownxr/xr-menuexample and in every web-components example that uses the script; it's only conspicuous where the camera happens to frame the origin closely (e.g. the shoe configurator, where the 7.5 cm menu fills a fifth of the frame).Inspecting the live scene outside XR, before this change:
XrMenuContainer.enabledtrueelement.opacity0.85element.opacity1_menuVisible/_currentOpacity/_targetOpacityfalse/0/0The internal state says "hidden" while the scene graph says "visible".
Cause
initializehides the menu via_setMenuVisible(false), but that method opens with a no-change guard:_menuVisibleis alreadyfalsefrom its field initializer, so the initial hide is a no-op:_menuContainerkeepsEntity's defaultenabled = true._updateMenuOpacitynever runs — it's only called fromupdatewhen_currentOpacity !== _targetOpacity, and both are0— so the elements stay at the opacities_createButtonassigned.updatereturns on its first line while!app.xr.active._onXrEndfails the same way from the other direction: it only requests the fade-out by setting_targetOpacity = 0, andupdatestops advancing that fade the moment the session ends. Exit XR with the menu open and it stays frozen in the world at its last headset-relative pose.Both cases are one flaw: hiding is delegated to a fade loop that only runs during an XR session, while the initial hide is delegated to a setter that can't fire.
Fix
Add
_hideImmediate— zero the opacities, clear hover/press state, disable the container — and call it frominitializeand from_onXrEnd(after_setMenuVisible(false), which is kept so'xr:menu:active'still fires for listeners when the menu was open).Testing
Verified in the shoe-configurator web-components example with the patched script dropped in:
false✔0✔0✔_setMenuVisible(true)+ fade to 1true✔0.85✔1✔_onXrEndfalse✔0✔0✔The show path is unaffected:
_setMenuVisible(true)re-enables the container and the existing_targetOpacity > 0guard inupdatestill prevents the first-framedt ≈ 0self-disable. Lint passes.🤖 Generated with Claude Code