# SkeletonData

<Badge tone="type">class (plain C++)</Badge> <Badge>C++ only</Badge>

```cpp
class AR51SDK_API SkeletonData
```

A plain C++ class — **not** a `USTRUCT`, not Blueprint-exposed. Holds one frame of skeleton joint data: a parallel pair of arrays (`Positions` + `Confidence`) indexed by the [`Keypoints`](#keypoints) scheme, plus indexer access and a set of derived-rotation helpers that compute body/limb orientations from triangles of keypoints. This is the raw frame the SDK receives and feeds to the solver; [`USkeletonConsumer`](/docs/sdk-api/unreal-api/classes/skeletonconsumer) drives characters from it each frame.

:::caution[Units]
Unreal works in **cm / degrees**. `Positions` are vectors indexed by `Keypoints`; treat them as **cm after SDK scaling**. ⚠️ The space/units of this raw container are unverified — the IK pipeline operates in UE world-space cm, but the container may carry meters *before* scaling. Treat the **index → joint mapping** as authoritative; treat units as cm-after-scaling unless you confirm otherwise.
:::

## Fields

<div className="apiPropTable">

| Field | Type | Description |
|---|---|---|
| `Positions` | [`TArray<FVector>`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/Containers/TArray) | joint positions, indexed by [`Keypoints`](#keypoints) (or raw `int`). ⚠️ space/units unverified — see caution above (treat as cm after scaling) |
| `Confidence` | [`TArray<float>`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/Containers/TArray) | per-joint confidence, parallel to `Positions`, roughly `0–1`. Low-confidence joints are de-weighted or ignored by the solver |

</div>

The two arrays are parallel: `Confidence[i]` is the confidence for `Positions[i]`, where `i` is a `Keypoints` index.

## Constructors

<ApiBody kind="method" tags="C++ only">

```cpp
SkeletonData(const TArray<FVector>& positions, const TArray<float>& confidence);
SkeletonData(int capacity);
```

Construct from an existing positions+confidence pair, or pre-size an empty frame to `capacity` joints.

<Params>
<Param name="positions" type="TArray<FVector>">joint positions, indexed by `Keypoints`</Param>
<Param name="confidence" type="TArray<float>">per-joint confidence, parallel to `positions`</Param>
<Param name="capacity" type="int">number of joints to reserve for an empty frame</Param>
</Params>

</ApiBody>

## Indexer

<ApiBody kind="method" tags="C++ only">

```cpp
      FVector& operator[](Keypoints joint);
const FVector& operator[](Keypoints joint) const;
      FVector& operator[](int index);
const FVector& operator[](int index) const;
```

Read or write a joint position by `Keypoints` value or by raw integer index (const and mutable overloads). Prefer the `Keypoints` overload — it is self-documenting and immune to index drift for the [auto-numbered joints](#keypoints).

<Example inferred>

```cpp
// Read the head/wrist positions from a frame (UE cm, after scaling)
const FVector Nose   = Frame[Keypoints::Nose];
const FVector LWrist = Frame[Keypoints::LWrist];

if (Frame.Confidence[(int)Keypoints::LWrist] > 0.5f)
{
    // ...use LWrist
}
```

</Example>

</ApiBody>

## Derived-rotation helpers

<ApiBody kind="method" tags="C++ only">

```cpp
FQuat GetHipRotation();
FQuat GetHipRotation(FVector& forward);
FQuat GetHeadRotation();
FQuat GetSpineRotation();
FQuat GetSpineRotation(FVector& forward);
FQuat GetUpperChestRotation();
FQuat GetUpperChestRotation(FVector& forward);

FQuat GetLShoulderRotation();   FQuat GetLShoulderRotation(FVector& forward);
FQuat GetRShoulderRotation();   FQuat GetRShoulderRotation(FVector& forward);
FQuat GetLHipRotation();        FQuat GetLHipRotation(FVector& forward);
FQuat GetRHipRotation();        FQuat GetRHipRotation(FVector& forward);

FQuat GetLimbRotation(Keypoints top, Keypoints mid, Keypoints bottom, FVector& forward);

FQuat GetRotation(Keypoints rBottom, Keypoints lBottom, Keypoints rTop, Keypoints lTop, FVector& forward);
static FQuat GetRotation(FVector rightPoint, FVector leftPoint, FVector topPoint, FVector& forward);
```

Compute joint/body orientations from triangles of keypoints in this frame. Each has a `(FVector& forward)` overload that also returns the body/limb forward vector as an out-param. `GetLimbRotation` is the general form — pass the three keypoints that define a limb; `GetRotation` builds an orientation from a left/right/top point set (the `static` overload takes raw `FVector`s instead of keypoint indices).

The internals are a black box, but the methods are public and useful when a game wants to read body or limb orientation directly from a frame rather than from a driven character.

<Returns type="FQuat">the computed joint/body orientation</Returns>

</ApiBody>

---

## Keypoints

<Badge tone="type">enum class (plain C++)</Badge> <Badge>C++ only</Badge>

```cpp
enum class Keypoints : int
```

A plain C++ `enum class`, int-backed — **not** a `UENUM`, not Blueprint-exposed. The canonical joint-index scheme: the joint/bone naming that the whole data model uses to index [`SkeletonData::Positions`](#fields) and `Confidence`.

The **body** joints (OpenPose-style) have **fixed** integer indices — safe to rely on:

```cpp
enum class Keypoints : int
{
    Unknown   = -1,
    Nose      = 0,
    Neck      = 1,
    RShoulder = 2,
    RElbow    = 3,
    RWrist    = 4,
    LShoulder = 5,
    LElbow    = 6,
    LWrist    = 7,
    MidHip    = 8,
    RHip      = 9,
    RKnee     = 10,
    RAnkle    = 11,
    LHip      = 12,
    LKnee     = 13,
    LAnkle    = 14,
    REye      = 15,
    LEye      = 16,
    REar      = 17,
    LEar      = 18,
    LBigToe   = 19,
    LSmallToe = 20,
    LHeel     = 21,
    RBigToe   = 22,
    RSmallToe = 23,
    RHeel     = 24,
    // ...auto-numbered hand + extra joints follow (see below)
};
```

After `RHeel`, the enum continues with **auto-numbered** entries (the compiler assigns sequential values; order-dependent):

- **Right-hand fingers:** `RightWrist`, then `R{Thumb,Index,Middle,Ring,Pinky}Finger0..3` — 4 joints per finger, `0` = base → `3` = tip.
- **Left-hand fingers:** `LeftWrist`, then `L{Thumb,Index,Middle,Ring,Pinky}Finger0..3` — same layout.
- **Extra body joints:** `UpperChest`, `Spine`, `RClavicle`, `LClavicle`, `RForearmeTwist0`, `LForearmeTwist0`, `RForearmeTwist1`, `LForearmeTwist1`.
- **Sentinels:** `Background`, then `Last` (the count sentinel — equals the number of keypoints).

:::caution
**Do not hardcode the integer values of the hand/extra joints.** Only the fixed body block `Nose=0 … RHeel=24` is guaranteed stable. The finger, twist, clavicle, chest/spine, and sentinel values are auto-numbered and will shift if the enum changes. Always reference them by name (`Keypoints::RIndexFinger2`), never by literal index.
:::

### KeypointsHelper::AllKeypoints

<ApiBody kind="method" tags="C++ only, static">

```cpp
static const TArray<Keypoints>& KeypointsHelper::AllKeypoints();
```

Every enumerated keypoint, in order — iterate this instead of writing your own range, so hand/extra joints are included without hardcoding bounds.

<Returns type="const TArray<Keypoints>&">all enumerated keypoints</Returns>

<Example inferred>

```cpp
for (Keypoints K : KeypointsHelper::AllKeypoints())
{
    const FVector P = Frame[K];   // UE cm, after scaling
    // ...
}
```

</Example>

</ApiBody>

## See also

- [`USkeletonConsumer`](/docs/sdk-api/unreal-api/classes/skeletonconsumer) — receives these frames and drives characters from them
- [`UAR51Character`](/docs/sdk-api/unreal-api/skeletons-and-characters#uar51character) — the mocap-driven mesh whose `Solve(positions, confidence)` consumes `Keypoints`-indexed data
- [`BoneTransform`](/docs/sdk-api/unreal-api/classes/bonetransform) — per-bone handle the solver hands out
- [Class index](/docs/sdk-api/unreal-api/classes) — all Unreal SDK types
