mcpbeat

Xb Hands

google/xb-hands

>- Add WebXR hand tracking to an XR Blocks app — enable hand joints, optional joint and mesh visualizations, pinch-to-select, and direct touch/grab of meshes. Use when you need the user's hands (index-finger touch, grab, wrist/joint positions) rather than just controller rays, or want to visualize hands in the simulator's pose mode. Covers `enableHands()`, the `options.hands.*` flags, `xb.user.hands` (`getIndexTip`, `getWrist`), and the object touch/grab lifecycle hooks. For named gestures (fist, point, spread…) use xb-gestures.

608 tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
455
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/google/xrblocks --skill xb-hands

The instruction itself

5 sections, as written by the author

xb-hands: hand tracking

Setup

const options = new xb.Options();
options.enableReticles();
options.enableHands();

options.hands.enabled = true;
options.hands.visualization = true; // render hands
options.hands.visualizeJoints = true; // show joint spheres
options.hands.visualizeMeshes = true; // show hand meshes

// Develop hands on desktop: simulator pose mode.
options.simulator.defaultMode = xb.SimulatorMode.POSE;
xb.init(options);

Reacting to hands

xb.user drives direct interaction. Pinch maps to select, so onSelectStart/End already

covers "pinch". For direct touch and grab of meshes in the scene, use the object-targeted

hooks on your Script (return true to stop propagation):

class Grabbable extends xb.Script {
  init() {
    this.box = new THREE.Mesh(/* … */);
    this.add(this.box);
  }
  onObjectTouchStart(e) {
    // index fingertip entered a mesh's bounds
    // e.handIndex (0|1), e.touchPosition: THREE.Vector3
  }
  onObjectGrabStart(e) {
    // touching + pinching
    // e.handIndex, e.hand: THREE.Object3D (the wrist)
  }
  onObjectGrabbing(e) {}
  onObjectGrabEnd(e) {}
}

Reading joints directly

const hands = xb.user.hands; // present once enableHands() + tracking
if (hands) {
  const tip = hands.getIndexTip(0); // index fingertip of hand 0 (THREE.Object3D)
  const wrist = hands.getWrist(1);
  if (tip) tip.getWorldPosition(this._v3);
}
xb.user.isSelecting(0); // is hand 0 pinching?

Notes

  • numHands is 2; hand index 0/1. xb.user.handedness (0 left, 1 right, 2 both).
  • Joint name constants are exported (HandJointNames).
  • Touch detection uses each mesh's bounding box vs. the index fingertip; grab = touch +

pinch. See src/core/User.ts for exact semantics.

  • See templates/2_hands for a complete example.

How to use it

Copy the folder

Take google/xb-hands from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.