> For the complete documentation index, see [llms.txt](https://docs.stixgames.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.stixgames.com/text-animations/c-extensions/custom-c-animations.md).

# Custom C# Animations

{% hint style="info" %}
Unless you want to create an animation that dynamically reacts to external events, or an animation that includes randomness, like `<shake>` you can use [Custom Animations](/text-animations/animations/custom-animations.md) instead of Custom C# Animations.
{% endhint %}

To create a custom animation you need 3 steps:&#x20;

* Create a class inheriting from `TextAnimation`. It will be responsible for animating the text.
* Create a class inheriting from `TextAnimationTagParser`. It will parse the tag and create a `TextAnimation` object with the right parameters.
* Register the parser.

## Text Animation

In this example we'll create a simple animation that moves opacity between 0 and 1.

<figure><img src="/files/WbkEaxbaQxRbFfqrTlgi" alt=""><figcaption><p>The annimation we're going to create in this short tutorial.</p></figcaption></figure>

```csharp
public class OpacityPingPong : TextAnimation
{
    // The frequency of the animation with a default value.
    // The default value is going to be used if no parameter is specified in the tag
    public float frequency = 1;

    // The construction takes the tag used to create the animation object.
    // In case of our simple animation that wouldn't be necessary,
    // but it's useful for animations that have different variants (fade-in / fade-out)
    public OpacityPingPong(string creatorTag) : base(creatorTag) { }

    // Here's where the animation happens.
    // This function is called every frame for every single letter, 
    // even if they are invisible, so try not to do anything crazy in here.
    public override void Animate(
        Letter letter, // The current letter being animated
        int letterIndex, // The index of the currently animated letter
        float time, // The current time of the animation
        AnimationResult result // Contains all modified animation properties
    )
    {
        // Calculate a triangle wave between 0 and 1, that's our opacity!
        var opacity = Mathf.PingPong(time * frequency, 1);
        
        // Multiply the current opacity with our new value.
        // It's important to always modify properties in a way that doesn't overwrite
        // the changes set by other animations.
        // If we wrote `result.opacity = opacity;` here, this animation would break
        // all other animations that use opacity.
        result.MultiplyOpacity(opacity);
    }
    
    // Optimization hints for UI Toolkit.
    public override bool animatesColor => false;
    public override bool animatesTransform => false;
}
```

## Text Animation Tag Parser

```csharp
public class OpacityPingPongParser : SimpleTextAnimationTagParser
{
    public override IEnumerable<string> GetTagNames()
    {
        // This animation parser only supports a single tag
        return new[] { "ping-pong" };
    }

    public override TextAnimation CreateAnimation(string tag, Parameters parameters)
    {
        // Create a new object of our new animation class.
        var pingPong = new OpacityPingPong(tag);

        // Check if the animation tag has the parameter "f" set.
        // If yes, set the value in our ping pong class
        if (parameters.TryGetFloatValue("f", out var frequency))
        {
            pingPong.frequency = frequency;
        }

        // Return the animation object with the right parameters.
        // The animation will be applied to all letters within the tag.
        return pingPong;
    }
}

```

## Registering the parser

There are two ways to register an `AnimationParser` for your text elements:

```csharp
// Register the parser for a single text element
animatedText.AddAnimationParser(new OpacityPingPongParser());

// Register the parser globally
TextAnimator.AddGlobalAnimationParser(new OpacityPingPongParser());
```

## How to use the new animations

Now everything is set up, you can use the animations like any other:

```
Hello, let's try our new <ping-pong>animation</ping-pong>!
```

***

You can also look at the code of all built-in animations for inspiration.

If you need help developing custom animations or want to share your creations, join my [Discord](https://discord.gg/jvBFhQA) and start a discussion!
