# How to Use the Stretch Method for Dynamic Duration Changes in Anime.js

> Learn to use the stretch method in Anime.js to dynamically rescale animation durations. Preserve playback position while recalculating timing for smooth interactive control.

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

---

**The `stretch` method in Anime.js allows you to dynamically rescale the total duration of running animations, timelines, or timers by recalculating internal timing values while preserving the current playback position.**

The `stretch` method is a powerful runtime API in the **juliangarnier/anime** library that enables dynamic duration changes without destroying and recreating animation instances. This functionality is essential for building responsive animations that must adapt to user interactions, scroll positions, or changing viewport conditions while maintaining smooth playback continuity.

## What Is the Stretch Method?

The `stretch` method is available on three core classes within the Anime.js architecture: `JSAnimation`, `Timeline`, and `Timer`. It accepts a single parameter—`newDuration`—and proportionally scales all internal timing properties to match the requested length. Unlike simply changing playback speed, `stretch` modifies the underlying duration values themselves, making it ideal for scenarios where you need to synchronize animation length with external data sources like audio tracks or scroll distances.

## How Stretch Works Under the Hood

All three implementations of `stretch` follow a consistent algorithm defined across the source tree. When you call `stretch(newDuration)`, the engine performs the following operations:

1. **Early termination check** – If the normalized `newDuration` equals the current duration, the method returns immediately to avoid unnecessary calculations.
2. **Calculate time-scale factor** – The engine computes `timeScale = newDuration / currentDuration`.
3. **Resize child components** – Every child tween, animation, or timer has its timing values multiplied by the scale factor.
4. **Delegate to base class** – The `Renderable` base class updates generic fields like `duration` and `iterationDuration`, then returns `this` to enable method chaining.

### Animation Stretching in [`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js)

In the `JSAnimation` class, the `stretch(newDuration)` method iterates through every `Tween` instance stored in the animation. For each tween, it rescales `_updateDuration`, `_changeDuration`, `_currentTime`, `_startTime`, and `_absoluteStartTime` by the computed time-scale factor. This ensures that the animation's easing curves and keyframe distributions remain proportional while occupying the new temporal space.

### Timeline Stretching in [`src/timeline/timeline.js`](https://github.com/juliangarnier/anime/blob/main/src/timeline/timeline.js)

The `Timeline` class implements `stretch(newDuration)` by recursively invoking `stretch` on every child animation or timer added to the timeline. Additionally, it updates the position of all **labels** stored on the timeline instance, multiplying their offsets by the same scale factor. This maintains the relative synchronization between sequenced animations and labelled markers, ensuring that `tl.add({...}, '+=200')` remains proportionally correct after stretching.

### Timer Stretching in [`src/timer/timer.js`](https://github.com/juliangarnier/anime/blob/main/src/timer/timer.js)

For the `Timer` class—which powers scroll-based and generic timekeeping—`stretch(newDuration)` rescales internal offsets including `_offset`, `_delay`, and `_loopDelay`. It also adjusts the timer's `duration` and `iterationDuration` fields. This implementation is particularly important for scroll-linked animations where the "duration" might represent a scroll distance in pixels that changes based on viewport resizing.

## Practical Examples

### Stretching a Simple Animation

Create a basic animation and dynamically slow it down mid-playback:

```javascript
// Create an animation that moves a box over 1 second
const boxAnim = anime({
  targets: '#box',
  translateX: 300,
  duration: 1000,
  easing: 'linear',
  autoplay: true
});

// After 400ms, double the remaining duration
setTimeout(() => {
  boxAnim.stretch(2000); // Total duration becomes 2s, animation slows down
}, 400);

```

The internal `timeScale` calculates as `2000 / 1000 = 2`. All tween timings multiply by this factor, causing the box to continue moving at half speed while preserving its current position.

### Rescaling a Timeline

Adjust the total duration of a complex sequence without breaking synchronization:

```javascript
const tl = anime.timeline({ autoplay: true });

tl.add({
  targets: '.dot',
  translateY: [-50, 0],
  duration: 500,
  easing: 'easeOutQuad'
})
.add({
  targets: '.dot',
  opacity: [0, 1],
  duration: 800,
  offset: '-=200' // Overlap with previous animation
});

// After 500ms, expand the whole timeline to 3 seconds total
setTimeout(() => {
  tl.stretch(3000);
}, 500);

```

Both child animations and their relative offsets scale proportionally. The 200ms overlap becomes a 600ms overlap after the stretch, maintaining the sequence's rhythmic structure.

### Adjusting Timer Duration Dynamically

Use `stretch` with scroll-based or responsive timers:

```javascript
const timer = anime.createTimer({
  duration: 2000,
  autoplay: true,
  update: anim => console.log(`Progress: ${anim.progress}%`)
});

// Responsive adjustment: user resizes scroll container
function onScrollRangeChanged(newRangeMs) {
  timer.stretch(newRangeMs);
}

```

The timer rescales its internal `_offset`, `_delay`, and `_loopDelay` values, ensuring that progress calculations remain accurate relative to the new duration.

### Method Chaining

All `stretch` implementations return `this`, enabling fluent API usage:

```javascript
anime({
  targets: '.ball',
  translateX: 400,
  duration: 1200
})
  .stretch(1800)   // Slow down to 1.8s total
  .pause()         // Pause immediately
  .play();         // Resume with new timing

```

## Edge Cases and Considerations

**Zero Duration Handling** – When `newDuration` approaches or equals the internal `minValue` (used for setter animations), the timer forces its duration to `minValue` and treats the instance as an instant setter. This prevents division-by-zero errors in the time-scale calculation.

**Floating-Point Precision** – After scaling, tween durations are normalized using the internal `normalizeTime` function to minimize accumulated floating-point errors during long-running animations.

**Label Synchronization** – Only `Timeline.stretch` updates label positions. If you manually store external references to timeline offsets, you must recalculate them independently or rely on the built-in label system.

## Summary

- The **`stretch(newDuration)`** method dynamically rescales animation duration without restarting playback or losing progress.
- It is implemented across three core classes: **`JSAnimation`** ([`src/animation/animation.js`](https://github.com/juliangarnier/anime/blob/main/src/animation/animation.js)), **`Timeline`** ([`src/timeline/timeline.js`](https://github.com/juliangarnier/anime/blob/main/src/timeline/timeline.js)), and **`Timer`** ([`src/timer/timer.js`](https://github.com/juliangarnier/anime/blob/main/src/timer/timer.js)).
- The algorithm calculates a **time-scale factor** (`newDuration / currentDuration`) and applies it to all child tweens, offsets, delays, and labels.
- **Method chaining** is supported, allowing `anim.stretch(2000).pause().play()` syntax.
- Edge cases include **zero-duration** handling (setter animations) and **floating-point normalization** to prevent timing drift.

## Frequently Asked Questions

### Can I use stretch on an animation that has already completed?

Yes, you can call `stretch` on a completed animation, but it will only affect the duration values. To see the effect, you would need to restart the animation using `.restart()` or seek to a new position. The `stretch` method itself does not trigger playback; it only modifies the timing structure.

### Does stretching an animation change its easing curve?

No, the easing function remains unchanged. The `stretch` method scales the **duration** and **timing values** (start times, delays, offsets) but preserves the interpolation method defined in the `easing` property. The animation will simply take longer or shorter to complete while maintaining the same acceleration profile.

### How does stretch affect timeline labels?

When you call `stretch` on a `Timeline` instance, the method automatically scales all registered label positions by the same time-scale factor. For example, if you have a label at `1000ms` and stretch the timeline from `2000ms` to `4000ms`, the label moves to `2000ms`. This ensures that relative positioning using labels remains synchronized after duration changes.

### Is there a performance penalty for calling stretch frequently?

The `stretch` method involves iterating through all child tweens or animations and recalculating timing values, which is an O(n) operation where n is the number of active tweens. For simple animations with few properties, this is negligible. However, for complex timelines with hundreds of child animations, calling `stretch` inside a high-frequency event handler (like `mousemove` or `scroll`) could impact performance. For such cases, consider throttling the calls or using the `Timer` class specifically designed for scroll-linked duration changes.