Animator Parameters
TL;DR: AvatarDefinitions.CoreParameters is the source of truth for the 22 names the runtime treats as “core” (read-only via SetParameter). Twelve of those are network-replicated through AvatarCoreSyncData; the other ten are computed locally on each receiver. Two extra [Obsolete] properties (Swimming, AFK) are writable from scripts but not synced.
Core parameter table
Section titled “Core parameter table”Every name below is recognised by the runtime with the matching type. Declare a parameter on your avatar’s Animator with the exact name and type and the engine will drive it for you — no extra component required.
| Name | Type | Net-replicated? | Read-only via SetParameter? | Notes |
|---|---|---|---|---|
MovementX | float | yes (core sync) | yes | Strafe input. BetterBetterCharacterController divides by worldSprintMultiplier, so a sprinting avatar produces values up to 1.0. |
MovementY | float | yes (core sync) | yes | Forward input, same normalisation. |
Grounded | bool | yes (core sync) | yes | True while IsGrounded() OR IsSwimming() OR IsSitting() OR IsImmobilized. |
Crouching | bool | yes (core sync) | yes | Driven by BetterBetterCharacterController.crouching. |
Prone | bool | yes (core sync) | yes | Driven by BetterBetterCharacterController.prone. |
Flying | bool | yes (core sync) | yes | True if the controller is flying or in zero-gravity mode. |
Sitting | bool | yes (core sync) | yes | True while attached to a CVRSeat. |
GestureLeft | float | yes (core sync) | yes | Hand gesture float (see Hand Gestures). |
GestureRight | float | yes (core sync) | yes | Hand gesture float. |
Toggle | int | yes (core sync as float) | yes | Driven by CVRInputManager.toggleState, integer 0..7. Stored as float in AvatarCoreSyncData. |
Emote | int | yes (core sync as float) | yes | 0 = none, 1..8 = Emote1..Emote8. Auto-resets to 0 after 0.1 s (PlayerSetup.ResetEmoteAfterTime). |
CancelEmote | bool | yes (core sync) | yes | Set true on movement, hide, death, or visibility transitions. |
GestureLeftIdx | int | local-computed | yes | Auto-set to Mathf.RoundToInt(GestureLeft) whenever GestureLeft is written. |
GestureRightIdx | int | local-computed | yes | Same as left. |
DistanceTo | float | local-computed | yes | World distance from the local player to this avatar. 0 on the local avatar. |
IsLocal | bool | local-computed | yes | true on the local PlayerSetup, false on every PuppetMaster. |
IsFriend | bool | local-computed | yes | Whether the viewer is friended with the avatar’s owner (per-receiver lookup). |
VisemeIdx | int | local-computed | yes | Index of the dominant viseme 0..14. Read from each side’s LipSyncManager. |
VisemeLoudness | float | local-computed | yes | Smoothed amplitude. For viseme idx 0 (silence) this is 1 - peak — invert if you want a “speaking” curve. |
VelocityX | float | local-computed | yes | characterMovement.velocity.x (local) or netIkController.GetRootVelocity().x (remote). |
VelocityY | float | local-computed | yes | Vertical component, same source. |
VelocityZ | float | local-computed | yes | Forward component, same source. |
Swimming | bool | no (local-only) | no | [Obsolete("Swimming is not yet a core parameter!")]. Engine drives it via BetterBetterCharacterController.IsSwimmingAnimator() but it is not in CoreParameters and not synced. |
AFK | bool | no (local-only) | no | [Obsolete("AFK is not yet a core parameter!")]. Set when _vrAfkDetectionEnabled && isUsingVr && !HeadsetOnHead, or when CVRInputManager.AFKToggle fires. Not synced. |
AvatarDefinitions.CoreParameters has exactly 22 entries — the table rows above except Swimming and AFK. AvatarDefinitions.IsCoreParameter(name) is what marks a parameter read-only from the script API.
Network sync mechanisms
Section titled “Network sync mechanisms”Three buckets, three different paths over the wire:
1. AvatarCoreSyncData struct (12 fields)
Section titled “1. AvatarCoreSyncData struct (12 fields)”Sent in the avatar movement packet:
public struct AvatarCoreSyncData{ public float MovementX, MovementY, GestureLeft, GestureRight; public float Emote, Toggle; public bool Grounded, Sitting, Crouching, Flying, Prone, CancelEmote;}Emote and Toggle are stored here as float for compactness even though the public API exposes them as int.
2. Local-computed (10 names)
Section titled “2. Local-computed (10 names)”Read-only core parameters that are not in AvatarCoreSyncData. Each receiver computes them independently — PuppetMaster.AnimateCoreParameters and PlayerSetup.AnimateCoreParameters derive them from local state and the incoming movement packet. For example, DistanceTo uses Vector3.Distance(transform.position, PlayerSetup.Instance.GetPlayerPosition()); VelocityX/Y/Z reads netIkController.GetRootVelocity() on remotes; VisemeIdx/VisemeLoudness come from the receiver’s local LipSyncManager.
GestureLeftIdx and GestureRightIdx are produced as a side effect of writing GestureLeft/GestureRight — see the setter:
public float GestureRight{ set { _coreSyncData.GestureRight = value; if (Parameters.TryGetValue("GestureRight", out var p)) SetParameter_Internal(p, value); if (Parameters.TryGetValue("GestureRightIdx", out var pIdx)) SetParameter_Internal(pIdx, GestureRightIdx = Mathf.RoundToInt(value)); }}3. AAS additional sync data
Section titled “3. AAS additional sync data”Every other Animator parameter that is:
- not local (does not start with
#, is not aTrigger) - not read-only (not in
CoreParameters, not curve-controlled) - still under the 3200-bit budget when registered
…is added to _aasOutboundCacheFloat/Int/Bool and packed into AvatarAdditionalSyncData per tick. See AAS Bookkeeping for the budget mechanics.
The [Obsolete] Swimming and AFK parameters fall outside all three — they bypass IsCoreParameter, are written via SetParameter from the engine, and never enter the sync buffers. They behave as “engine-driven local-only” parameters.
Local-only # prefix
Section titled “Local-only # prefix”Any animator parameter whose name starts with # is treated as local:
public static bool IsLocalParameter(string name) => name.StartsWith("#");AvatarParam.IsSynced returns false for them, so they are skipped by the AAS sync layer and consume 0 bits of the 3200-bit budget.
AnimatorControllerParameterType.Trigger is always local — AvatarParam’s constructor sets isLocal |= type == Trigger, regardless of name. Triggers fire only on the local client.
Use #-prefixed names for menu state, debug toggles, or any parameter that should never leave the local client.
AAS bit costs (summary)
Section titled “AAS bit costs (summary)”| Type | Bits |
|---|---|
Float | 32 |
Int | 32 |
Bool | 1 (packed 8 per byte) |
Trigger | 0 (always local) |
Quick reference — setting from a mod
Section titled “Quick reference — setting from a mod”using ABI_RC.Core.Player;using ABI_RC.Core.Util.AnimatorManager;
var mgr = PlayerSetup.Instance.AnimatorManager; // local AvatarAnimatorManager
// Core parameters: write through the typed properties (bypasses the read-only guard).mgr.MovementX = 1f;mgr.GestureLeft = 2f; // also auto-updates GestureLeftIdxmgr.Emote = 3; // does NOT auto-reset; only PlayerSetup.TriggerEmote() doesmgr.CancelEmote = true;
// Custom / AAS parameter (must be declared on the avatar's controller):mgr.SetParameter("MyHairToggle", true);mgr.SetParameter("HairColor-r", 0.42f);
// Read:mgr.GetParameter("HairColor-r", out float r);For a remote avatar, substitute puppetMaster.AnimatorManager. Calling SetParameter(name, …) for a core parameter is a no-op — IsCoreParameter(name) is checked inside CVRAnimatorManager.SetParameter and the typed properties on AvatarAnimatorManager are the only valid write path.
Public scripting surface
Section titled “Public scripting surface”ABI_RC.API.Player.CoreParameters (the read-only view exposed to scripts) wraps a subset:
MovementX, MovementY, Grounded, Crouching, Prone, Flying, Sitting,GestureLeft, GestureLeftIdx, GestureRight, GestureRightIdx,Toggle, Emote, CancelEmote, DistanceTo, VisemeIdx, VisemeLoudness,Swimming, AFKIsLocal, IsFriend, and VelocityX/Y/Z are not surfaced through Player.Core — read them off AvatarAnimatorManager directly if you need them from a mod.