# 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!


---

# 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://docs.stixgames.com/text-animations/c-extensions/custom-c-animations.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.
