On this page
ECSAnimator API reference
Read unsupported combinations and prohibited operations before integration. A successful Build does not preserve arbitrary Prefab behaviours or automatically compose multiple Animators.
Namespaces: ECSAnimator.Runtime.Product.ECS for runtime/client/commands,
ECSAnimator.Runtime.Product.Data for EntityDesc/Settings, and Asterism.Editor.OfflineBuild.Convert
for the Editor conversion window/plan. Application code references ECSAnimator.Runtime.Product plus the Unity assemblies it uses:
Unity.Entities/Unity.Mathematics for the spawn example, Unity.Transforms for movement,
Unity.Burst for Burst jobs and Unity.Collections for NativeArray. Conversion extensions also
reference ECSAnimator.Offline.Build and ECSAnimator.Package.Contract. All assemblies set
autoReferenced: false, so put consuming code in an asmdef and add the reference explicitly.
Recommended runtime lifecycle
First-time users should start with Getting started and the shipped
SimpleCharacterExample.cs, which includes setup, movement and cleanup instead of isolated snippets.
For step-by-step instructions, see Animation integration and Conversion and component support.
Runtime-loaded EntityDesc assets use the same APIs; see resource-manager loading and unloading.
| API | Purpose |
|---|---|
CharacterRuntime.TryGet(World, ...) |
Gets the single ECSAnimator facade for one live World. |
TryPrepare(CharacterRuntimeAsset, ...) |
Hydrates and retains one reusable character asset. |
CharacterPreparedAsset.RuntimeResource |
Reads compiled public metadata while the prepared bindings remain live; null when stale/released. |
TryCreateScope(expectedCount, ...) |
Creates a caller-owned group of spawned characters. |
TrySpawn / TrySpawnBatch |
Creates character roots from CharacterSpawnRequest; presentation owns their EG render children. |
TryResolve(CharacterInstanceHandle, ...) |
Resolves a stable handle when an Entity is actually required. |
TryCreateAnimationClient(...) |
Resolves declared exact Controller binding keys once and creates one command lane. |
CharacterAnimationClient.TryBind(...) |
Binds one live target to a main-thread CharacterAnimator. |
CharacterAnimationClient.Dispose() |
Stops/disposes the client and releases its prepared-asset hold; do this before Release. |
Destroy / DestroyScope |
Requests instance destruction without exposing renderer ownership. |
Release(CharacterPreparedAsset) |
Returns whether entityDesc/resource retirement was requested. |
prepared.ReleaseState / ReleaseDetail |
Read Active, Pending, Released, FaultedRetainedRequiresWorldRebuild or Invalid directly on the prepared object. |
CharacterRuntime, CharacterPreparedAsset, CharacterSpawnScope and handles are World-bound.
Do not reuse them after destroying or recreating that World. Repeated TryGet returns the same
facade. Removing/replacing internal ECSAnimator systems in a live World is unsupported; rebuild the
entire World instead. Detached release tickets and their bounded history are removed; retain the
prepared object when release status is needed.
Cleanup order: stop/unregister producers, Dispose animation clients, Destroy/DestroyScope, then Release prepared assets. Continue normal World updates while a release is Pending; never busy-wait. If the World was already disposed, discard its facade/handles and do not call its EntityManager.
if (!CharacterRuntime.TryGet(world, out var runtime, out var error) ||
!runtime.TryPrepare(entityDesc, out var prepared, out error) ||
!runtime.TryCreateScope(100, out var scope, out error))
throw new InvalidOperationException(error);
var requests = new CharacterSpawnRequest[100];
for (var i = 0; i < requests.Length; i++)
requests[i] = new CharacterSpawnRequest(new float3(i, 0, 0), quaternion.identity, 1f);
if (!runtime.TrySpawnBatch(prepared, requests, scope, null, out var spawned, out error))
throw new InvalidOperationException(error);
Clothing color at spawn
CharacterSpawnRequest(position, rotation, scale, clothingColor) accepts linear RGB in [0,1];
the fourth channel is tint strength, where 0 preserves the material and 1 replaces the masked
cloth hue while retaining its shading. The three-argument constructor preserves existing appearance.
For a Unity Inspector Color, convert with .linear before passing its RGB values.
var request = new CharacterSpawnRequest(position, rotation, 1f,
new float4(0.02f, 0.20f, 0.95f, 1f));
runtime.TrySpawn(prepared, request, scope, null, out var character, out var error);
The source ECSAnimator/Lit material must enable Clothing Tint and assign a linear
_ClothingMask texture (red channel: white = cloth, black = protected). It shares _BaseMap UV
scale/offset. _ECSAnimClothingColor also provides the material preview/default color.
Rebuild the offline asset after changing these inputs. The renderer sets the color independently
on each character's render children; it does not clone materials per faction or update color every
frame. Characters without a spawn override have no additional color component. This input sets
the initial appearance; runtime color mutation is not exposed by this API.
Animation commands
Create one CharacterAnimationClient per producer/asset, not per character. Declare exact Controller parameter names, layer names or full exported state paths with TryCreateAnimationClient. Main-thread code binds a target and uses those declared keys.
TryBind returns a frame-scoped writer, not a persistent Unity Animator. Bind again each frame, once per client in that frame; do not cache the writer across updates or use the single-target entry for a crowd. Use TryReserveTargets for batch/Jobs. Missing, duplicate or ambiguous keys are rejected at client registration. No Template or gameplay-alias asset is involved.
if (!client.TryBind(character, out var animator, out error) ||
!animator.TrySetFloat("Speed", speed, out error))
throw new InvalidOperationException(error);
CharacterAnimator supports TrySetFloat, TrySetInt, TrySetBool, TrySetTrigger,
TryResetTrigger, TrySetLayerWeight, TryPlay, TryPlayFixedTime, TryCrossFade, and
TryCrossFadeFixedTime. For jobs, cache ResolvedAnimationHandle values with TryGet, reserve once
with TryReserveTargets, write through CharacterAnimationParallelWriter.Begin, and call
RegisterProducer(JobHandle).
CharacterAnimatorWriter supports:
SetFloat,SetInt,SetBool,SetLayerWeightfor continuous state;SetTriggerandResetTrigger;Play,PlayFixedTime,CrossFade, andCrossFadeFixedTime.
Use NextRequest() for direct writer one-shot identity, then call TryGetReceipts once per consumption
batch and use Matches before acknowledging gameplay intent. Its buffer is read-only and must not
be retained across updates. ReceiptCount and TryGetReceipt remain available for individual queries.
Each character has one business writer per frame. Resolve AI/player priorities before writing.
Commands from that writer are applied in reservation/append order; repeated continuous values use
last-write order. Two writers targeting the same character reject that character's entire command
set (Conflict for one-shots). Cross-character producers remain parallel; no global sorting or
multi-writer coalescing is performed. Writer identities are process-local counters, not stable-key
hashes; recreating a client cannot reuse its old requests. At input-generation exhaustion, all new
commands return Fault and the character must be recreated.
Read-only animation state is exposed by CharacterAnimationObservation: TryGetLayer, IsInState,
IsInTag, IsActionPlaying, CountEvent, TryGetEventOccurrence, TryGetEventOccurrences, WasTriggerConsumed, and
TryGetConsumedTrigger. Animation observations are presentation feedback, not gameplay authority.
For a batch of events, call TryGetEventOccurrences once, then use MoveNext(out occurrence, out metadata).
The enumerator validates the binding and generation, preserves occurrence order and duplicate keys,
and borrows the current read-only occurrence buffer. Consume it before the next update or structural change.
CharacterDynamicPackingSystem.TryCopyCurrentWords replaces TryCopyPublishedWords. The requested
generation must still occupy the CPU work buffer; every new Pack attempt invalidates the prior capture,
including failed attempts. Pending data never stands in for an older published generation. LocalResolve
palettes remain evaluator-owned. GPU diagnostics capture their own expected data on request and retain
the exact GPU lease until readback completes; the runtime keeps no published CPU mirror.
State and transition lifecycle feedback is exposed through CharacterLifecycleOccurrence:
StateEnter, StateExit, TransitionStart, and TransitionEnd are emitted without per-instance
configuration. Add CharacterLifecycleSubscription only when per-update StateUpdate records are
required. Consume the buffer in CharacterEventSystemGroup; this is the ECS bridge for presentation
side effects and does not execute arbitrary StateMachineBehaviour managed code.
AI, behaviour tree and movement integration
Move/intent producers belong in CharacterAnimationIntentProducerSystemGroup, before Unity
TransformSystemGroup; animation bridges then run before evaluation. The simple sample has a
Burst ISystem movement example. Its MonoBehaviour animation writes are consumed by a subsequent
ECS update; use the dedicated bridge group when same-Simulation ordering is required.
Project systems own AI state and LocalTransform. A single system in
CharacterAnimationBridgeSystemGroup translates project intent into ECSAnimator commands.
Presentation-event consumers run in CharacterEventSystemGroup. No AI or movement system needs a
GPU buffer, BRG system, Blob layout, or Shader ABI reference.
Prototype and spawn customization
Implement ICharacterPrototypeCustomizer to add unmanaged ECS components or buffers once through
CharacterPrototypeBuilder. Its PrototypeCustomizationId must change whenever the resulting
configuration changes, including default values as well as the archetype. Implement ICharacterSpawnInitializer to populate those declared values through
CharacterSpawnValueWriter for each new instance. ECSAnimator topology, cleanup, transform and
renderer-owned material-property components cannot be replaced through this seam.
Attachments and authoring
CharacterSpawnerBehaviouris the Inspector spawn path;CharacterWorldSelectorsupports an unambiguous default World or an exact named World.CharacterAttachmentAuthoringdeclares a semantic attachment on the source character.- A
SkinnedMeshRendereris converted normally. AMeshRenderer(including a Unity Cube) is converted as a one-bone rigid skin only when it is below its nearestCharacterAttachmentAuthoring, has exactly oneMeshFilter, and that marker's owner bone belongs to the same character. - No enabled
LODGroupis valid and produces one always-visible graphics LOD. Exactly one enabledLODGrouppreserves its authored levels. Multiple enabled groups containing exported levels fail conversion. Unsupported renderer references and levels containing only ignored renderers are omitted with warnings; an effects-only group is ignored. Runtime LOD authority cachesCamera.mainby default.runtime.TrySetLodCamera(camera, out error)explicitly selects another active Game camera; bind before evaluation. Position, lens and LOD bias are sampled each Unity frame. Rebinding after evaluation discards that frame. Display 0, no RenderTexture and no stereo remain required. Additional tagged cameras do not replace the cached selection. - One direct
AnimatorOverrideControllerpreserves replacement clips and null/base entries. Nested chains are not produced by Unity 2022.3's public authoring API: construction flattens them and the controller setter rejects them. ECSAnimator fails closed if malformed serialized data bypasses that API. - Conversion copies each source renderer's GameObject layer, rendering-layer mask, shadow casting,
shadow receiving, and motion-vector mode. It ignores source
lightProbeUsageandprobeAnchor; V4 compatibility fields are normalized toLightProbeUsage.Offand a zero anchor. ECSAnimator ignores serialized probe values at runtime. Artifacts from the older sealed-material digest format must be rebuilt. Current artifacts and animation payloads use V6. Characters do not support or need per-instance Light Probes. Package Lit still receives global ambient lighting through URPSampleSHandunity_ProbesOcclusion; External HLSL/ShaderGraph profiles require Camera motion vectors but no Light Probe-specific ABI. TryResolveAttachmentresolves the semantic key once.TryGetAttachmentPosereturns the committed pose without claiming the target Transform.CharacterRigidEquipmentAttachmentSystempublishes the full affineLocalToWorldfor one separately rendered, project-owned rigid ECS root. Bind it only after an accepted receipt resolves the character, usingTryCreatewith that sameCharacterPreparedAsset; its lifecycle-safeRuntimeResourceis null when stale or released, and the public opaque attachment handle intentionally exposes no index. Every attachment is a public, user-authored attachment; ECSAnimator creates no internal Light Probe attachments. ItsLocalOffsetexcludes the optionalPostTransformMatrix, which the runtime appends once. The binding'sWriteGroupmakes it the only transform owner.Parent, child render hierarchies, SMR, automatic equip/swap/destroy, artifact merging, and same-BRG guarantees are out of scope. Demo17 loads preauthored rigid meshes into one render entity per item; it does not instantiate a child entity hierarchy. Its equip/unequip, automatic/manual LOD and visible Idle have Windows D3D11 Player evidence, plus Unity 2022.3.1f1 Editor checks. Other devices and arbitrary equipment structures remain unqualified. See the sample.- Optional
CharacterRigidEquipmentLodfollows the owner'sCharacterLodSelection. Supply valid consecutive mesh slots, a shared material/submesh and bounds covering all levels; keep assets loaded. Remove the component before a manual writer changes MaterialMeshInfo. This does not simplify meshes, manage equipment lifetime, or create a global managed callback dispatcher.
The custom evaluator intentionally does not claim arbitrary Unity Animator equivalence. Synced and
additive layers, transition interruption and state-machine routes, dynamic state
speed/mirror/time/cycle-offset, Write Defaults Off history, and 2D/Direct BlendTrees have deterministic
runtime implementations, with support bounded by the Unity-oracle qualification matrix for the
chosen Unity version. See the current support table and limits;
this is not a promise of arbitrary Animator combinations. StateMachineBehaviour, controller IK Pass, state Foot IK and Apply Root Motion
are omitted without rejecting the remaining skeletal animation. Inspect preview findings and
OfflinePackageBuildResult.OmittedFeatures; the conversion window also displays a completion dialog.
Source Prefabs/Controllers are unchanged and state scripts are not executed during sampling.
Out-of-envelope Humanoid Hips displacement and arbitrary non-transform/ObjectReference curves
still produce actionable errors instead of silently publishing a wrong character. Exact Root
and hand/foot goal channels from a compatible Humanoid clip/avatar are Unity offline-sampler inputs:
their resulting bone matrices are baked, without adding runtime root-motion or IK execution. The
lifecycle occurrence bridge replaces common enter/exit/update side effects but does not execute
behaviour classes.
Editor conversion API
Multiple Animator components do not block discovery. A valid Preset Animator Path takes priority;
otherwise the first component in prefab hierarchy order (including inactive children) is selected.
The other controllers are omitted, and their preview-clone Animators are disabled. The whole Prefab
hierarchy/renderers remain in scope; this does not split assets or export independent child animation.
Ignored GameObject behaviours are listed in preview and OfflinePackageBuildResult.OmittedFeatures.
The window keeps completion warnings inline/in Console without a confirmation dialog. Invalid
controller, geometry, shader, LOD and artifact-integrity data still require correction.
CharacterConversionDiscovery.Discover(prefab, preset) is pure preview and returns a
CharacterConversionPlan with findings, memory estimates, and CanBuild. Inspect findings for
NeedsVerification; the former CanVerify convenience property is removed. Use the plan's
Build; on success, load result.AssetPath as CharacterRuntimeAsset using AssetDatabase.LoadAssetAtPath in the Editor. Build rediscovers the current Prefab/preset and captures the full
source identity once, then resolves the fixed last-green backup. Do not change source assets or
presets during Build, including from progress callbacks; cancellation remains supported. The four-argument Discover overload
supplies an explicit product key plus separate allowed/requested output roots for tools such as
imported Samples.
The lower-level OfflinePackageBuildApi remains available to custom producers that already own an
OfflineBuildInput and attachment array. Both paths preserve the same candidate validation,
automatic fixed-backup recovery and last-green behavior. Check OfflinePackageBuildResult.IsCompleted, then inspect its asset path,
source/artifact digests, last-green fields, and diagnostics. Cancellation uses the standard
CancellationToken; progress uses IProgress<OfflinePackageBuildProgress>. Invoke Build
synchronously on the Unity Editor main thread; do not wrap it in Task.Run or run two Editors against
the same project checkout.
Public surface index
The following groups account for the package's public top-level types. The first two groups are the ordinary integration contract. Serialized artifact and renderer-diagnostic groups are public so Unity can serialize assets or expose system telemetry; application code should not construct them.
Ordinary integration
- Runtime:
CharacterRuntime,CharacterAnimationClient,CharacterPreparedAsset,CharacterSpawnScope,CharacterSpawnRequest,CharacterSpawnResult,CharacterInstanceHandle,CharacterReleaseState,CharacterSpawnRequestandCharacterSpawnResult. Deferred ECB spawn APIs are removed; Jobs prepare request arrays for main-threadTrySpawnBatch.CharacterPrototypeHandleandWorldResourceTokenare opaque lifecycle capabilities returned by framework extension/resource paths; application code must not construct them. - Binding/commands:
CharacterAnimator,ResolvedCharacterBindings,ResolvedAnimationHandle,ResolvedAttachmentHandle,AnimationRequestToken,CharacterAnimatorWriter,CharacterAnimationParallelWriter,CharacterAnimationReceipt,CharacterAnimationReceiptStatus,CharacterAnimationOperation. - Observation:
CharacterLayerObservation,CharacterAnimationEventOccurrence,CharacterAnimationEventMetadata,CharacterAnimationObservation,CharacterAttachmentObservation,CharacterLifecycleEventKind,CharacterLifecycleSubscription,CharacterLifecycleOccurrence,CharacterAnimationObservationUtility. - Extension:
PrototypeCustomizationId,ICharacterPrototypeCustomizer,ICharacterSpawnInitializer,CharacterPrototypeBuilder,CharacterSpawnValueWriter. - Authoring/groups:
CharacterSpawnerBehaviour,CharacterSpawnerWorldSelection,CharacterWorldSelector,CharacterAttachmentAuthoring,ECSAnimatorSettings,CharacterAnimationIntentProducerSystemGroup,CharacterAnimationBridgeSystemGroup, andCharacterEventSystemGroup.
Editor integration
- Discovery:
CharacterConversionDiscovery,CharacterConversionPlan,CharacterConversionFinding,CharacterConversionSupport,CharacterConvertPreset, andCharacterConvertWindow. - Input/build:
OfflineBuildInput,OfflineBuildRequest,OfflineBuildRequestFactory,SemanticBindingInput,OfflineAttachmentInput,OfflinePackageBuildApi,OfflinePackageBuildProgress,OfflinePackageBuildDiagnostic,OfflinePackageBuildResult,OfflinePackageBuildStage, andOfflinePackageBuildTerminal.
Ordinary CharacterConversionDiscovery.Discover(prefab, preset) defaults to the prefab directory
and <prefab filename>_EntityDesc.asset. A populated preset Output Root overrides the directory.
It locates a moved published descriptor by Product Key; multiple matching _EntityDesc.asset
entries are rejected rather than selecting one arbitrarily. Move it through Unity's AssetDatabase
with its GUID intact. The explicit identity/root overload retains the legacy published basename.
OfflineBuildInput.PublishedAssetPath optionally selects a canonical .asset path under Assets;
null/empty keeps RequestedOutputRoot/CharacterRuntimeAsset.asset. Original output roots still
own immutable snapshots and Recovery; the published entry may be moved outside those roots.
Do not change the original roots merely to relocate an entry.
Serialized package and asset contract
- Assets:
CharacterRuntimeAsset,CharacterAnimationData,CharacterRuntimeResource,CharacterCatalogInput,CharacterCatalog,PackageHandle,PackageLoadState. - Artifact values:
SemanticKey,FailureClass,DiagnosticSnapshot,OperationOutcome,Sha256Digest,SkeletonIdentity,AnimationPropertyId,AnimationBindingDomain,AnimationBindingKind,CharacterDiagnosticCode, andCharacterRuntimeArtifactDigest. - Schema:
PackageParameterKind,PackageLayerBlendKind,PackageMotionKind,PackageTransitionSourceKind,PackageTransitionTargetKind,PackageConditionMode,PackageInterruptionMode,PackageTransitionFlags,PackageControllerFeature,CharacterExecutionProfile, andCharacterSemanticLimits. The renderer schema isCharacterShaderContractV1,CharacterShaderBackend,CharacterShaderIntegrationKind,CharacterShaderPassRole,CharacterShaderProof,CharacterTransformBindingProfile, andCharacterVertexStreamMask. - Runtime records:
CharacterSimulationLodSettings,CharacterRuntimeDraw,CharacterRuntimeLod,CharacterRuntimeMeshSkinRange,CharacterRuntimeParameterMetadata,CharacterRuntimeStateMetadata,CharacterRuntimeShaderCapability,CharacterRuntimeActionInfo,CharacterRuntimeEventInfo, andCharacterRuntimeAttachmentInfo.CharacterExternalRenderStatusreports the Preview/NeedsVerification HLSL/ShaderGraph External path without introducing a second serialized artifact authority.
V6 retains product, source and artifact digests. It stores validated state write masks and fixed
attachment transforms for LocalResolve. As in V5, there are no per-source receipts or serialized
controller feature declarations; the reader checks actual semantic tables and execution capacities.
CharacterRuntimeAsset.EditorInitialize computes and returns the artifact digest once. It no longer
accepts a caller-computed digest or receipts. V4/V5 runtime loading is rejected. Rebuilding an existing
owned V4/V5 output keeps the old asset and references until the V6 candidate passes validation; cancellation
or publication failure preserves/restores the old file. The ArtifactV4 lineage directory name remains
stable for Editor ownership/recovery; it does not select the payload reader.
New builds store lossless compiled animation bytes in CharacterRuntimeAsset.AnimationData,
a CharacterAnimationData subasset named after the selected controller (ByteCount reports its
binary size). Derived Mesh and Material subassets retain source object names. The published asset
owns all three; runtime loading does not depend on ArtifactV4 snapshots. Textures and shaders
remain ordinary external references. The legacy Payload field and its TextAsset loading API have been removed.
AnimationData is required; external-payload assets must be rebuilt from their source Prefabs.
The embedded animation bytes still use the V6 binary layout. Do not construct,
rename, mutate or remove generated subassets; change sources and rebuild. User assets are not
automatically migrated. The distributed Demos have been rebuilt with embedded data and source
prefabs beside their descriptors in Resources; their EntityDesc loading keys are unchanged.
Resources output roots keep Editor lineage/recovery under the corresponding
Editor/ECSAnimatorGenerated directory. These snapshots are not runtime loading dependencies.
Distributed samples omit local snapshots. To start rebuilding a sample in another project, use
a renamed source prefab and a preset with a new unique Product Key; retain that project's new
snapshots for subsequent rebuilds.
Advanced ECS and renderer diagnostics
CharacterRootTag, CharacterDiagnostic, CharacterUpdateBudget, CharacterLodSelection,
CharacterOccurrenceA, CharacterAttachmentPose, CharacterEvaluationSystem,
CharacterDynamicPackingSystem, CharacterDynamicGpuUploadSystem,
CharacterStaticResidencySystem, CharacterEntitiesGraphicsPresentationSystem, CharacterGpuAbi,
CharacterGpuRecoveryRequirement, CharacterGpuBufferLease, CharacterStaticBufferLease,
CharacterStaticPayloadSet, CharacterStaticPayloadBuilder, and
CharacterDrawSubmissionObservation are framework/diagnostic surfaces. They are not required for
normal spawning, AI, movement, animation commands, or attachments.
CharacterEntitiesGraphicsPresentationSystem.TryGetCurrentDrawSubmission and
TryValidateCurrentShaderPasses are on-demand, main-thread diagnostics. The first scans current
render plans and reports logical submissions before view culling plus completed frame retirements;
its draw/visible counts are not native GPU draw-call or pixel measurements. Do not poll it per
character or use it instead of Profiler/GPU evidence for performance claims.
A character evaluation failure is terminal for that instance: its diagnostic is retained, animation updates stop, render children are hidden, and commands/observations reject it. Destroy and respawn the instance after correcting the cause. Other characters continue; failed events, attachment poses and staged frozen poses are never published. Internal mutable state is not restored for retry.
External RegisterConsumer(GraphicsFence) support has been removed. Buffer leases are diagnostic
lifetime pins; external GPU submission through them is unsupported. The package renderer alone owns
the completion protocol, using a queue-ordered generation marker readback after detachment.
A GPU submission fault stops that World at the first fault and retains resources without proven
completion; it no longer continues through spare ring slots. Inspect the reported error and rebuild
the World. Fault-retained buffers are never forcibly disposed; normal shutdown still drains proofs.
ECSAnimator/Lit is Stable. The documented handwritten opaque/cutout HLSL seam and package-SubGraph
URP 14 Lit/Opaque/Forward profile are Preview/NeedsVerification. Graph D3D/Vulkan source variants compile;
Graph Metal cross-compilation has an unresolved URP failure, and mobile device proof remains open.
Transparent, Deferred and arbitrary runtime extra passes remain outside the
contract; see ECSAnimator Lit deformation seam.