Skip to content

Tracking Beta

scene.tracking reads live tracking data from script – articulated hand joints, and face blendshapes when the scene runs in a face context. It is the author-facing entry point for both; you never talk to the underlying provider directly.

Two things it is useful for: reading hand or face data without planting an anchored object, and controlling when the hand-tracking provider is running.

Hands

Hand tracking is currently available on Apple Vision Pro only, and it is opt-in – nothing is tracked until a script asks for it. Gate portable scripts on the feature flag:

javascript
// Attach to: On Experience Start
if (environment.features.has("handTracking")) {
    await scene.tracking.hands.enable();   // resolves when tracking is live
}

enable() rejects if the device cannot track hands or the person declines permission, so handle the rejection rather than assuming it succeeded:

javascript
// Attach to: On Experience Start
try {
    await scene.tracking.hands.enable();
} catch (e) {
    console.log("Hand tracking unavailable: " + e.message);
}

Once tracking is live, read the hands each frame:

javascript
// Attach to: On Render
var right = scene.tracking.hands.right;      // null when that hand isn't tracked
if (right) {
    var tip = right.joints.indexFingerTip.worldTransform.position;
    console.log("Right index tip: " + tip);
}

Hands reference

MemberTypeDescription
enable()Promise<void>Opt into hand tracking. Idempotent. Resolves when the provider is running and authorized; rejects if denied or unsupported.
disable()Drop this script's request. Fire-and-forget.
isSupportedbooleanWhether this device can track hands at all.
activebooleanWhether the provider is authorized and running.
enabledbooleanWhether this script currently requests hand tracking.
leftAnchorData | nullLeft hand, or null when it isn't tracked.
rightAnchorData | nullRight hand, or null when it isn't tracked.
anchorsArray<AnchorData>All currently tracked hands.

active vs enabled vs a hand being visible

These are three different questions – enabled is what your script asked for, active is whether tracking is actually running, and a left / right of null means that particular hand isn't in view right now. Poll active to notice permission being revoked or tracking being lost after a successful enable().

Face

Face data needs no opt-in – it is already flowing whenever the scene runs in a face tracking context, so there is nothing to enable.

javascript
// Attach to: On Render
var face = scene.tracking.face.current;
if (face) {
    console.log("Face at: " + face.worldTransform.position);
}

Face reference

MemberTypeDescription
isSupportedbooleanWhether the scene can deliver face tracking data.
activebooleanWhether a face is currently tracked.
currentAnchorData | nullThe current face anchor – blendshapes and eye transforms – or null.

Coordinate spaces

Joint and face positions are in world space. To use them against an object you created, convert into that object's local frame first – see Coordinate spaces.

The lower-level equivalent

scene.tracking is a convenience layer over scene.getAnchors(...), which stays available if you would rather filter the anchor list yourself:

javascript
// Attach to: On Render
var anchors = scene.getAnchors("hand");
for (var i = 0; i < anchors.length; i++) {
    if (anchors[i].chirality === "right") {
        console.log("Right hand at: " + anchors[i].worldTransform.position);
    }
}

The difference is lifecycle: only scene.tracking.hands can turn the hand-tracking provider on and off. getAnchors("hand") returns an empty list until something has enabled it.

  • Anchors – anchoring an object to a hand joint instead of reading joints yourself
  • Feature Detection – the full capability matrix
  • Examples – worked hand-tracking snippets