# Skeleton

<Badge tone="type">class · sealed</Badge> <Badge>immutable</Badge> <Badge>thread-safe</Badge>

```csharp
namespace AR51.Net;

public sealed class Skeleton
```

One tracked person at one moment: the 3D position and confidence of each body joint, the hands when a hand-tracking headset reports them, plus identity and timing.

Positions are in meters, in the AR 51 world: left-handed, X right, Y up, Z forward (the same axes as Unity). A joint the cameras could not see is reported at (0, 0, 0) with confidence 0; use [`TryGetPosition`](#trygetposition) to tell it apart. Instances are immutable and safe to share across threads.

:::note[Units]
Positions are in **meters**, in the AR 51 world: **left-handed, X right, Y up, Z forward** (the same axes as Unity). See [Data conventions](/docs/csharp-api/conventions/).
:::

:::tip[How-to]
This page is **reference** (facts only). For a walkthrough with a complete sample, see the [Skeletons guide](/docs/csharp-api/skeletons/).
:::

<Example>

```csharp
// Hands are present only when the person wears a hand-tracking headset.
if (skeleton.LeftHand is { } hand)
    Console.WriteLine($"left index fingertip at {hand.GetPosition(HandJoint.IndexTip)} m");
```

</Example>

## Properties

<div className="apiPropTable apiTable">

| Property | Type | Access | Description |
|---|---|---|---|
| `Id` | `string` | `get` | Tracking id of this person, stable while the person stays tracked. |
| `EntityId` | `string` | `get` | Identity assigned to this person at registration, stable across sessions. Empty when the person is not registered. |
| `EntityDisplayName` | `string` | `get` | Name of the registered person, for display. Empty when the person is not registered. |
| `DeviceId` | `string` | `get` | Id of the headset worn by this person, the same as [`DeviceInfo.Id`](/docs/sdk-api/csharp-api/classes/ideviceclient/#deviceinfo). Empty when no headset is associated with this person. |
| `Positions` | [`IReadOnlyList<Vector3>`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlylist-1) | `get` | Joint positions in meters (left-handed: X right, Y up, Z forward), indexed by [`Joint`](#joint). |
| `Confidences` | [`IReadOnlyList<float>`](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlylist-1) | `get` | How sure the cameras are of each joint, from 0 (not seen) to 1, indexed by [`Joint`](#joint). Empty when the server does not report confidence. |
| `LeftHand` | [`HandPose?`](/docs/sdk-api/csharp-api/classes/handpose/) | `get` | The left hand's joints, or `null` unless this person wears a headset with hand tracking. Hands come from the headset, not from the cameras. |
| `RightHand` | [`HandPose?`](/docs/sdk-api/csharp-api/classes/handpose/) | `get` | The right hand's joints, or `null` unless this person wears a headset with hand tracking. Hands come from the headset, not from the cameras. |
| `CaptureTime` | [`DateTimeOffset`](https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset) | `get` | When the cameras captured this skeleton (server clock, UTC). The Unix epoch (1970-01-01) when the server did not send a valid time. |
| `ReceivedTime` | [`DateTimeOffset`](https://learn.microsoft.com/en-us/dotnet/api/system.datetimeoffset) | `get` | When this client received it (local clock). `CaptureTime` uses the server's clock and this uses yours, so their difference is the true delay only when both clocks are synchronized (for example with NTP). |

</div>

## Method summary

<div className="apiTable">

| Method | Returns | |
|---|---|---|
| [`GetPosition`](#getposition) | [`Vector3`](https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector3) |  |
| [`GetConfidence`](#getconfidence) | `float` |  |
| [`TryGetPosition`](#trygetposition) | `bool` |  |

</div>

→ Full descriptions in [Method details](#method-details) below.

## Method details

### GetPosition

<ApiBody kind="method">

```csharp
public Vector3 GetPosition(Joint joint);
```

Gets the position of a joint, in meters.

<Params>
<Param name="joint" type="Joint" typeHref="#joint">The joint.</Param>
</Params>

<Returns type="Vector3" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector3">The position, or (0, 0, 0) when the joint was not detected.</Returns>

</ApiBody>

### GetConfidence

<ApiBody kind="method">

```csharp
public float GetConfidence(Joint joint);
```

Gets how sure the cameras are of a joint.

<Params>
<Param name="joint" type="Joint" typeHref="#joint">The joint.</Param>
</Params>

<Returns type="float">From 0 (not seen) to 1. 0 when the server does not report confidence.</Returns>

</ApiBody>

### TryGetPosition

<ApiBody kind="method">

```csharp
public bool TryGetPosition(Joint joint, out Vector3 position);
```

Gets the position of a joint if it was detected.

<Params>
<Param name="joint" type="Joint" typeHref="#joint">The joint.</Param>
<Param name="position" type="out Vector3" typeHref="https://learn.microsoft.com/en-us/dotnet/api/system.numerics.vector3">The position in meters, or (0, 0, 0) when not detected.</Param>
</Params>

<Returns type="bool">`true` when the joint was detected: its confidence is above 0 (or, when the server does not report confidence, its position is not (0, 0, 0)).</Returns>

<Example>

```csharp
if (skeleton.TryGetPosition(Joint.RightWrist, out Vector3 wrist))
    Console.WriteLine($"right wrist at {wrist} m (confidence {skeleton.GetConfidence(Joint.RightWrist):F2})");
else
    Console.WriteLine("right wrist not seen");
```

</Example>

</ApiBody>

## Related types

Small types used by this class, documented here.

### Joint

<Badge tone="type">enum</Badge>

```csharp
public enum Joint
```

Body joints reported in a `Skeleton`. The value is the index into `Skeleton.Positions`.

:::note
Left and right are the person's own left and right.
:::

<div className="apiTable">

| Value | Meaning |
|---|---|
| `Nose = 0` | Tip of the nose. |
| `Neck = 1` | Base of the neck, between the shoulders. |
| `RightShoulder = 2` | Right shoulder. |
| `RightElbow = 3` | Right elbow. |
| `RightWrist = 4` | Right wrist. |
| `LeftShoulder = 5` | Left shoulder. |
| `LeftElbow = 6` | Left elbow. |
| `LeftWrist = 7` | Left wrist. |
| `MidHip = 8` | Center of the pelvis, between the hips. |
| `RightHip = 9` | Right hip. |
| `RightKnee = 10` | Right knee. |
| `RightAnkle = 11` | Right ankle. |
| `LeftHip = 12` | Left hip. |
| `LeftKnee = 13` | Left knee. |
| `LeftAnkle = 14` | Left ankle. |
| `RightEye = 15` | Right eye. |
| `LeftEye = 16` | Left eye. |
| `RightEar = 17` | Right ear. |
| `LeftEar = 18` | Left ear. |
| `LeftBigToe = 19` | Left big toe. |
| `LeftSmallToe = 20` | Left small toe. |
| `LeftHeel = 21` | Left heel. |
| `RightBigToe = 22` | Right big toe. |
| `RightSmallToe = 23` | Right small toe. |
| `RightHeel = 24` | Right heel. |

</div>

## See also

- [Skeletons guide](/docs/csharp-api/skeletons/) — walkthrough with a complete, compiled sample
- [Class index](/docs/sdk-api/csharp-api/classes/) — every AR51.Net type
- [Data conventions, threading and errors](/docs/csharp-api/conventions/)
