VR in a Ferret game
Skill ferret-xr · download all skills · SKILL.md
When to use#
A game should run in a headset, a VR control scheme is needed, something must be grabbed or pointed at, or the frame time in the headset is off.
The model#
VR is opt-in and the game does not change: createGame({ xr: { enabled: true } }) loads @ferret/xr by import() only where navigator.xr exists (never on OS Beroun). The headset is the camera, the capsule stays the player, UIService is drawn on panels in the world, Interactor gets ray and touch sources, and Grabbable gives grabbing on the screen and in the headset.
Steps#
- Pass
xr: { enabled: true, storageKey: '<game>' }tocreateGame; add the samples'addEnterVrButton(game)(a session must start from a click) and honour?xr. - Add
xrbindings for the game's existing actions (xrStick,xrButton,xrPinch); keep action names, never branch game code on VR. - Keep
turnandteleportas the action names or setxr.actions; leave snap turn and vignette on by default. - Put every piece of text through
UIService; own DOM elements are not seen in the headset. - Add
Grabbable(with aRigidBody) to objects to take; setmaxMass,snapPoints,twoHanded. - Do loading (glTF, shapes, NavMesh) behind a fade; check budgets with
xr.statusand the section on budgets in the guide.
Check afterwards#
xr.status on a screen reports unsupported and the game plays as before; unit tests with a fake XrDriver; Playwright with an emulated headset; on a Quest: comfort first, then frame time (13.9 ms Quest 2, 11.1 ms Quest 3).
What usually goes wrong#
- Assuming a feature (hand tracking, layers, multiview): they are optional; read
xr.status. - Starting a session without a user click: it is refused.
- Pushing the view back from a wall or moving the camera in code: the headset owns the head; use blink and fades.
- Removing snap turn or the vignette, or dropping the "In VR" settings page.
- Loading a heavy level in free play: a dropped frame in both eyes.
- Mapping buttons "like the console": the headset has its own kind (
xr); do not reuse cursor/A/B keys.
Files#
reference/xr.md— Turn a game into a VR game with one option: head and hands, controller bindings, comfort settings, menus in the world, grabbing, budgets for Quest.reference/api-xr.md— every export of@ferret/xrwith signature and doc commentreference/api-interaction.md— every export of@ferret/interactionwith signature and doc commentreference/commands.md— 4 commands of these packages with their arguments