sparksbud

WebXR Input Design

A VR menu needs an escape route as much as it needs a pointer. We learned that while building Sparksbud's headset dock: a button can work with a trigger and still become unreachable when the panel fades, a controller disconnects, or the visitor has only gaze input. The useful design unit is the complete path from appearing to selecting to getting the menu back.

Start with WebXR input sources, then design each menu action for a ray, a press and a recovery path. Sparksbud uses controller selection events for buttons, press and release for sliders, and a timed gaze selection when no controller source is connected. The dock can be brought back after hiding. Hand input and Vision Pro still need device-specific checks.

What WebXR actually gives you

WebXR input sources describe where an aim ray comes from and how a primary action is reported. A controller, a tracked hand and a gaze pointer may behave differently. A browser can add or remove sources during a session, so inputSources is a changing list rather than a permanent pair of hands. The selectstart, select and selectend events are useful for different moments in the same action.

Sparksbud asks for an immersive-vr session from the Enter VR button and requests local-floor and hand-tracking as optional features. A browser can decline an optional feature and still open the session. That is why the dock also accepts controller selection and gaze. The WebXR session request must stay attached to the visitor's button action; moving it behind an unrelated asynchronous setup step risks losing the required user activation.

Three paths to one VR dock action A controller trigger, a hand pinch, or a timed gaze dwell aims at the dock. Sparksbud maps each to one selected action, with a separate reveal step when the dock is hidden. One dock action, three input paths Aim first. Select once. Keep a way back when the dock hides. Controller ray Trigger selects Press and hold for sliders Tracked hand Pinch selects Browser source varies Gaze fallback Look for 1.5 seconds Only with no source connected Visible dock action
Three paths to one VR dock action Controller trigger, hand pinch and timed gaze dwell each select an action on the dock. A hidden dock has a separate reveal step. One dock action Three ways to aim and select Controller ray Trigger selects Hold and move for a slider Tracked hand Pinch selects Check the real device source Gaze fallback Look for 1.5 seconds Only with no source connected Visible dock action
One dock action has three input paths. The browser supplies an input source; Sparksbud checks the ray against the dock and maps a select event, a held slider press or a timed gaze dwell to the same action.
Input paths in the current Sparksbud dock
SituationAim and actionRecovery when the dock is hidden
Controller source connectedPoint a target ray and press the triggerPress once to reveal the dock, then choose an action
Tracked hand exposed as a controller sourceAim the ray and pinch to selectPinch to reveal the dock
No controller source connectedLook at a dock target for 1.5 secondsLook away, then back at the old dock position for 1.5 seconds

The controller and gaze paths have code and Quest emulator checks. They do not cover every controller model or prove physical hand input, gaze comfort or Vision Pro behavior.

Those paths share actions, but they do not share a control signal. In Sparksbud, a trigger or pinch calls select. A slider starts on selectstart, tracks the same target while held and finishes on selectend. A quick click handler alone would make the slider feel broken. When a second resting controller is present, the dock keeps the active one from stealing hover until the user moves or selects again.

The recovery lesson

The dock sits in world space, just below the visitor's view. It fades after controller inactivity. We found that restoring it on any gaze hit caused an immediate reappearance after Hide: the visitor was still looking at the same place. The current gaze path requires a look away before a look back. That makes recovery a deliberate action without drawing a permanent floating instruction over the scene.

For controllers, a first press when the dock is hidden reveals it and does not also activate the button underneath. Once visible, the visitor can choose a control. A grip squeeze recenters a visible dock. These are separate states in the input code, and the tests check both the hidden and visible paths. A timed gaze also remembers the last button it fired so a layout repaint does not trigger the same choice twice.

A hidden dock needs a deliberate returnSparksbud separates revealing a hidden dock from selecting a control. Its gaze path requires a look away before a look back. A hidden dock needs a deliberate returnThe first action reveals; the next action chooses.01ControllerA first triggerpress reveals thedock.02Hand sourceA pinch can revealit.03Gaze onlyLook away, then backfor the dwell.04Visible dockChoose the controlyou meant to use.
A hidden dock needs a deliberate returnSparksbud separates revealing a hidden dock from selecting a control. Its gaze path requires a look away before a look back.A hidden dock needs adeliberate returnThe first action reveals; the nextaction chooses.1ControllerA first trigger press reveals thedock.2Hand sourceA pinch can reveal it.3Gaze onlyLook away, then back for thedwell.4Visible dockChoose the control you meant touse.
Sparksbud separates revealing a hidden dock from selecting a control. Its gaze path requires a look away before a look back.

Put the dock away while the ray is already over a button, then select once. The action should restore the dock without firing the hidden button.

Keep the pose and the menu alive

The world motion can stop while the headset pose keeps updating. Sparksbud's render loop still draws a surround world when motion is paused, which lets the visitor look around and use the dock. A pause that also stops head tracking would be a broken VR state. Its menu input and rendering use the current XR camera pose, and its own state reports whether the dock is visible, which input path is active and what is hovered.

When the visitor switches worlds in VR, the old world remains visible while the new one prepares. The loading cue appears in the dock, then the next scene replaces the old one after preparation. That choice avoids leaving the visitor in an untracked blank view during synchronous geometry work. Our world lifecycle note follows the loading path.

Test the transitions, not just the click

A compact test matrix for a headset dock
ChangeWhat to checkFailure it catches
Visible to hiddenHide, fade and idle timeoutA menu that blocks the scene or never leaves
Hidden to visibleFirst press reveals without selectingAn accidental action behind the hidden panel
One source to anotherConnect, disconnect, then selectA stale pointer or slider drag
Press to drag to releaseMove along a slider before letting goA value that jumps or never commits
World switchKeep pose, cue and exit availableA frozen headset view during loading

We run browser checks and a two-eye Quest emulator for these paths. Those checks prove the application state and stereo render in that environment. They cannot prove how a physical Quest pinch feels, whether a real hand is exposed the same way, or how Safari on Apple Vision Pro maps look-and-pinch. We have not tested Sparksbud on Vision Pro. The dock currently binds two Three.js controller slots; a transient pointer on another device is a reason to test the actual input-source sequence before promising support.

Test the state changes around a clickThe input test matrix checks recovery, source changes, slider drag and world switching as well as a simple selection. Test the state changes around a clickA working button is only one part of input.Hide and revealNo accidental actionunderneath.Change sourceNo stale pointerafter disconnect.Drag a sliderStart, move and endstay connected.Switch worldsPose, dock and ExitVR remain usable.
Test the state changes around a clickThe input test matrix checks recovery, source changes, slider drag and world switching as well as a simple selection.Test the state changesaround a clickA working button is only one part ofinput.Hide and revealNo accidental action underneath.Change sourceNo stale pointer after disconnect.Drag a sliderStart, move and end stayconnected.Switch worldsPose, dock and Exit VR remainusable.
The input test matrix checks recovery, source changes, slider drag and world switching as well as a simple selection.

After swapping from controllers to hands, drag a slider as well as tapping a button. The drag can expose stale input state that a single select misses.

What we would change next

For a broader device target, we would record the input-source profile, target-ray mode and select events on the physical device, without logging hand poses or personal data. Then we would make the dock's pointer policy explicit for transient sources. The aim is to preserve the same user outcome: see a target, choose it once, and recover the menu. The Quest entry guide covers the visitor's steps; this note is about the implementation behind them.

Questions developers ask

Should gaze always be active beside controllers?

No. Sparksbud enables timed gaze selection when no controller source is connected. With a controller present, gaze could compete for hover and fire an unintended action.

Why use selectstart and selectend for a slider?

They mark the held interaction. Sparksbud starts the drag on selectstart, updates the value while the ray stays on that slider and clears the drag on selectend.

Does optional hand tracking guarantee hands will work?

No. An optional feature may be unavailable or declined, and devices expose input differently. Test the source and event sequence on the physical headset you support.

Why render while world motion is paused?

The visitor still needs head tracking, the dock and Exit VR. Sparksbud can stop scene travel while continuing the XR render loop and input updates.

Has this input design been verified on Vision Pro?

No. Its WebXR input model needs a physical Safari session test. The Quest emulator and code review do not establish Vision Pro behavior.