Создание собственных easing функций

Easing-функции определяют характер изменения значения во времени. В отличие от линейной интерполяции, где скорость постоянна, easing позволяет задавать ускорение, замедление, колебания и другие нелинейные эффекты. Это критически важно для создания естественных и выразительных анимаций.

В библиотеке Popmotion easing-функции представляют собой обычные функции, принимающие значение времени t в диапазоне от 0 до 1 и возвращающие преобразованное значение, также в диапазоне 0–1.

const easing = (t) => t

Такой пример соответствует линейному движению.


Базовая структура пользовательской easing-функции

Любая пользовательская easing-функция должна соответствовать следующим требованиям:

  • Входное значение t находится в диапазоне [0, 1]
  • Выходное значение также должно быть в диапазоне [0, 1]
  • Функция должна быть детерминированной (одинаковый вход — одинаковый выход)

Простейший пример — квадратичное ускорение:

const easeIn = (t) => t * t

Здесь движение начинается медленно и ускоряется к концу.


Создание функций ускорения и замедления

Ускорение (ease-in)

const easeInCubic = (t) => t * t * t

Чем выше степень, тем более выражено начальное замедление.

Замедление (ease-out)

Для создания эффекта замедления используется обратная трансформация:

const easeOutCubic = (t) => 1 - Math.pow(1 - t, 3)

Анимация начинается быстро и плавно замедляется к завершению.

Комбинированный вариант (ease-in-out)

const easeInOutCubic = (t) => {
  return t < 0.5
    ? 4 * t * t * t
    : 1 - Math.pow(-2 * t + 2, 3) / 2
}

Первая половина — ускорение, вторая — замедление.


Использование пользовательских easing в Popmotion

В Popmotion easing-функции передаются в конфигурацию анимации:

import { animate } from "popmotion"

animate({
  from: 0,
  to: 100,
  duration: 1000,
  ease: (t) => t * t,
  onUpdate: (value) => console.log(value)
})

Функция ease будет применяться к каждому шагу анимации.


Создание нестандартных кривых

Экспоненциальная функция

const easeInExpo = (t) => {
  return t === 0 ? 0 : Math.pow(2, 10 * (t - 1))
}

Резкое ускорение ближе к концу.

Синусоидальная функция

const easeInOutSine = (t) => {
  return -(Math.cos(Math.PI * t) - 1) / 2
}

Очень плавное и естественное движение.


Параметрические easing-функции

Иногда требуется управлять формой кривой через параметры:

const createPowerEasing = (power) => {
  return (t) => Math.pow(t, power)
}

const easeInQuad = createPowerEasing(2)
const easeInQuart = createPowerEasing(4)

Такой подход позволяет гибко переиспользовать логику.


Имитация физических эффектов

Пружинный эффект (spring-like easing)

const springEasing = (t) => {
  return 1 - Math.cos(t * Math.PI * 4) * Math.exp(-t * 6)
}

Характерные колебания с затуханием.

Эффект “bounce”

const bounce = (t) => {
  if (t < 1 / 2.75) {
    return 7.5625 * t * t
  } else if (t < 2 / 2.75) {
    t -= 1.5 / 2.75
    return 7.5625 * t * t + 0.75
  } else if (t < 2.5 / 2.75) {
    t -= 2.25 / 2.75
    return 7.5625 * t * t + 0.9375
  } else {
    t -= 2.625 / 2.75
    return 7.5625 * t * t + 0.984375
  }
}

Создаёт иллюзию падения с отскоками.


Комбинирование easing-функций

Можно объединять функции для создания сложных эффектов:

const combine = (easeIn, easeOut) => {
  return (t) => {
    return t < 0.5
      ? easeIn(t * 2) / 2
      : 0.5 + easeOut((t - 0.5) * 2) / 2
  }
}

Пример использования:

const customEase = combine(
  (t) => t * t,
  (t) => 1 - Math.pow(1 - t, 2)
)

Ограничения и ошибки при создании easing

  • Выход за пределы [0,1] может привести к некорректной анимации
  • Резкие скачки (discontinuity) создают визуальные артефакты
  • Слишком сложные функции увеличивают нагрузку на CPU

Пример неправильной функции:

const badEasing = (t) => Math.sin(t * 100)

Такая функция вызывает хаотичные скачки.


Визуализация и отладка

Для анализа easing-функций удобно строить графики:

const sample = (fn, steps = 100) => {
  const values = []
  for (let i = 0; i <= steps; i++) {
    values.push(fn(i / steps))
  }
  return values
}

Полученные значения можно отобразить через canvas или графические библиотеки.


Интерполяция с easing

Popmotion позволяет комбинировать easing с интерполяцией:

import { interpolate } from "popmotion"

const mixer = interpolate(
  [0, 1],
  [0, 100],
  { ease: (t) => t * t }
)

console.log(mixer(0.5))

Easing применяется до интерполяции значений.


Продвинутые техники

Кусочно-заданные функции

const customPiecewise = (t) => {
  if (t < 0.3) return t * t
  if (t < 0.7) return 0.3 + (t - 0.3)
  return 0.7 + Math.pow(t - 0.7, 2)
}

Позволяют точно контролировать разные фазы анимации.

Инверсия easing-функции

Иногда требуется “перевернуть” функцию:

const invert = (ease) => {
  return (t) => 1 - ease(1 - t)
}

Практическое применение

  • UI-анимации (hover, клики, переходы)
  • Скролл-анимации
  • Анимация физических объектов
  • Геймдев и интерактивные сцены

Грамотно подобранная easing-функция делает анимацию более естественной, улучшает восприятие интерфейса и повышает качество взаимодействия.