How to Animate Colors and Color Transitions with Anime.js
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 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.
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 (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 (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:
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:
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:
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:
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 |
Contains convertColorStringValuesToRgbaArray and the specific parsers (hexToRgba, rgbToRgba, hslToRgba) that normalize all color inputs to RGBA arrays. |
src/core/values.js |
Implements decomposeRawValue and the isCol helper that detects color strings during value decomposition (lines 190-208). |
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 |
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
COLORvalue type, automatically detecting hex, RGB, and HSL formats. - The library converts every color to a normalized RGBA array
[r, g, b, a]using parsers insrc/core/colors.js. - Type mismatches between from/to values are normalized in
src/animation/animation.jsto ensure compatible interpolation. - During rendering, each RGBA channel is interpolated separately with
lerpinsrc/core/render.js, then composed into anrgba()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.
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, 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 (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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →