Функции плавности (easing functions) определяют характер изменения
значения во времени — ускорение, замедление, инерцию и другие физически
правдоподобные эффекты. В библиотеке Popmotion они представлены как
обычные функции, принимающие прогресс t в диапазоне
[0, 1] и возвращающие преобразованное значение.
Комбинирование функций плавности позволяет создавать более сложные и выразительные анимации, выходящие за рамки стандартных кривых.
Любая функция плавности в Popmotion имеет вид:
const easing = (t) => t
Где:
t — нормализованное время (от 0 до 1)Один из ключевых подходов — передача результата одной функции в другую.
const easeIn = (t) => t * t
const easeOut = (t) => 1 - Math.pow(1 - t, 2)
const combined = (t) => easeOut(easeIn(t))
Особенности:
pipe для композицииPopmotion предоставляет утилиту pipe, которая упрощает
цепочку функций:
import { pipe } from 'popmotion'
const easeIn = (t) => t * t
const easeOut = (t) => 1 - Math.pow(1 - t, 2)
const combined = pipe(easeIn, easeOut)
Преимущества:
Комбинирование может выполняться через разбиение диапазона времени на участки.
const easeIn = (t) => t * t
const easeOut = (t) => 1 - Math.pow(1 - t, 2)
const segmented = (t) => {
if (t < 0.5) {
return 0.5 * easeIn(t * 2)
} else {
return 0.5 + 0.5 * easeOut((t - 0.5) * 2)
}
}
Идея:
[0, 1]Popmotion позволяет интерполировать не только значения, но и сами функции.
import { mix } from 'popmotion'
const easeIn = (t) => t * t
const easeOut = (t) => 1 - Math.pow(1 - t, 2)
const blend = (t) => {
const factor = t
return mix(easeIn(t), easeOut(t), factor)
}
Результат:
easing внутри tweenКомбинированные функции можно напрямую использовать:
import { tween } from 'popmotion'
tween({
from: 0,
to: 100,
duration: 1000,
ease: combined
}).start(console.log)
Popmotion поддерживает сложные кривые через keyframes и easing-массивы:
import { keyframes, easing } from 'popmotion'
keyframes({
values: [0, 50, 100],
ease: [easing.easeIn, easing.easeOut],
duration: 1000
}).start(console.log)
Особенности:
Комбинирование часто включает инверсию:
const invert = (fn) => (t) => 1 - fn(1 - t)
const easeIn = (t) => t * t
const easeOut = invert(easeIn)
Преимущество:
Можно изменять интенсивность функции:
const amplify = (fn, power) => (t) => Math.pow(fn(t), power)
const strongEase = amplify((t) => t, 3)
Или сглаживать:
const soften = (fn, factor) => (t) => fn(t) * factor + t * (1 - factor)
Popmotion позволяет сочетать easing с физическими анимациями (spring, decay).
import { spring } from 'popmotion'
spring({
from: 0,
to: 100,
stiffness: 200,
damping: 15
}).start(console.log)
Комбинирование происходит на уровне управления прогрессом:
const customEase = (t) => t * t * (3 - 2 * t) // smoothstep
Можно трансформировать само время:
const warpTime = (fn) => (t) => fn(t)
const bounceTime = (t) => Math.abs(Math.sin(6.28 * t) * (1 - t))
Использование:
const complex = pipe(bounceTime, (t) => t * t)
Popmotion поддерживает cubic-bezier:
import { cubicBezier } from 'popmotion'
const ease = cubicBezier(0.42, 0, 0.58, 1)
Комбинирование:
const combinedBezier = pipe(
cubicBezier(0.42, 0, 1, 1),
cubicBezier(0, 0, 0.58, 1)
)
1. Ease-in + overshoot + settle
const overshoot = (t) => t + Math.sin(t * Math.PI) * 0.2
const pattern = pipe(
(t) => t * t,
overshoot,
(t) => Math.min(t, 1)
)
2. Медленный старт, быстрый центр, плавный конец
const custom = (t) => {
if (t < 0.3) return t * t
if (t < 0.7) return t
return 1 - Math.pow(1 - t, 2)
}
pipe вместо глубоких вложенийКомбинированные функции лучше оформлять как независимые модули:
export const easeIn = (t) => t * t
export const easeOut = (t) => 1 - Math.pow(1 - t, 2)
export const easeInOut = pipe(easeIn, easeOut)
[0, 1]Функции высшего порядка позволяют строить универсальные композиции:
const chain = (...fns) => (t) =>
fns.reduce((acc, fn) => fn(acc), t)
const easing = chain(
(t) => t * t,
(t) => Math.sin(t * Math.PI / 2)
)
Сложные easing-функции позволяют:
Разнообразие подходов — от простой композиции до сегментации и интерполяции — делает Popmotion мощным инструментом для тонкой настройки анимаций.