Architecture
In this section, we’ll cover the general architecture of the package. As the package is built with extensibility in mind, this will go into more technical detail about how the package functions to familiarize the user with key concepts.
The package works with both traditional GameObjects (a.k.a. hybrid) and ECS subscenes using the same authoring components (e.g., MonoBehaviours
). However, in both use cases, all logic runs in the ECS world, and the authoring components merely contain logic to set up entities. In the hybrid scenario, during MonoBehaviour
setup, it also creates an Entity
that gets connected with the GameObject's lifetime and adds components that are connected with the authoring component. For the subscene workflow, it follows general Unity concepts, so for more details, it is recommended to check Unity’s com.unity.entities
package documentation about subscenes.
The other sections will cover the authoring components, entity components, and systems. Keep in mind this only covers the core elements of the package for simplicity. The package contains more components, but they follow this structure quite strictly.

Authoring
Each animated object will contain at minimum the following structure. There is a parent GameObject that contains the Animatron
component, which is the main component. It references the Rig
ScriptableObject that is baked at edit time and contains the bone structure and animation data.
Then it contains one or more child GameObjects, referred to as Skin
, where each of them at the very least contains a RenderMeshArray
. RenderMeshArray
is a general-purpose rendering component that replaces the SkinnedMeshRenderer
.
It is a helpful analogy to think of the parent GameObject with Animatron
as the bones of a body, and the Skin
objects as the flesh that gets rendered—usually bound to a subset of bones or all of them.
Note
Note: RenderMeshArray
can be used as a standalone component that essentially works as a MeshRenderer
. There are multiple benefits to using it instead of Unity’s built-in MeshRenderer
. For more details, read the section about RenderMeshArray
.
Entity
Entities follow a structure similar to authoring, but with more granular components. There is a parent entity that contains several key components. The first is an optional Animatron
, which simply plays an animation at a given index. Next, it contains a JointPose
buffer, which is an array of transforms representing the entity’s pose at the current frame. It also has references to Armature
and Motion
. Armature
and Motion
are generated by the Rig
. Armature
is a compact binary blob that contains joint data, while Motion
is another compact blob containing animation data.
Similarly to authoring, there are one or more child entities. They reference the same Armature
and also contain a SkinMatrix
buffer, which is an array of transforms derived from a subset of the parent’s JointPose
.
There is also a singleton entity that contains the SkinMatrixBuffer
component. This holds all SkinMatrix
buffers from all entities, flattened into a single array and stored in GPU memory. It is later bound to shaders for deformation. Each entity also contains a SkinMatrixBufferIndex
, which is simply an offset into this buffer and is regenerated each frame.
Systems
Most of the system logic runs in a system group called AnimatronSystemGroup
. Here is a simplified execution order of systems and what they do:
AnimatronSystemGroup
contains systems:AnimatronSystem
: Plays the current animation by writing transforms intoJointPose
. This is optional, and users can implement more advanced systems here—e.g., playing multiple animations on different joints or using a custom animation graph.- Animation post-processing: This can be user-defined or, in this package’s case, includes blending (e.g., crossfade, inertialization, inverse kinematics, etc.).
PoseSystem
: Transforms theJointPose
array from local space to object space.SkinSystem
: Updates theSkinMatrix
array from the parent’sJointPose
and applies the bind pose transform, since this matrix will be used by the GPU. For more details, read the code or look up how skinning matrices are typically calculated.SkinMatrixSystem
: This includes several systems that execute at different stages for performance reasons. Their main purpose is to flatten allSkinMatrix
data from all entities into the singletonSkinMatrixBuffer
in GPU memory. It also binds this GPU memory to the shader.
After this, the Unity Entities Graphics package takes over, issuing draw calls for each RenderMeshArray
. Since SkinMatrixBuffer
contains all skin matrices in a single buffer, and each entity contains instance data like SkinMatrixBufferIndex
, the shader can easily access the correct transforms.
In theory, other rendering solutions can also be used, as long as they correctly gather all entities' SkinMatrixBufferIndex
components and pass them to the GPU as instanced data.