SkeletonConsumer
public class SkeletonConsumer : Singleton<SkeletonConsumer>, ISkeletonListener
Inherits: Singleton<SkeletonConsumer> — a MonoBehaviour base. Reach the live instance with SkeletonConsumer.Instance. Implements: ISkeletonListener (its OnSkeleton(...) callback is how incoming frames are delivered).
The heart of the SDK runtime. Drop one on a GameObject in the scene; it receives Skeleton messages from CVS, keeps a Person per tracked skeleton, instantiates an AR51Character prefab for each, and applies smoothing / scaling / IK / foot-contact every LateUpdate. Configure character prefabs and tuning in the Inspector; subscribe to its events to react to detection and person-lifecycle changes. Acts as a singleton.
The AR 51 Unity SDK works in meters (positions/lengths) and degrees (angles). All joint positions read through Person.Positions, HeadPosition, etc. are Unity world-space Vector3 in meters.
This page is reference (facts only). For the step-by-step connect → skeleton → drive a character walkthrough, see the How-to guide.
Properties
State & collections
The live set of tracked Persons, plus the singleton accessor. Iterate Persons to read joints each frame.
| Property | Type | Access | Description |
|---|---|---|---|
| Singleton | |||
Instance | SkeletonConsumer | static get | the singleton in the scene |
| Persons | |||
ActivePerson | Person | get | the local / nearest-to-camera person (headset/AR) |
Persons | IEnumerable<Person> | get | all currently-tracked persons |
PersonById | Dictionary<string, Person> | get | tracked persons keyed by Skeleton.Id |
ActiveSkeleton | GameObject | get / set | the active (local) skeleton GameObject |
| Active character | |||
DefaultCharacter | AR51Character | get | the default prefab applied when none is pinned |
ActiveCharacterPrefab | AR51Character | get | the prefab currently on the active person |
| Timing | |||
CVSTimeDifference | double | field | Time.time − CVS PyTime, seconds |
Character prefab configuration
Assign these in the Inspector. They select which AR51Character prefab is spawned for each tracked person — globally, or pinned per entity id / display name.
| Field | Type | Default | Description |
|---|---|---|---|
| Prefabs | |||
CharacterPrefabs | AR51Character[] | — | the drivable character prefabs to spawn |
CharacterPrefabByEntityId | CharacterMapping[] | — | pin a prefab by external EntityId |
CharacterPrefabByEntityDisplayName | CharacterMapping[] | — | pin a prefab by external display name |
CharacterPrefabOverrideBySkeletonId | Dictionary<string,string> | — | runtime override of prefab name by skeleton Id |
UseTitleAsPrefab | bool | false | use the server-requested prefab name (Skeleton.CharacterPrefab) |
Inspector tuning knobs
Many [Header]-grouped public fields tune visibility, smoothing, scaling, solvers, and bounds. Names/units are as shown in the Inspector; lengths are meters, angles degrees.
| Field | Type | Default | Description |
|---|---|---|---|
| Visibility | |||
MoveLimbs | bool | true | drive limb IK |
ShowModel | bool | true | render the character mesh |
ShowSkeleton | bool | true | draw the skeleton |
ShowControllers | bool | true | draw controller meshes |
ShowSkeletonGizmo | bool | false | draw the skeleton gizmo |
| Gating | |||
IgnoreUnidentified | bool | false | drop skeletons with no entity id |
IgnoreOutOfBounds | bool | false | drop skeletons outside ActiveBounds |
ActiveBounds | Bounds | — | bounds (meters) for accepting skeletons |
IgnoreLowConfidence | bool | true | drop low-confidence joints |
UpdateSkeleton | bool | true | apply incoming skeleton data each frame |
UpdateIk | bool | true | run IK each frame |
UpdateFingerRotations | bool | true | apply finger rotations |
| Rotation | |||
EnableClavicleRotation | bool | true | rotate clavicles |
EnableSpineRotation | bool | true | rotate spine |
CopyHeadRotationFromCamera | bool | false | drive head rotation from the main camera |
| Scaling | |||
AutoScaleMode | AutoScaleMode | NonUniform | how bone lengths rescale to the person |
HandAutoScaleMode | HandAutoScaleMode | Disabled | hand-scaling mode |
UniformScale | float | 1 | 0..2 world scale applied to all positions |
MinTorsoSpanInMeters / MaxTorsoSpanInMeters | float | 0.2 / 1 | torso-span clamp (meters) |
MinArmSpanInMeters / MaxArmSpanInMeters | float | 0.22 / 0.9 | arm-span clamp (meters) |
MinLegSpanInMeters / MaxLegSpanInMeters | float | 0.35 / 1.1 | leg-span clamp (meters) |
| Ground | |||
GroundY | float | 0 | ground plane height (meters) |
GroundPlane | Transform | — | transform defining the ground |
| Lifecycle | |||
DestroyInactivePersons | bool | true | destroy models for stale persons |
InactivePersonMaxSeconds | float | 1 | seconds without updates before removal |
MinSkeletonUpdateBeforeBirth | int | 5 | updates required before a Person is created |
| Solvers | |||
FootSolver | FootSolvers | — | Default / Plainer / Advanced |
FootAdvancedSolver | FootAdvancedSolvers | — | MoveAndRotateHips / MoveHipsOnly / MoveKnee |
HandSolver | HandSolvers | — | Default / Advanced |
FootContactParameters | FootContactParameters | — | foot-contact tuning |
| Web streaming | |||
StreamToWeb | bool | false | mirror frames to a web endpoint |
StreamToWebUri | string | — | the web stream URI |
⚠️ Many more [Header]-grouped public fields exist for smoothing, foot-contact, finger and scale tuning — they are Inspector knobs with the names/units shown above.
Method summary
Static
| Method | Returns | |
|---|---|---|
Instance | SkeletonConsumer | static (property) |
Instance — lookup
| Method | Returns | |
|---|---|---|
TryGetPerson | bool | |
GetPerson | Person | |
GetPersonId | string | |
GetDevicePerson / GetDeviceCharacter | Person / AR51Character | |
TryGetPrefabByName | bool |
Instance — characters
| Method | Returns | |
|---|---|---|
SetActiveCharacter | bool | |
OverrideCharacter | void | overloads |
NextCharacter | void | |
SetCharacter | bool | deprecated |
ResetCharacter / ResetCharacters | void |
→ Full descriptions in Method details below.
Events
EventHandler / EventHandler<T>. Subscribe with += in C# (e.g. on Start), unsubscribe with -= on teardown.
| Event | Args | Fires when |
|---|---|---|
OnActivePersonChanged | EventHandler | the active Person changed |
OnActiveSkeletonChanged | EventHandler | the active (local) skeleton GameObject changed |
OnCvsSkeletonReceived | SkeletonEventArgs | a raw skeleton arrived from CVS (before queue/playback gating) |
OnSkeletonReceived | SkeletonEventArgs | a skeleton is about to be processed this frame |
OnPersonCreated | PersonEventArgs | a new Person/character was instantiated |
OnPersonDeleting | PersonEventArgs | a Person is about to be removed (model still alive) |
OnPersonDeleted | PersonEventArgs | a Person has been removed (model destroyed) |
A Person is created after MinSkeletonUpdateBeforeBirth updates (default 5) and removed after InactivePersonMaxSeconds (default 1) without updates (when DestroyInactivePersons).
// Spawn a log line per new character:
SkeletonConsumer.Instance.OnPersonCreated += (s, e) =>
Debug.Log($"Spawned character for {e.Person.Id}");
Method details
Instance
public static SkeletonConsumer Instance { get; }
The singleton consumer in the scene — the usual way to reach it from anywhere.
var consumer = SkeletonConsumer.Instance;
foreach (var person in consumer.Persons)
Debug.Log(person.Positions[Joints.RWrist]); // right wrist in meters, world space
TryGetPerson
public bool TryGetPerson(string personId, out Person person);
Look up a tracked person by id.
true if a person with that id is trackedif (SkeletonConsumer.Instance.TryGetPerson(personId, out var person))
Debug.Log(person.HeadPosition); // meters, world space
GetPerson
public Person GetPerson(Transform t);
public string GetPersonId(Transform t);
The person (or its id) owning the character under a scene Transform — handy from collision/raycast hits on a character mesh.
void OnTriggerEnter(Collider other)
{
var person = SkeletonConsumer.Instance.GetPerson(other.transform);
if (person != null)
Debug.Log($"Hit character of person {person.Id}");
}
GetDevicePerson
public Person GetDevicePerson(string deviceId);
public AR51Character GetDeviceCharacter(string deviceId);
Resolve the person / character associated with a given originating device id (see Skeleton.DeviceId).
TryGetPrefabByName
public bool TryGetPrefabByName(string prefabName, out AR51Character prefab);
Look up an AR51Character prefab in CharacterPrefabs by name.
CharacterPrefabstrue if a prefab with that name existsSetActiveCharacter
public bool SetActiveCharacter(string characterPrefabName);
Change the active person's prefab to a named entry in CharacterPrefabs.
true if the swap succeeded (prefab found)// Swap the active person's mesh to a named character prefab at runtime
if (!SkeletonConsumer.Instance.SetActiveCharacter("RobotCharacter"))
Debug.LogWarning("Prefab not found in CharacterPrefabs");
OverrideCharacter
public void OverrideCharacter(string personId, string overridePrefabName);
public void OverrideCharacter(Person person, string overridePrefabName);
Pin a specific prefab to one person (overrides auto-assignment). Use for deterministic casting; otherwise rely on AutoScaleMode / CharacterPrefabByEntityId mapping.
// Always cast a specific tracked person as a named prefab
SkeletonConsumer.Instance.OverrideCharacter(personId, "GuestAvatar");
NextCharacter
public void NextCharacter(int indexIncrease = 1);
Cycle the default prefab forward through CharacterPrefabs by indexIncrease entries.
1)SetCharacter
public bool SetCharacter(string characterPrefabName);
⚠️ Deprecated. Sets the default prefab for all persons. Prefer SetActiveCharacter (active person) or OverrideCharacter (a specific person).
true if the prefab was foundResetCharacters
public void ResetCharacter(string personId); // destroy that person's model
public void ResetCharacters(); // destroy all spawned models, clear assignment
Destroy spawned character models and clear assignment — one person, or all of them.
// Drop everything and let characters respawn from the next frames
SkeletonConsumer.Instance.ResetCharacters();
Nested enums
public enum FootSolvers { Default, Plainer, Advanced }
public enum FootAdvancedSolvers { MoveAndRotateHips, MoveHipsOnly, MoveKnee }
public enum HandSolvers { Default, Advanced }
Solver selectors for the FootSolver / FootAdvancedSolver / HandSolver Inspector fields above.
Solve(...) / SolveAll() / OnSkeleton(...) (the ISkeletonListener callback) / NormlizeSkeletonOrigin() [sic] / GetNestedProperties() / GetPersonCollider(...) / GetGroundY() / SetHandsAdapterOverride(...) are public but are driven internally by LateUpdate or by playback — you don't normally call them. The IK/solver math behind the solve is internal and not part of the documented surface.
See also
Person— the tracked-person wrapper returned by the lookupsAR51Character— the mocap-driven mesh this consumer spawns and drivesSkeleton— the per-frame payload the consumer receivesJoints— the joint-index map forPerson.PositionsServiceManager— the connection entry-point that must be connected firstCharacterMapping— per-entity prefab mapping- Class index — all Unity SDK types
- How-to: connect → drive a character