Skip to content

Creating Custom Properties (AnimX.use)

AnimX handles standard CSS properties natively. But what if you want to animate something completely custom? For example, what if you want to animate a number counting up from 0 to 100 inside a text element?

Since "counter" is not a real CSS property, AnimX doesn't know how to animate it. To teach AnimX how to do this, we create a Custom Property Plugin using AnimX.use().

In this guide, we will build a counter plugin step-by-step. By the end, you will understand exactly how AnimX plugins work under the hood.


Step 1: The Plugin Skeleton

Every custom property plugin is simply a JavaScript object with two required functions: prepare and render. Let's create an empty skeleton for our counterPlugin.

javascript
const counterPlugin = {
  // 1. prepare: Runs ONCE before the animation starts
  prepare: (target, prop, fromValue, toValue) => {
    // We will figure out our starting and ending numbers here
  },
  
  // 2. render: Runs on EVERY FRAME of the animation
  render: (target, descriptor, t) => {
    // We will update the HTML on the screen here
  }
};
  • prepare: Think of this as the "setup" phase. It looks at what the user wants to do, and prepares the math.
  • render: Think of this as the "drawing" phase. It happens 60 times a second, updating the screen as the animation runs.

Step 2: Writing the prepare Function

The prepare function is called exactly once when the animation is created. Let's look at its arguments:

javascript
prepare: (target, prop, fromValue, toValue) => {
  • target: The actual HTML element on the page that we are animating (e.g., <div class="count-box">0</div>).
  • prop: The name of the property being animated. In our case, this string will be "counter".
  • fromValue: The starting value. If the user didn't specify one, this will be undefined.
  • toValue: The ending value the user requested (e.g., 100).

The Goal of prepare

The engine needs to know exactly what numbers to animate between. Our job is to return an object (called a "descriptor") that provides these numbers.

javascript
prepare: (target, prop, fromValue, toValue) => {
  // If fromValue is undefined, we need to guess the starting number.
  // We do this by reading the text inside the HTML element and parsing it as a number.
  // If it's empty or not a number, we default to 0.
  const current = fromValue !== undefined ? fromValue : (parseFloat(target.textContent) || 0);
  
  // Now we return the instruction object back to the AnimX engine
  return { 
    type: 'plugin', // This tells AnimX "Hey, this is a custom plugin, treat it specially!"
    prop: prop,     // The name of the property ('counter')
    from: current,  // The starting number we just figured out
    to: parseFloat(toValue) // Ensure the ending value is safely a number
  };
}

Step 3: Writing the render Function

The render function is called continuously (e.g., 60 times per second) while the animation runs.

javascript
render: (target, descriptor, t) => {
  • target: The HTML element we are animating.
  • descriptor: This is the exact object we returned from the prepare function! It contains our from and to numbers.
  • t: This stands for "time" (or progress). It is a decimal number that usually goes from 0.0 (start of the animation) to 1.0 (end of the animation).

The Goal of render

We need to calculate the current number based on t, and then put that number onto the screen.

javascript
render: (target, descriptor, t) => {
  // 1. Calculate the current value using standard interpolation math:
  // start + (difference between end and start) * progress
  const currentVal = descriptor.from + (descriptor.to - descriptor.from) * t;
  
  // 2. We don't want decimals like 45.678 on our screen, so we round it to a whole number.
  const roundedVal = Math.round(currentVal);
  
  // 3. Finally, we update the HTML element's text so the user sees it change!
  target.textContent = roundedVal;
}

Step 4: Register and Use!

Now that our plugin object is built, we need to register it with the AnimX engine using AnimX.use(). The first argument is the property name we want to listen for ('counter'), and the second is our plugin object.

javascript
import { animate, registerPropertyPlugin } from 'animx';

registerPropertyPlugin('counter', counterPlugin);

That's it! AnimX now knows how to animate the counter property. We can use it just like a normal CSS property in our animate() calls:

javascript
animate('.count-box', {
  counter: 100, // Our custom plugin will handle this!
  duration: 2
});

Final Result

Here is the complete, working code in action:

Click replay to execute
0
60 FPS