# How to Use Keyframes with Percentage-Based Timing in Anime.js

> Master percentage-based timing in Anime.js. Learn how keyframes translate into precise animations for smoother control over your timelines. Optimize your web animations today.

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

---

**Anime.js converts percentage-based keyframes into precisely timed tweens by parsing percentage keys into proportional offsets, calculating segment durations based on the total animation length, and propagating easing curves continuously across the timeline.**

Anime.js provides a powerful API for **keyframes with percentage-based timing** that allows you to define animation states at specific timeline percentages rather than fixed durations. Unlike array-based keyframes where values are distributed evenly across the duration, percentage-based keyframes give you explicit control over when each property change occurs. The juliangarnier/anime repository implements this feature through the `generateKeyframes` function in [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js), transforming percentage objects into internally timed animation segments.

## Understanding Percentage-Based Keyframes

In Anime.js, percentage-based keyframes use an object syntax where keys represent timeline positions as percentage strings and values define CSS properties at those points.

Instead of supplying an array of values like `[0, 100, 200]` distributed evenly, you provide an object with keys like `"0%"`, `"20%"`, or `"50%"`, mapping to property states. When the animation runs, Anime.js calculates the absolute time for each keyframe by multiplying the percentage offset by the total animation duration you specify.

This approach is particularly useful for coordinating complex animations where multiple properties must change at different rates or specific synchronization points are required.

## Technical Implementation in the Animation Engine

The Anime.js source code processes percentage-based keyframes through a specific pipeline that converts percentage strings into timed animation segments.

### Type Definitions and Validation

The animation parameter types are defined in [`src/types/index.js`](https://github.com/juliangarnier/anime/blob/main/src/types/index.js), where the `keyframes` property accepts either `PercentageKeyframes` or `DurationKeyframes`:

```javascript
// src/types/index.js
@typedef {PercentageKeyframes|DurationKeyframes} [keyframes]

```

This type definition at lines 27-31 validates that your keyframes object contains valid percentage strings or duration-based arrays before processing begins.

### Parsing Percentage Offsets with generateKeyframes

When you create an animation with percentage-based keyframes, Anime.js calls the `generateKeyframes` function in [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js). This function parses the object keys and converts each percentage into a numeric offset:

```javascript
// From src/animation/animation.js (simplified)
const offset = parseFloat(key) / 100;

```

The algorithm at lines 52-66 sorts these offsets and prepares them for duration calculation. This conversion allows the engine to treat percentage markers as normalized timeline positions from 0.0 to 1.0.

### Calculating Segment Durations

After parsing offsets, Anime.js builds a per-property keyframe array (`propArray`) containing `TweenKeyValue` objects. The engine computes the absolute duration for each segment based on the total animation duration:

```javascript
// src/animation/animation.js lines 67-79
duration: offset * totalDuration - accumulatedDuration

```

This calculation ensures that each keyframe segment lasts exactly the proportion of time defined by your percentage markers. For example, a keyframe at `"20%"` in a 1000ms animation receives a timestamp of 200ms, with the segment duration calculated relative to the previous keyframe.

### Easing Propagation Across Keyframes

Anime.js maintains continuous easing curves across percentage boundaries through a post-processing loop at lines 85-95 of [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js). If you specify easing on one keyframe but not the next, the engine copies the previous keyframe's easing forward, ensuring smooth transitions throughout the entire timeline rather than abrupt jumps at segment boundaries.

## Code Examples and Usage Patterns

The following examples demonstrate practical implementations validated by the Anime.js test suite in [`tests/suites/keyframes.test.js`](https://github.com/juliangarnier/anime/blob/main/tests/suites/keyframes.test.js).

### Basic Percentage Keyframe Syntax

Define animation states at specific timeline percentages using the `keyframes` object property:

```javascript
// HTML
// <div id="target-id"></div>

import anime from 'animejs/lib/anime.esm.js';

anime({
  // The keyframes object – keys are percentages
  keyframes: {
    '0%': { x: 100, y: 100 },
    '20%': { x: -100 },           // y stays at 100 until the next keyframe that defines y
    '50%': { x: 100 },
    '80%': { x: -100 },
    '100%': { x: 100, y: -100 },
  },
  // Total duration for the whole sequence (ms)
  duration: 1000,
  // Linear easing ensures each segment follows a straight line
  ease: 'linear',
  // Prevent automatic playback – we'll control it manually in this demo
  autoplay: false,
  // Target element
  targets: '#target-id',
});

// Manually seek to see the intermediate states
const anim = anime.get('#target-id'); // retrieve the running instance
anim.seek(0);    // → translateX(100px) translateY(100px)
anim.seek(200);  // → translateX(-100px) translateY(60px)
anim.seek(500);  // → translateX(100px) translateY(0px)
anim.seek(800);  // → translateX(-100px) translateY(-60px)
anim.seek(1000); // → translateX(100px) translateY(-100px)

```

At 200ms (20% of 1000ms), the animation reaches the state defined at `"20%"`, while properties not explicitly defined at that keyframe maintain their values from previous states.

### Precision with Floating-Point Percentages

Anime.js supports decimal precision in percentage keys for fine-grained control:

```javascript
anime({
  keyframes: {
    '0%': { x: 0 },
    '21.5%': { x: 50 },
    '100%': { x: 100 },
  },
  duration: 1000,
  ease: 'linear',
  autoplay: false,
  targets: '#target-id',
});

const a = anime.get('#target-id');
a.seek(215); // → translateX(50px)

```

The `parseFloat` function in the source code handles these decimal percentages, calculating exact offsets like 0.215 for precise timing control.

### Combining with Traditional Property Arrays

You can mix percentage-based keyframes with standard array-based property animations:

```javascript
anime({
  // Normal property array (duration-based) for X
  x: [0, 100, 200],
  // Percentage-based keyframes for Y
  keyframes: {
    '0%': { y: 0 },
    '50%': { y: 150 },
    '100%': { y: 0 },
  },
  duration: 1500,
  ease: 'easeInOutQuad',
  targets: '#target-id',
});

```

This hybrid approach allows array-based properties to distribute evenly while percentage keyframes control specific timing for other properties.

## Summary

- **Percentage-based keyframes** use object keys like `"0%"` or `"50%"` to define animation states at specific timeline positions rather than distributing values evenly.
- The `generateKeyframes` function in [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js) parses percentage strings into numeric offsets using `parseFloat(key) / 100` and calculates segment durations based on the total animation duration.
- Anime.js builds per-property tween arrays where each segment's duration equals `offset * totalDuration - accumulatedDuration`, ensuring precise timing.
- Easing curves propagate continuously across keyframe boundaries through a post-processing loop in the animation engine.
- Floating-point percentages (e.g., `"21.5%"`) are fully supported for granular control over animation timing.

## Frequently Asked Questions

### What is the difference between percentage-based and duration-based keyframes?

**Percentage-based keyframes** define animation states using percentage strings (like `"0%"` or `"50%"`) relative to the total animation duration, while **duration-based keyframes** use arrays of values distributed evenly across the timeline or explicit duration offsets. According to [`src/types/index.js`](https://github.com/juliangarnier/anime/blob/main/src/types/index.js), Anime.js accepts both `PercentageKeyframes` and `DurationKeyframes` types, but percentage-based timing gives you explicit control over when each state change occurs proportionally to the total animation length.

### How does easing work across percentage keyframe boundaries?

Anime.js propagates easing values continuously across percentage keyframe boundaries through a post-processing loop in [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js) (lines 85-95). If you define easing on an earlier keyframe but omit it on subsequent ones, the engine copies the previous keyframe's easing forward to the next, ensuring smooth transitions rather than abrupt changes at segment boundaries.

### Can I use decimal percentages like 21.5%?

Yes, Anime.js fully supports floating-point percentages. The `generateKeyframes` function uses `parseFloat(key) / 100` to convert percentage strings into numeric offsets, allowing precise timing definitions such as `"21.5%"` or `"33.33%"`. The test suite in [`tests/suites/keyframes.test.js`](https://github.com/juliangarnier/anime/blob/main/tests/suites/keyframes.test.js) validates this behavior, confirming that seeking to 215ms in a 1000ms animation correctly reaches the state defined at `"21.5%"`.

### Where does Anime.js calculate the timing offsets for percentage keyframes?

The timing offset calculations occur in the `generateKeyframes` function within [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js). This function parses the percentage keys, converts them to normalized offsets (0.0 to 1.0), sorts them chronologically, and computes absolute durations for each segment based on the total animation duration you provide. The resulting `TweenKeyValue` objects contain precise `duration` and `to` values that drive the underlying tween engine.