Easing

Velocity.js реализует систему easing как фундаментальный механизм управления динамикой анимации. Easing определяет характер изменения значений во времени: скорость ускорения, замедления, наличие колебаний и степень плавности переходов между состояниями.

В основе лежит функция времени t, нормализованная в диапазоне от 0 до 1, где:

  • 0 — начало анимации
  • 1 — завершение анимации

Easing-функция преобразует это значение в кривую, определяющую фактическое изменение свойства.


Базовая модель easing

Любая easing-функция в Velocity.js описывается как преобразование:

f(t) → t'

где:

  • t — линейный прогресс времени
  • t' — скорректированный прогресс с нелинейной динамикой

Линейная анимация:

t' = t

Easing вводит нелинейность:

t' = t²
t' = √t
t' = sin(t · π / 2)

Такие преобразования позволяют моделировать физически правдоподобное движение.


Категории easing-функций

Линейное изменение

Самая простая форма:

linear: t

Характеристика:

  • постоянная скорость
  • отсутствие ускорения и замедления
  • визуально механическое движение

Используется для технических индикаторов, прогресс-баров без акцента на UX.


Квадратичные и кубические кривые

Классические easing-функции:

easeInQuad: t²
easeOutQuad: t(2 - t)
easeInOutQuad: 2t² (t < 0.5)

Поведение:

  • easeIn: старт медленный, ускорение к концу
  • easeOut: быстрый старт, замедление в конце
  • easeInOut: комбинированная симметрия

Кубические варианты усиливают эффект:

easeInCubic: t³
easeOutCubic: (t - 1)³ + 1

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

Экспоненциальное поведение создаёт резкие изменения скорости:

easeInExpo: 2^(10(t - 1))
easeOutExpo: 1 - 2^(-10t)

Особенности:

  • почти мгновенное ускорение или торможение
  • высокая выразительность движения
  • применяется для акцентных интерфейсных эффектов

Синусоидальные кривые

Основаны на тригонометрии:

easeInSine: 1 - cos(t · π/2)
easeOutSine: sin(t · π/2)

Характер:

  • мягкое начало и завершение
  • отсутствие резких скачков
  • визуально «естественное» движение

Структура easing в Velocity.js

Velocity.js поддерживает easing в нескольких формах:

Строковое определение

Velocity(element, { opacity: 1 }, { duration: 800, easing: "easeInOutQuad" });

Строка указывает на встроенную функцию.


Числовые параметры spring-подобных кривых

Velocity.js поддерживает расширенные модели:

easing: [0.25, 0.1, 0.25, 1.0]

Это cubic-bezier кривая:

cubic-bezier(x1, y1, x2, y2)

Параметры:

  • x1, x2 — временные точки управления
  • y1, y2 — амплитудные коэффициенты

Такая модель позволяет задавать произвольные траектории ускорения.


Кастомные функции

Поддерживается передача функции:

easing: function (t) {
    return t * t * (3 - 2 * t);
}

Функция получает нормализованное время и возвращает преобразованное значение.

Типичная сигнатура:

f(t: number) → number

Ограничение:

  • вход и выход в диапазоне [0, 1] для корректной интерполяции

Внутренний механизм применения easing

Velocity.js применяет easing на этапе вычисления промежуточных кадров.

Процесс:

  1. Вычисляется прогресс анимации:

    t = elapsed / duration
  2. Применяется easing-функция:

    t' = easing(t)
  3. Интерполяция свойств:

    value = start + (end - start) · t'

Для числовых свойств применяется линейная интерполяция, для цветов — компонентная.


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

Для свойства opacity:

start = 0
end = 1

При easeOutQuad:

t' = t(2 - t)

Итог:

opacity = 0 + (1 - 0) · t'

Для координат:

x = x0 + (x1 - x0) · t'
y = y0 + (y1 - y0) · t'

Cubic Bezier как основа сложных easing

Модель cubic-bezier лежит в основе большинства современных easing-кривых.

Форма:

B(t) = (1 - t)^3·P0 + 3(1 - t)^2·t·P1 + 3(1 - t)·t^2·P2 + t^3·P3

Где:

  • P0 = (0,0)
  • P3 = (1,1)
  • P1, P2 — управляющие точки

Velocity.js использует упрощённую интерпретацию для расчёта прогресса по оси Y.


Типичные пресеты easing

Ease In

slow start → fast end

Примеры:

  • easeInQuad
  • easeInCubic
  • easeInExpo

Используется для появления элементов из состояния покоя.


Ease Out

fast start → slow end

Примеры:

  • easeOutQuad
  • easeOutCubic
  • easeOutExpo

Применяется для завершения движения и фиксации объектов.


Ease In Out

slow start → fast middle → slow end

Примеры:

  • easeInOutQuad
  • easeInOutSine

Оптимален для UI-переходов.


Кастомизация поведения easing

Расширенные сценарии включают создание составных функций.

Ограничение амплитуды

function easeSoft(t) {
    return Math.min(1, t * 1.2);
}

Пружинная модель

function easeSpring(t) {
    return 1 - Math.exp(-6 * t) * Math.cos(12 * t);
}

Поведение:

  • колебания вокруг целевого значения
  • эффект инерции

Эластичное замедление

function easeElastic(t) {
    return Math.pow(2, -10 * t) * Math.sin((t - 0.1) * 5 * Math.PI);
}

Ошибки проектирования easing-кривых

Выход за диапазон

t' < 0 или t' > 1

Приводит к:

  • дерганью анимации
  • выходу за границы свойств

Неправильная нормализация времени

Если:

t = elapsed / duration

не ограничивается:

t ∈ [0, 1]

возникает некорректная интерполяция.


Несовместимость с физическим движением

Резкие кривые:

  • экспоненциальные скачки
  • мгновенное ускорение

создают визуальный диссонанс при длительных анимациях.


Производительность easing-функций

Easing вызывается на каждый кадр анимации.

При 60 FPS:

60 вызовов в секунду на одно свойство

При множественных анимациях:

N × 60 вычислений

Поэтому:

  • избегаются тяжёлые вычисления
  • минимизируются тригонометрические функции в массовых анимациях
  • предпочтение отдается предрассчитанным кривым

Сравнение типов кривых

Тип Характер Интенсивность
Linear равномерное движение низкая
Quad мягкое ускорение средняя
Cubic выраженная динамика высокая
Expo резкие изменения очень высокая
Sine плавность низкая

Роль easing в архитектуре анимаций

Easing является промежуточным слоем между временем и визуальным состоянием. Он отделяет:

  • временную модель (time)
  • визуальную модель (presentation)

Такое разделение позволяет:

  • повторно использовать анимации
  • менять поведение без изменения логики
  • создавать адаптивные интерфейсные переходы