Skip to content

Core Concepts: Effects and Animated Properties

Mathéo Auer edited this page Oct 20, 2025 · 1 revision

Core Concepts: Effects and Animated Properties

An Effect is a class that generates particles. TimelineFX provides several built-in effects like CircleEffect and SphereEffect, but its true power comes from creating your own.

Creating a Custom Effect

To create a custom effect, you extend the AnimatedEffect base class. This class provides the necessary boilerplate for automatic property binding.

You only need to implement one method:

  • render(EffectSamplingContext ctx, ParticleBuffer out): This is where you write your particle generation logic. You add particles to the out buffer.

@AnimatedProperty: Making Fields Animatable

To make a field in your effect class controllable by a timeline, you must annotate it with @AnimatedProperty.

import com.github.amatheo.timelinefx.annotation.AnimatedProperty;
import com.github.amatheo.timelinefx.effect.AnimatedEffect;

public class MyCustomEffect extends AnimatedEffect {

    @AnimatedProperty(defaultValue = "1.0")
    public Double radius;

    @AnimatedProperty(defaultValue = "32", name="particle_count")
    public Integer particleCount;

    @Override
    protected void render(EffectSamplingContext ctx, ParticleBuffer out) {
        if (radius <= 0 || particleCount <= 0) return;
        // Your logic here to spawn 'particleCount' particles
        // in a shape of 'radius'.
    }
}

Note

The default values here used in the annotation can only be parsed into Integers, Long, Float, Double or Boolean

Important Rules for @AnimatedProperty

  1. Must be Non-Final: The annotation processor will cause a compile-time error if you apply @AnimatedProperty to a final field. This is because the engine needs to modify the field's value at runtime via reflection.
  2. Connecting to a TimelineProperty: The link between a TimelineProperty from your timeline and the field in your effect is made in the bindings section of an EffectClip. The string name you use in bindParameter must match the field name (or the name attribute of the annotation).
    // In the timeline definition:
    TimelineProperty<Double> radiusProp = TimelineProperty.of("circle_radius");
    
    // In the EffectClip bindings:
    .bindings(b -> b
      // Maps the timeline property "circle_radius" to the Java field "radius"
      .bindParameter("radius", radiusProp)
    )

Tip

The best way to know which properties are available for built-in effects is to look at their source code. Any non-final field annotated with @AnimatedProperty is available to be animated.

◄ Back to Core Concepts

Clone this wiki locally