MasterNin ECSAnimator
On this page

Getting Started with Your Own Character

Conversion exports valid character data where possible: one selected Animator is compiled, while valid skins and bones under other Animators can remain without their independent animation. Particles, lines, trails, sprites and unmarked rigid renderers are omitted with diagnostics. Source components are not deleted. Invalid exported meshes, bindings, Shaders or LOD still require correction.

Read Supported Boundaries and Unsupported Operations first. Build success does not establish support for omitted behavior or arbitrary Prefab combinations.

Start by displaying one character, control Idle/Run with a Speed parameter, then connect movement. You do not need to access GPU buffers or Blobs. See the conversion guide, animation integration and Shader guide for details.

1. Installation and scene requirements

  1. In Package Manager, choose Add package from disk and select the package's package.json, or Add package from tarball for a supplied UPM archive.
  2. Minimum declared version: Unity 2022.3.1f1, Entities/Entities Graphics 1.0.10 and URP 14.0.8. A fresh official URP project on 2022.3.1f1 passed Demos import, Battle Editor Play and a visible Windows x64 Mono/D3D11 run. Earlier complete conversion regression used 2022.3.45f1c1; do not generalize a sample result to all features or devices.
  3. Use URP, enable the SRP Batcher, and set Graphics > BatchRendererGroup Variants > Keep All.
  4. Keep one enabled Game Camera tagged MainCamera, using Display 1 (internal index 0), no Target Texture and no XR/stereo. Add a Directional Light and aim the camera at the spawn location.
  5. Use D3D11/12 on Windows. Vulkan/Metal source paths do not establish mobile device qualification.

Import Quick Start from Package Manager > ECSAnimator > Samples, place NewcomerQuickStart.prefab in a scene and enter Play. Its simplified mesh faces +Z; a Directional Light rotation of (45,150,0) is a useful starting point. Do not rely on residual ambient light in an empty scene.

Gamma and Linear color spaces are usable. Switching after stopping Play and entering Play again has been checked; an Editor restart is not required by ECSAnimator. Brightness need not match between spaces. Legacy Input Manager or Both enables WASD and attack keys. Input System-only projects still spawn and play Idle, but the sample does not read legacy input.

Keep the plugin in Packages/com.asterism.ecsanimator, or select package.json from an external package directory. Do not split Runtime/Editor into Assets. The manifest declares Burst 1.8.4, Collections 2.1.4, Entities/Entities Graphics 1.0.10, Mathematics 1.2.6, URP 14.0.8, TMP 3.0.6, Test Framework 1.1.33 and required Unity modules. Test Framework supplies NUnit for the older Entities Editor assembly. Installation requires access to Unity's package service. Check Package Manager's resolved versions if the host already pins dependencies; do not install duplicate plugin copies.

Imported samples, Settings, character sources and generated assets belong in Assets. They are game content, not another copy of the plugin implementation.

2. Global settings

Open Tools > ECSAnimator > Settings, also available under Project Settings > ECSAnimator.

3. Prepare your Prefab and materials

A minimal character needs a selectable Animator, AnimatorController, SkinnedMeshRenderer, valid bones/mesh and animation. Meshes must be readable and include Position, Normal, Tangent and UV0, with triangle submeshes. See the component table.

Only skeletal animation is converted. Apply Root Motion, IK and StateMachineBehaviour do not block the remaining conversion, but are omitted and reported in Preview and completion diagnostics. Source assets remain unchanged. Your ECS systems must implement movement and any gameplay or parameter changes previously produced by state scripts. BlendShapes, non-skeletal animation and transparent materials are outside scope.

Ordinary URP/Lit is not adapted automatically. Create Assets > Create > ECSAnimator > Lit Material, assign it to the source Prefab, and transfer supported properties:

Source material ECSAnimator/Lit
Base Map / Base Color Base Map / Base Color
Normal Map Normal Map; set Normal Enabled to 1
Normal Scale Normal Scale
Metallic / Smoothness Metallic / Smoothness
Alpha Clipping / Threshold Alpha Clip / Cutoff

Keep the original material as a visual reference. This is a common PBR subset, not an automatic reproduction of arbitrary vendor Shaders. Every exported renderer must use the same supported profile; built-in and External profiles cannot be mixed in one character.

4. Build a minimal Idle/Run Controller

  1. Add a Float parameter named Speed.
  2. Add Idle and Run states. Use Speed > 0.1 for Idle to Run and Speed < 0.1 for Run to Idle. Initially disable Has Exit Time and use a short transition.
  3. Assign the Controller to the Prefab's Animator and save the Controller, Prefab and materials.
  4. Open Tools > ECSAnimator > Convert Character, assign the Prefab, read Preview and fix blocking findings, then click Build.
  5. A successful build selects <PrefabName>_EntityDesc.asset (CharacterRuntimeAsset). This example uses the Controller Float parameter Speed directly.
  6. Rebuild after changing animation, Controller, mesh, material or Shader sources. Runtime uses the built snapshot.

Reusable presets and outputs

Create Assets > Create > ECSAnimator > Convert Preset, then assign it in the conversion window.

Field Meaning
Prefab Saved source Prefab asset, not a temporary scene instance
Product Key Stable, unique character identity; never share it between different characters
Output Root Optional directory under Assets; empty means the source Prefab directory
Animator Path Relative path from the Prefab root. A valid path takes precedence; otherwise the first Animator in hierarchy order, including inactive objects, is used. Other Animators are omitted with warnings.

Supported is an accepted configuration; Ignored identifies omitted behavior; NeedsVerification describes an External Shader requiring further validation. Fix blocking errors before building. The displayed mesh/static-skin and state-arena byte counts are partial estimates, not total RAM or VRAM usage.

Build creates <PrefabName>_EntityDesc.asset. The descriptor embeds compiled animation, derived meshes and materials. Animation data uses the selected Controller's name; meshes/materials retain source names. Move the descriptor through Unity's Project window to preserve its GUID and asset references. Rebuilding the same source/Product Key updates the moved entry. Textures and Shaders remain external dependencies. See output rules.

Distributed demo source Prefabs and descriptors live together in their Resources directories. Runtime loads the generated EntityDesc by its Resources path; the source GameObject is an authoring input. Presets remain in Authoring/source directories. Editor build snapshots for Resources output live under the corresponding Editor/ECSAnimatorGenerated directory.

Rebuilds preserve the published asset GUID and the last successful result. Read diagnostics and Last green preserved before retrying. Do not delete recovery or transaction files. Refresh Preview after source changes; Build rediscovers the current Prefab/preset. Do not modify either during Build, including from progress callbacks.

Materials and format upgrades

Generated materials are snapshots; textures remain ordinary Unity asset references. Editing a referenced texture affects generated characters, and Unity includes its dependencies in Player builds. Do not delete referenced textures. Animation, mesh and runtime structures retain integrity/range checks; the former per-property material sealing and Gamma digest repair interfaces have been removed.

The current format is V6. Rebuild V4/V5 RuntimeAssets from source; do not edit digests to bypass validation. The builder upgrades owned, identity-matching V4/V5 outputs only after candidate validation succeeds. Earlier, damaged or unowned outputs may reject replacement. Preserve old output and metadata. If ownership is uncertain, build in a new empty output directory, test it and switch asset references. See rebuilding and recovery.

5. Move your character

After importing Quick Start, add SimpleCharacterExample to an empty GameObject:

  1. Assign your generated EntityDesc.
  2. Set Speed Parameter to the exact, case-sensitive Float parameter name.
  3. Use DefaultWorld for a single live World; streaming/conversion helper Worlds are ignored. For client/server or other multiple-World projects, select NamedWorld with its exact unique name.
  4. Enter Play and use WASD with Legacy Input Manager/Both. Move Speed is world units per second; the animation parameter receives speed magnitude.

SimpleCharacterExample.cs contains spawning, parameter writes, ECS movement and cleanup. It demonstrates a short main-thread integration, not an efficient command loop for ten thousand characters. For batches/Jobs, use NewcomerAnimationBridgeSystem.cs.

The separate combat example NewcomerCodeSpawner uses exact keys: Speed, Direction, Grounded, UpperBody/Attack#1, FullBody/Hit#1 and FullBody/Death#2. Those state paths belong to its supplied Controller. Its Presentation Event is the animation event's function name, normally ECSAnimatorEvent; event.attack.contact is a payload, not that key. A Speed-only Controller should use SimpleCharacterExample.

6. Connect your System or AI

SimpleCharacterMovementSystem uses Burst/IJobEntity to read SimpleCharacterVelocity and write LocalTransform before Transform updates. Disable Read Keyboard to call example.SetVelocity(new float3(0, 0, 2)) from C#, or write the velocity in an ECS system:

using ECSAnimator.Runtime.Product.ECS;
using ECSAnimator.Runtime.Product.Samples.Newcomer;
using Unity.Entities;
using Unity.Mathematics;

[UpdateInGroup(typeof(CharacterAnimationIntentProducerSystemGroup))]
[UpdateBefore(typeof(SimpleCharacterMovementSystem))]
public partial struct GameVelocitySystem : ISystem
{
    public void OnUpdate(ref SystemState state)
    {
        foreach (var velocity in SystemAPI.Query<RefRW<SimpleCharacterVelocity>>())
            velocity.ValueRW.Value = new float3(0, 0, 2);
    }
}

Put this script in a separate directory with Game.CharacterSystems.asmdef:

{
  "name": "Game.CharacterSystems",
  "references": [
    "ECSAnimator.Runtime.Product", "ECSAnimator.Runtime.Product.Newcomer",
    "Unity.Entities", "Unity.Mathematics", "Unity.Collections"
  ]
}

Generated SystemAPI.Query code also needs Unity.Collections. Add Unity.Transforms when accessing transforms and Unity.Burst when using Burst. Never reference Editor assemblies from Player code.

The Simple example writes commands from MonoBehaviour.Update for a later ECS update. For strict ordering within one Simulation update, use IntentProducer > Transform > AnimationBridge > Evaluation. If the previous command is still pending, Simple retries the latest Speed on a later update without blocking or destroying the character. This is suitable for continuous parameters, not guaranteed one-shot delivery.

Copy/rename sample gameplay types for production integrations. Give each character position one writer. Moving the Spawner GameObject after spawning does not move the Entity. Collision, navigation and damage remain gameplay responsibilities.

7. Control parameters, states and layers

Animation clients use exact Controller parameter names, layer names and exported state paths. Inspect GetStateMetadata(i).Key for states. No gameplay aliases or short state names are generated. Rebuild after source renames and use the matching type: a Float cannot be written with an Int API.

Animator intent ECSAnimator main-thread API
SetFloat / SetInteger / SetBool TrySetFloat / TrySetInt / TrySetBool
SetTrigger / ResetTrigger TrySetTrigger / TryResetTrigger
SetLayerWeight TrySetLayerWeight
Play / PlayInFixedTime TryPlay / TryPlayFixedTime
CrossFade / CrossFadeInFixedTime TryCrossFade / TryCrossFadeFixedTime

Create one shared client per producer/asset, not one per character per frame:

// runtime, prepared and character come from the loading/spawning workflow.
if (!runtime.TryCreateAnimationClient(prepared, "game.player", new[] { "Speed", "Attack" },
        out var client, out var error))
    throw new System.InvalidOperationException(error);

During an update, bind once and write multiple distinct parameters. Attack must be a Trigger. Keep attackPending until writing succeeds:

if (client.TryBind(character, out var animator, out var error))
{
    if (!animator.TrySetFloat("Speed", speed, out error))
        UnityEngine.Debug.LogError(error);
    if (attackPending && animator.TrySetTrigger("Attack", out var request, out error))
        attackPending = false; // Written, not yet accepted, played or applied as damage.
}

The returned animator is valid only for that update. Do not cache it across frames or repeatedly bind thousands of targets. Retry on a later frame if busy. For reliable one-shot behavior, retain the request and follow the receipt/Matches workflow. Acceptance, Trigger consumption and visual events are separate moments; animation events are not authoritative damage decisions.

Use the batch/Jobs sample for crowds: resolve typed handles, reserve once, schedule, call RegisterProducer(jobHandle), and consume current-frame results in CharacterEventSystemGroup. See complete integration instructions.

8. Cleanup and uninstallation

The Simple example calls StopCharacter from OnDisable/OnDestroy:

  1. Stop your command producers; unregister the advanced sample's bridge.
  2. Dispose the animation client.
  3. Destroy the character or its scope.
  4. Release the prepared asset.

Release may span frames. Keep the prepared object and observe prepared.ReleaseState until Released before unloading dependencies. Invalid and FaultedRetainedRequiresWorldRebuild are not success. Do not busy-wait Pending on the main thread or dispose shared Blobs/GPU buffers yourself. After a World rebuild, reacquire every runtime, prepared object and handle.

Before removing the package, remove unused consumer scripts/assembly references, generated content and imported samples, then wait for compilation and remove ECSAnimator in Package Manager. Source Prefabs, Controllers, textures and clips are not automatically deleted.

Troubleshooting

Symptom Check first
Build disabled / SHD010 ECSAnimator/Lit or correctly adapted External Shader; saved inputs
Spawn succeeds but nothing is visible Cached or explicitly bound LOD camera, position/layers, URP, SRP Batcher, DOTS variants and Console
Required binding key missing Exact parameter name and type, rebuilt data, correct sample for the binding contract
Visible but not moving Legacy Input Manager/Both, Read Keyboard, or your velocity-producing System
Renamed parameter has no effect Rebuild and update the exact Controller keys
Release remains Pending Stop producers, dispose clients, continue World updates and inspect returned details
Shader/material edits have no effect Edit the source and rebuild, not the generated snapshot
Rigid weapon is omitted Valid nearest CharacterAttachmentAuthoring, one MeshFilter/sharedMesh and an in-character Owner Bone
Mesh unreadable / invalid vertex streams Read/Write Enabled, complete normals/tangents/UV0, triangle topology
LOD build fails One valid enabled LODGroup, no crossfade, distinct meshes with decreasing vertices and triangles
Missing collision/navigation on Entity These behaviors require game-owned ECS components and systems
Animation stays at its beginning Do not submit Play/CrossFade to zero every frame
Parameter writes do not transition Exact Controller key/type, conditions/Exit Time, conflicting writers and receipts
World unavailable / ambiguous Initialize ECS; select the exact unique NamedWorld and reacquire handles after rebuild

Include Unity/package versions, Editor or Player, graphics API, complete diagnostic code/object path, reproduction steps, parameter types and declared binding keys in a support report. For Shader issues, include source configuration and shadow/depth comparisons rather than only the final “Build failed” line.

Before shipping your project

First test spawning, parameters, movement, events/attachments and destruction in a small scene. Then profile your intended population, mesh/material counts, LOD and motion settings. Sample counts are not performance guarantees. Keep EntityDesc assets, dependencies, Settings and DOTS variants in the Player and test the actual loading route.

Back up sources, generated assets and metadata before upgrades; rebuild compatible data and repeat relevant checks. See the manual index and API reference.