# How to Animate Colors and Color Transitions with Anime.js

> Animate colors and color transitions effortlessly using Anime.js. Learn to interpolate between hex, RGB, and HSL color formats for smooth visual effects.

- Repository: [Julian Garnier/anime](https://github.com/juliangarnier/anime)
- Tags: how-to-guide
- Published: 2026-03-04

---

**Anime.js automatically converts hex, RGB, and HSL color values into normalized RGBA arrays to perform smooth channel-wise interpolation between any CSS color formats.**

Anime.js is a lightweight JavaScript animation library that makes it easy to animate colors and color transitions between any CSS color format. Whether you are transitioning from hex codes to HSL values or animating RGBA transparency, the library handles complex color space conversions internally. This article explores the internal mechanics and practical implementations based on the `juliangarnier/anime` source code.

## How Anime.js Processes Color Animations

The library treats CSS colors as a dedicated `COLOR` value type. When you animate a color property, Anime.js executes a multi-stage pipeline that parses, normalizes, and interpolates color values.

### Color Detection and Parsing

When Anime.js encounters a property value, the `decomposeRawValue` function in [`src/core/values.js`](https://github.com/juliangarnier/anime/blob/main/src/core/values.js) checks whether the string represents a color. The `isCol` helper identifies hex, RGB, and HSL patterns. If detected, the string is passed to `convertColorStringValuesToRgbaArray` in [`src/core/colors.js`](https://github.com/juliangarnier/anime/blob/main/src/core/colors.js).

This converter dispatches to specialized parsers—`hexToRgba`, `rgbToRgba`, or `hslToRgba`—depending on the input format. Each parser extracts numeric components and normalizes the alpha channel to `1` when omitted, returning a unified four-element RGBA array `[r, g, b, a]`.

### Type Normalization

In [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js) (lines 88-95), Anime.js ensures that both the starting and ending values share the same type. If you animate from a numeric value to a color (or vice versa), the engine coerces the non-color side to a color placeholder `[0, 0, 0, 1]`. This normalization guarantees that the interpolation engine receives compatible RGBA arrays on both sides of the tween.

### Channel Interpolation

During each frame of the animation, the render loop in [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) (lines 199-207) handles the actual color transition. When the tween's `_valueType` is `valueTypes.COLOR`, the engine interpolates each of the four RGBA channels separately using linear interpolation (`lerp`). After applying easing functions and modifiers, the results are clamped to valid ranges and composed into an `rgba()` string.

The final `rgba()` string is then written to the target element's style or attribute in the same block (lines 236-242), completing the color transition.

## Practical Code Examples

### Basic Color Tween

Animate a div's background from its current color to bright red:

```javascript
anime({
  targets: '.box',
  backgroundColor: '#ff0000',
  duration: 1200,
  easing: 'easeInOutQuad'
});

```

Internally, Anime.js reads the computed `background-color`, converts both start and end values to RGBA arrays, and interpolates each channel over 1.2 seconds.

### Multi-Step Color Keyframes

Transition through multiple colors using an array:

```javascript
anime({
  targets: '.circle',
  backgroundColor: [
    '#ff0000',              // red
    'rgba(0,255,0,0.6)',    // semi-transparent green
    'hsl(240,100%,50%)'     // blue
  ],
  easing: 'linear',
  loop: true,
  duration: 3000
});

```

The engine builds intermediate tweens between each pair of colors. Because all entries are normalized to RGBA arrays, you can mix hex, RGBA, and HSL formats freely.

### Cross-Format Transitions

Animate from a hex color to an HSL value:

```javascript
anime({
  targets: '#logo',
  color: [
    '#ff6600',              // orange
    'hsl(300, 70%, 40%)'    // dark magenta
  ],
  duration: 1500,
  easing: 'easeOutCubic'
});

```

Behind the scenes, `#ff6600` converts to `[255, 102, 0, 1]` via `hexToRgba`, while `hsl(300,70%,40%)` converts to `[153, 51, 102, 1]` via `hslToRgba`. The channels are interpolated separately, producing a smooth transition through the color space.

### Animating CSS Custom Properties

When animating CSS variables that represent colors, animate the numeric components and reconstruct the color string in the update callback:

```javascript
anime({
  targets: ':root',
  '--main-hue': [
    '0',   // hue 0 (red)
    '180'  // hue 180 (cyan)
  ],
  update: anim => {
    const hue = anim.animations[0].currentValue;
    document.documentElement.style.setProperty('--main-color',
      `hsl(${hue}, 80%, 50%)`);
  },
  duration: 2000,
  easing: 'easeOutExpo'
});

```

This approach leverages Anime.js's numeric interpolation while manually constructing the HSL color string to update the CSS variable.

## Key Source Files

The color animation pipeline relies on these specific files in the `juliangarnier/anime` repository:

| File | Role in Color Animation |
|------|------------------------|
| [`src/core/colors.js`](https://github.com/juliangarnier/anime/blob/main/src/core/colors.js) | Contains `convertColorStringValuesToRgbaArray` and the specific parsers (`hexToRgba`, `rgbToRgba`, `hslToRgba`) that normalize all color inputs to RGBA arrays. |
| [`src/core/values.js`](https://github.com/juliangarnier/anime/blob/main/src/core/values.js) | Implements `decomposeRawValue` and the `isCol` helper that detects color strings during value decomposition (lines 190-208). |
| [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js) | Handles type normalization between mismatched from/to values, ensuring both sides are converted to the `COLOR` type before interpolation (lines 88-95). |
| [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js) | Executes the per-frame interpolation of RGBA channels using `lerp`, clamps values, and composes the final `rgba()` string for application to the DOM (lines 199-207 and 236-242). |

## Summary

- Anime.js treats all CSS colors as a dedicated `COLOR` value type, automatically detecting hex, RGB, and HSL formats.
- The library converts every color to a normalized RGBA array `[r, g, b, a]` using parsers in [`src/core/colors.js`](https://github.com/juliangarnier/anime/blob/main/src/core/colors.js).
- Type mismatches between from/to values are normalized in [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js) to ensure compatible interpolation.
- During rendering, each RGBA channel is interpolated separately with `lerp` in [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js), then composed into an `rgba()` string.
- You can mix color formats freely in keyframes, animate CSS variables by interpolating numeric components, and transition through semi-transparent colors.

## Frequently Asked Questions

### Can Anime.js animate between different color formats like hex and HSL?

Yes. Anime.js automatically converts hex, RGB, RGBA, HSL, and HSLA strings into normalized RGBA arrays before interpolation. You can animate from `#ff6600` to `hsl(300, 70%, 40%)` without manual conversion, as the library handles the parsing via `hexToRgba` and `hslToRgba` in [`src/core/colors.js`](https://github.com/juliangarnier/anime/blob/main/src/core/colors.js).

### How does Anime.js handle alpha transparency during color transitions?

The library includes the alpha channel as the fourth element in its internal RGBA array representation. When parsing colors without explicit alpha (such as hex or rgb()), the alpha defaults to `1`. During interpolation in [`src/core/render.js`](https://github.com/juliangarnier/anime/blob/main/src/core/render.js), all four channels—including alpha—are interpolated separately using `lerp`, allowing smooth transitions between opaque and semi-transparent colors like `rgba(0,255,0,0.6)`.

### What happens if I try to animate from a number to a color?

Anime.js normalizes mismatched value types in [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js) (lines 88-95). If the starting value is a number and the ending value is a color, the engine coerces the number to a color placeholder `[0,0,0,1]` (black with full opacity). This ensures both values share the `COLOR` type, allowing the interpolation engine to process the transition as a color animation rather than a numeric one.

### Can I animate CSS custom properties that contain colors?

Yes, but with a specific approach. Since CSS variables are strings, you should animate the numeric components of the color (such as hue, saturation, or lightness values) and reconstruct the color string in the `update` callback. For example, animate `--main-hue` from `0` to `180`, then use `document.documentElement.style.setProperty` to set `--main-color` to `hsl(${hue}, 80%, 50%)` based on the interpolated value.