Работа с инерционными анимациями в Popmotion основана на физической модели затухания скорости, где движение объекта продолжается после начального импульса и постепенно замедляется под действием коэффициента сопротивления. Такой подход используется для имитации реального поведения: прокрутка с «флингом», перетаскивание элементов, кинетические интерфейсы.
Decay-анимация опирается на идею начальной скорости, которая со временем уменьшается экспоненциально:
Ключевое свойство модели — отсутствие фиксированной длительности. В отличие от tween-анимаций, здесь невозможно заранее точно сказать, когда завершится движение.
Основное поведение можно описать как:
В Popmotion decay реализован как отдельная анимационная функция, создающая поток значений на основе начальной скорости и параметров затухания.
Базовая форма использования:
import { decay, animate } from "popmotion";
decay({
from: 0,
velocity: 2000
}).start(v => {
console.log(v);
});
Здесь:
from — начальное значениеvelocity — начальная скорость изменения значенияНачальная позиция анимации.
Используется как стартовая точка траектории:
from: 100
Если не указано, считается равным 0.
Начальная скорость движения.
velocity: 1500
Именно этот параметр определяет «импульс» инерции.
Коэффициент влияния скорости на расстояние.
power: 0.25
Фактически регулирует «масштаб инерции».
Определяет скорость затухания во времени.
timeConstant: 350
Этот параметр ближе всего к физическому коэффициенту трения.
Минимальное изменение значения, при котором анимация считается завершённой.
restDelta: 0.5
Если изменение между кадрами меньше этого значения — движение останавливается.
Позволяет трансформировать выходное значение.
modifyOutput: v => Math.max(0, v)
Часто используется для:
Жёсткое ограничение диапазона значений.
clamp: true
При включении значение не выходит за пределы заданного диапазона
(если он определён через min/max).
Decay часто используется для реализации кастомного скролла.
import { decay } from "popmotion";
let current = 0;
decay({
from: current,
velocity: 1200,
timeConstant: 300,
restDelta: 1
}).start(v => {
current = v;
element.style.transform = `translateY(${-v}px)`;
});
Поведение:
Decay сам по себе не знает о границах. Поэтому часто применяется ручное ограничение:
decay({
from: 0,
velocity: 2000,
modifyOutput: v => Math.min(1000, Math.max(0, v))
}).start(v => {
console.log(v);
});
Более продвинутый вариант — остановка при выходе за границы:
const controls = decay({
from: 0,
velocity: 1500
}).start(v => {
if (v > 500 || v < 0) {
controls.stop();
}
});
Decay одинаково работает в обе стороны:
decay({
from: 500,
velocity: -1000
})
Особенности:
Decay часто применяется после завершения drag-событий.
Типичный сценарий:
import { decay } from "popmotion";
let velocity = 0;
element.addEventListener("mouseup", () => {
decay({
from: currentY,
velocity
}).start(v => {
currentY = v;
element.style.transform = `translateY(${v}px)`;
});
});
Decay можно рассматривать как упрощённую физическую модель:
velocity — начальный импульсtimeConstant — коэффициент сопротивления средыpower — усиление или ослабление движенияrestDelta — порог «покоя системы»Это не строгая физическая симуляция, а инженерная модель, оптимизированная для UI.
Decay завершает работу автоматически, но поведение можно контролировать:
restDeltastop()const animation = decay({
from: 0,
velocity: 1800
}).start(v => {
if (v > 800) animation.stop();
});
Decay особенно полезен при создании:
Типичная схема:
let lastY = 0;
let velocity = 0;
element.addEventListener("mousemove", e => {
velocity = e.clientY - lastY;
lastY = e.clientY;
});
element.addEventListener("mouseup", () => {
decay({
from: lastY,
velocity
}).start(v => {
element.style.top = `${v}px`;
});
});
modifyOutput позволяет строить нелинейные эффекты:
modifyOutput: v => {
const resistance = Math.abs(v) > 500 ? 0.5 : 1;
return v * resistance;
}
modifyOutput: v => {
const snapPoints = [0, 300, 600];
return snapPoints.reduce((closest, p) =>
Math.abs(p - v) < Math.abs(closest - v) ? p : closest
, v);
}
Decay-анимации в Popmotion оптимизированы под:
Особенности:
Если velocity = 0, decay фактически не создаёт заметного
движения:
decay({
from: 100,
velocity: 0
})
Система быстро переходит в состояние покоя, поскольку нет начального импульса.
Decay часто используется как начальная стадия более сложных цепочек:
Такие цепочки позволяют комбинировать инерцию и точное позиционирование интерфейса.