# Extending the System

## Overview

A procedural animation feature consists of 2 entities:

* **FPSAnimatorLayerSettings:** a Scriptable Object that contains all the data.
* **IAnimationLayerJob:** a struct that executes custom animation logic.

{% hint style="success" %}
**Tip**: the framework uses the Animation Job System, which ensures solid performance even with a large number of characters.
{% endhint %}

If you open up the source code of the framework, you will notice that every layer has its own folder with 2 .cs files:

<figure><img src="/files/vFFypCkWM2HWhjD9OxfN" alt=""><figcaption><p>AdditiveLayer example.</p></figcaption></figure>

**FPSAnimatorLayerSettings** class is responsible not just for containing the data, but for instantiating the **IAnimationLayerJob** as well:

{% code title="AdditiveLayerSettings.cs" %}

```csharp
public class AdditiveLayerSettings : WeaponLayerSettings
{
    ...
    public override IAnimationLayerJob CreateAnimationJob()
    {
        return new AdditiveLayerJob();
    }
}
```

{% endcode %}

**CreateAnimationJob()** method must return a new instance of the desired **IAnimationLayerJob**-type. When you link a new **Animator Profile**, the system iterates over all animation features (*Layer Settings*) and then invokes the *CreateAnimationJob()* method to create the *Layer State*.

## Example

First, create a new **FPSAnimatorLayerSettings**-derived class for data, and **IAnimationLayerJob**-implemented struct:

{% code title="YourFeatureLayerSettings.cs" %}

```csharp
public class YourFeatureLayerSettings : FPSAnimatorLayerSettings
{
    //Define your settings here, including the KRigElements.
    public KRigElement myRigElement;

    public override IAnimationLayerJob CreateAnimationJob()
    {
        return new YourAnimationLayerJob();
    }
    
#if UNITY_EDITOR
    public override void OnRigUpdated()
    {
        base.OnRigUpdated();
        
        // (!) Always update KRigElements here.
        // Called when a rig asset is updated/changed.
        UpdateRigElement(ref myRigElement);
    }
#endif
}
```

{% endcode %}

{% code title="YourAnimationLayerJob.cs" %}

```csharp
public struct YourAnimationLayerJob
{
    private YourFeatureLayerSettings _settings;
    private LayerJobData _jobData;
    private TransformStreamHandle _yourBoneHandle;
        
    // Use this method for custom animation logic.
    public void ProcessAnimation(AnimationStream stream)
    {
    }
    
    // Use this for modifying root motion.
    public void ProcessRootMotion(AnimationStream stream)
    {
    }
    
    // This method is called when a new profile is linked.
    public void Initialize(LayerJobData newJobData, FPSAnimatorLayerSettings settings)
    {
        _settings = (AdditiveLayerSettings) settings;
        _jobData = newJobData;
        
        Transform bone = newJobData.rigComponent.GetRigTransform(settings.myRigElement);
        _yourBoneHandle = newJobData.animator.BindStreamTransform(bone);
    }
    
    public AnimationScriptPlayable CreatePlayable(PlayableGraph graph)
    {
        return AnimationScriptPlayable.Create(graph, this);
    }
    
    // Make sure to return a reference to the active asset.
    // It will be used by the FPSBoneController to compute a layer weight.
    public FPSAnimatorLayerSettings GetSettingAsset()
    {
        return _settings;
    }
    
    // Use this method to update job data when a layer is linked.
    public void OnLayerLinked(FPSAnimatorLayerSettings newSettings)
    {
    }
    
    // Use this method when a new weapon or item is equipped.
    public void UpdateEntity(FPSAnimatorEntity newEntity)
    {
    }
    
    // Use this method before the main update to gather input data.
    public void OnPreGameThreadUpdate()
    {
    }
    
    // Use this method to update playable data and gather game thread data.
    public void UpdatePlayableJobData(AnimationScriptPlayable playable, float weight)
    {
        _jobData.weight = weight;
        playable.SetJobData(this);
    }
    
    // Use this method when a finalized pose is required.
    public void LateUpdate()
    {
    }
    
    // Use this method to dispose data manually.
    public void Destroy()
    {
    }
}
```

{% endcode %}

***

In the next chapter, we will learn how to work with the demo project.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://kinemation.gitbook.io/scriptable-animation-system/workflow/extending-the-system.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
