# USkeletonConsumer

<Badge tone="type">UCLASS · UActorComponent</Badge> <Badge>BlueprintSpawnableComponent</Badge> <Badge>singleton</Badge>

```cpp
UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class AR51SDK_API USkeletonConsumer : public UActorComponent, public ISingleton<USkeletonConsumer>
```

**Inherits:** [`UActorComponent`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/UActorComponent) *(Unreal Engine)* · [`ISingleton<USkeletonConsumer>`](/docs/sdk-api/unreal-api/utilities-platform#isingletont)

The central entry point of the SDK. Drop one on an actor in the level; it connects to the AR 51 skeleton service, spawns/destroys a character per tracked person, drives each one every frame, and fires Blueprint events on person-lifecycle changes. Acts as a singleton.

:::tip[How-to]
This page is **reference** (facts only). For the step-by-step *connect → drive a character* walkthrough, see the [How-to guide](/docs/sdk-api/unreal-api/skeletons-and-characters#walkthrough).
:::

## Properties

All `EditAnywhere, BlueprintReadWrite`.

<div className="apiPropTable">

| Property | Type | Default | Description |
|---|---|---|---|
| **General** | | | |
| `ShowModel` | `bool` | `true` | render the character mesh |
| `ShowSkeleton` | `bool` | `false` | draw the skeleton gizmo |
| `ShowControllers` | `bool` | `false` | draw controller meshes |
| `MaxSkeletonCount` | `int32` | `0` | cap on tracked skeletons (0 = unlimited) |
| `CharacterBlueprints` | `TArray<TSubclassOf<AActor>>` | — | candidate [`AAR51CharacterActor`](/docs/sdk-api/unreal-api/skeletons-and-characters#aar51characteractor) BPs to spawn |
| `UpdateSkeleton` | `bool` | `true` | apply incoming skeleton data each frame |
| `IsApplyHeadRotationWristPositionAndFingerRotations` | `bool` | `true` | fuse device head rotation + wrist/finger poses |
| `SkeletonPredictionSettings` | [`FPredictionSettings`](/docs/sdk-api/unreal-api/skeletons-and-characters#prediction) | — | smoothing / extrapolation model |
| `HandTrackingFallbackSmoothingFactor` | `float` | `0.99` | smoothing when falling back to hand tracking |
| `SolverParameters` | [`FSolverParams`](/docs/sdk-api/unreal-api/skeletons-and-characters#ik-solver--auto-scale-settings) | — | IK / auto-scale settings |
| **Visualization** | | | |
| `ControllerMesh` | [`UStaticMesh*`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/UStaticMesh) | — | mesh drawn for controllers |
| `ControllerSize` | `float` | `0.1` | controller mesh scale |
| `SkeletonMesh` | [`UStaticMesh*`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/UStaticMesh) | — | mesh drawn per skeleton joint |
| `SkeletonSize` | `float` | `0.025` | joint mesh scale |
| **Debug** | | | |
| `bShowDebugBounds` | `bool` | `false` | draw person bounds |
| `DebugBoxColor` | [`FColor`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/FColor) | `Green` | bounds box color |
| `DebugSphereColor` | [`FColor`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Core/FColor) | `Red` | bounds sphere color |
| **Character instantiation** | | | |
| `ActivePersonCameraSpace` | `EActivePersonCameraSpace` | `ComponentSpace` | space used to pick the active person |
| `MaxCameraDistanceThreshold` | `float` | `20` | ⚠️ max distance (m?) for active-person selection |
| `DestroyInactivePersons` | `bool` | `true` | destroy models for stale persons |
| `InactivePersonMaxSeconds` | `float` | `1.0` | seconds without updates before removal |
| `HidePersonMaxSeconds` | `float` | `0.2` | seconds without updates before hiding |
| **Character mapping** | | | |
| `AutoCharacterAssignmentMode` | `EAutoCharacterAssignmentMode` | `Default` | how characters are auto-assigned (Default / Cycle / Random) |
| `PersonIdToCharacterBPMap` | `TMap<FString,FString>` | — | pin character BP by mocap `PersonId` |
| `EntityIdToCharacterBPMap` | `TMap<FString,FString>` | — | pin by external `EntityId` |
| `EntityDisplayNameToCharacterBPMap` | `TMap<FString,FString>` | — | pin by external display name |
| **Recording** | | | |
| `IsRecording` | `bool` | `false` | record incoming frames to `InOutRecordingFile` |
| `IsPlayback` | `bool` | `false` | replay from `InOutRecordingFile` instead of the live stream |
| `IsPlaybackLoop` | `bool` | `false` | loop playback |
| `InOutRecordingFile` | `FString` | `"/Recordings/file.txt"` | record/playback file path |

</div>

## Method summary

**Static**

| Method | Returns | |
|---|---|---|
| [`GetSkeletonConsumerSingleton`](#getskeletonconsumersingleton) | `USkeletonConsumer*` | <Badge tone="accent">BlueprintCallable</Badge> |

**Instance**

| Method | Returns | |
|---|---|---|
| [`Connect`](#connect) | `void` | <Badge tone="accent">BlueprintCallable</Badge> |
| [`Disconnect`](#disconnect) | `void` | <Badge tone="accent">BlueprintCallable</Badge> |
| [`IsConnected`](#isconnected) | `bool` | <Badge tone="accent">BlueprintCallable</Badge> |
| [`GetEndpoint`](#getendpoint) | `FString` | <Badge tone="accent">BlueprintCallable</Badge> |
| [`GetActivePerson`](#getactiveperson) | [`TScriptInterface<IPersonBase>`](/docs/sdk-api/unreal-api/skeletons-and-characters#ipersonbase) | <Badge tone="accent">BlueprintCallable</Badge> |
| [`GetPersonByPersonId`](#getpersonbypersonid) | [`TScriptInterface<IPersonBase>`](/docs/sdk-api/unreal-api/skeletons-and-characters#ipersonbase) | <Badge tone="accent">BlueprintCallable</Badge> |
| [`GetPersonByEntityId` / `…DisplayName`](#getpersonbyentityid) | [`TScriptInterface<IPersonBase>`](/docs/sdk-api/unreal-api/skeletons-and-characters#ipersonbase) | <Badge tone="accent">BlueprintCallable</Badge> |
| [`GetPersonById`](#getpersonbyid) | `TMap<FString, …>` | <Badge tone="accent">BlueprintCallable</Badge> |
| [`GetCharacters`](#getcharacters) | [`TArray<UAR51Character*>`](/docs/sdk-api/unreal-api/skeletons-and-characters#uar51character) | <Badge tone="accent">BlueprintCallable</Badge> |
| [`SetActiveCharacter`](#setactivecharacter) | `bool` | <Badge tone="accent">BlueprintCallable</Badge> |
| [`FindCharacterIndexByName`](#findcharacterindexbyname) | `int32` | <Badge tone="accent">BlueprintCallable</Badge> |
| [`SetCharacterBy…`](#setcharacterby) | `void` | <Badge tone="accent">BlueprintCallable</Badge> · overloads |
| [`ResetCharacter` / `…Characters`](#resetcharacters) | `void` | <Badge tone="accent">BlueprintCallable</Badge> |
| [`GetMainCameraComponent` / `SetMainCameraComponent`](#main-camera) | [`UCameraComponent*`](https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/UCameraComponent) | <Badge tone="accent">BlueprintCallable</Badge> |
| [`GetLastCaptureTime`](#getlastcapturetime) | `double` | <Badge tone="accent">BlueprintCallable</Badge> |

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

## Events

`UPROPERTY(BlueprintAssignable)`, dynamic multicast. Bind in C++ with `AddDynamic`, or as a red event node in Blueprint.

| Event | Signature | Fires when |
|---|---|---|
| `OnPersonDetected` | `FOnPersonDetected(FString PersonId)` | a person is detected for the first time (character spawned) |
| `OnPersonUpdated` | `FOnPersonUpdated(FString PersonId)` | a person's skeleton data is updated (per-frame-ish) |
| `OnPersonTrackingLost` | `FOnPersonTrackingLost(FString PersonId)` | tracking for a person is lost |
| `OnPersonTrackingRecovered` | `FOnPersonTrackingRecovered(FString PersonId)` | tracking recovers after being lost |
| `OnPersonDestroyed` | `FOnPersonDestroyed(FString PersonId)` | a person is destroyed (lost tracking too long) |
| `OnActivePersonChanged` | `FOnActivePersonChanged(FString PersonId)` | the headset-associated active person changes — **`PersonId` is `""`** when none |

A `Person` is created after `MinSkeletonUpdateBeforeBirth` updates (default 5) and removed after `InactivePersonMaxSeconds` (default 1) without updates.

## Method details

### GetSkeletonConsumerSingleton

<ApiBody kind="method" tags="static, BlueprintCallable">

```cpp
static USkeletonConsumer* GetSkeletonConsumerSingleton();
```

The live consumer instance — the usual way to reach it from anywhere. (Deprecated alias: `GetSingleton()`.)

<Returns type="USkeletonConsumer*">the singleton, or `nullptr` if none is in the level</Returns>

</ApiBody>

### Connect

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
void Connect(const FString& endpoint);
```

Connects to the AR 51 skeleton service and starts the background consume loop; characters begin appearing as people are detected. Call once (e.g. on `BeginPlay`).

<Params>
<Param name="endpoint" type="FString">the skeleton service address as `"IP:Port"`</Param>
</Params>

<Example inferred>

```cpp
void AMyManager::BeginPlay()
{
    Super::BeginPlay();
    auto* Consumer = USkeletonConsumer::GetSkeletonConsumerSingleton();
    Consumer->OnPersonDetected.AddDynamic(this, &AMyManager::HandlePersonDetected);
    Consumer->Connect(TEXT("127.0.0.1:50052"));   // ⚠️ exact port depends on your OMS/skeleton service
}
```

</Example>

</ApiBody>

### Disconnect

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
void Disconnect();
```

Tears down the connection and stops consuming frames. Call on `EndPlay`.

</ApiBody>

### IsConnected

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
bool IsConnected() const;
```

<Returns type="bool">`true` while the stream is live</Returns>

</ApiBody>

### GetEndpoint

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
FString GetEndpoint() const;
```

<Returns type="FString">the current endpoint as `"IP:Port"`</Returns>

</ApiBody>

### GetActivePerson

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
TScriptInterface<IPersonBase> GetActivePerson();
```

The person currently associated with the headset/camera (nearest/local) — the one you usually drive first-person logic or UI from.

<Returns type="TScriptInterface<IPersonBase>" typeHref="/docs/sdk-api/unreal-api/skeletons-and-characters#ipersonbase">the active person, or null if none is associated with the headset</Returns>

<Example inferred>

```cpp
if (UObject* P = Consumer->GetActivePerson().GetObject())
{
    UAR51Character* Char = IPersonBase::Execute_GetCharacter(P);
    const FVector Head = Char->GetHeadPosition();   // UE cm
}
```

</Example>

</ApiBody>

### GetPersonByPersonId

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
TScriptInterface<IPersonBase> GetPersonByPersonId(const FString& PersonId);
```

Look up a tracked person by the mocap system's per-person id.

<Params>
<Param name="PersonId" type="FString">the mocap `PersonId` (see Id semantics on [`IPersonBase`](/docs/sdk-api/unreal-api/skeletons-and-characters#ipersonbase))</Param>
</Params>

<Returns type="TScriptInterface<IPersonBase>" typeHref="/docs/sdk-api/unreal-api/skeletons-and-characters#ipersonbase">the person, or null if not tracked</Returns>

<Example inferred>

```cpp
if (UObject* P = Consumer->GetPersonByPersonId(PersonId).GetObject())
{
    if (IPersonBase::Execute_IsTracked(P))
        UE_LOG(LogTemp, Log, TEXT("Tracking %s"), *IPersonBase::Execute_GetId(P));
}
```

</Example>

</ApiBody>

### GetPersonByEntityId

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
TScriptInterface<IPersonBase> GetPersonByEntityId(const FString& EntityId);
TScriptInterface<IPersonBase> GetPersonByEntityDisplayName(const FString& Name);
```

Look up a person by the **external-system** entity id or display name (as opposed to the mocap `PersonId`).

<Returns type="TScriptInterface<IPersonBase>" typeHref="/docs/sdk-api/unreal-api/skeletons-and-characters#ipersonbase">the matching person, or null</Returns>

</ApiBody>

### GetPersonById

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
const TMap<FString, TScriptInterface<IPersonBase>>& GetPersonById();
```

<Returns type="TMap<FString, …IPersonBase>" typeHref="/docs/sdk-api/unreal-api/skeletons-and-characters#ipersonbase">all currently-tracked persons, keyed by `PersonId`</Returns>

</ApiBody>

### GetCharacters

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
TArray<UAR51Character*> GetCharacters() const;
```

<Returns type="TArray<UAR51Character*>" typeHref="/docs/sdk-api/unreal-api/skeletons-and-characters#uar51character">every tracked character component</Returns>

<Example inferred>

```cpp
for (UAR51Character* Char : Consumer->GetCharacters())
{
    const FVector L = Char->GetLeftWristPosition();   // UE cm
    const FVector R = Char->GetRightWristPosition();
}
```

</Example>

</ApiBody>

### SetActiveCharacter

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
bool SetActiveCharacter(const FString& characterBPName);
```

Swap the active person's character to a named Blueprint from `CharacterBlueprints`.

<Params>
<Param name="characterBPName" type="FString">name of a Blueprint in `CharacterBlueprints`</Param>
</Params>

<Returns type="bool">`true` if the swap succeeded</Returns>

<Example inferred>

```cpp
// Swap the active person's mesh to a named character BP at runtime
if (!Consumer->SetActiveCharacter(TEXT("BP_RobotCharacter")))
    UE_LOG(LogTemp, Warning, TEXT("Character BP not found in CharacterBlueprints"));
```

</Example>

</ApiBody>

### FindCharacterIndexByName

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
int32 FindCharacterIndexByName(const FString& CharacterBPName);
```

<Params>
<Param name="CharacterBPName" type="FString">Blueprint name to find</Param>
</Params>

<Returns type="int32">index into `CharacterBlueprints`, or `-1` if not found</Returns>

</ApiBody>

### SetCharacterBy

<ApiBody kind="method" tags="BlueprintCallable, overloads">

```cpp
void SetCharacterByPersonId(const FString& PersonId, const FString& CharacterBPName);
void SetCharacterIndexByPersonId(const FString& PersonId, int32 Index);
void SetCharacterByEntityId(const FString& EntityId, const FString& CharacterBPName);
void SetCharacterIndexByEntityId(const FString& EntityId, int32 Index);
void SetCharacterByEntityDisplayName(const FString& Name, const FString& CharacterBPName);
void SetCharacterIndexByEntityDisplayName(const FString& Name, int32 Index);
```

Pin a specific character Blueprint (by name or index) to a person, keyed by `PersonId`, `EntityId`, or display name. Use these for deterministic casting; otherwise rely on `AutoCharacterAssignmentMode`.

</ApiBody>

### ResetCharacters

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
void ResetCharacter(const FString& PersonId);   // remove that person + destroy its model
void ResetActiveCharacter();                     // same, for the active person
void ResetCharacters();                          // destroy all spawned models, clear tracking
```

</ApiBody>

### Main camera

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
UCameraComponent* GetMainCameraComponent() const;
void              SetMainCameraComponent(UCameraComponent*);
```

The camera used for head tracking / active-person selection. Override auto-detection with the setter when your rig has more than one camera.

<Returns type="UCameraComponent*" typeHref="https://dev.epicgames.com/documentation/en-us/unreal-engine/API/Runtime/Engine/UCameraComponent">the camera in use</Returns>

</ApiBody>

### GetLastCaptureTime

<ApiBody kind="method" tags="BlueprintCallable">

```cpp
double GetLastCaptureTime() const;
```

<Returns type="double">server-side capture timestamp of the last frame — **seconds since Unix epoch (1970 UTC)**</Returns>

</ApiBody>

## See also

- [`UAR51Character`](/docs/sdk-api/unreal-api/skeletons-and-characters#uar51character) — the mocap-driven mesh this consumer spawns and drives
- [`AAR51CharacterActor`](/docs/sdk-api/unreal-api/skeletons-and-characters#aar51characteractor) — the character actor listed in `CharacterBlueprints`
- [`IPersonBase`](/docs/sdk-api/unreal-api/skeletons-and-characters#ipersonbase) — the tracked-person interface returned by the lookups
- [Class index](/docs/sdk-api/unreal-api/classes) — all Unreal SDK types
- How-to: [connect → drive a character](/docs/sdk-api/unreal-api/skeletons-and-characters#walkthrough)
