Curve - кривые изменения

В анимационной модели mo.js ключевую роль играет функция преобразования времени в прогресс анимации. Именно это преобразование определяет характер движения, ускорения и замедления объектов, делая визуальные эффекты либо механически линейными, либо органично «живыми». Кривые изменения задают нелинейное соответствие между нормализованным временем t ∈ [0, 1] и значением прогресса p ∈ [0, 1], влияя на динамику любого tween или shape-анимации.

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

Линейная интерполяция задаётся функцией:

p(t) = t

Такой подход даёт равномерное движение без ускорений и замедлений. В контексте интерфейсной анимации это часто воспринимается как «неестественное» поведение, поскольку физические процессы редко происходят строго линейно. Даже простое движение объекта обычно имеет фазу разгона и торможения.

В mo.js линейная кривая может быть задана явно:

new mojs.Tween({
  duration: 1000,
  easing: 'linear'
});

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

Кубические кривые Безье как основа easing

Наиболее распространённый тип кривых изменения основан на кубических кривых Безье. Они задаются четырьмя точками: начальной, конечной и двумя контрольными, формирующими форму изгиба.

Математически кривая определяется как:

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

В контексте easing фиксируются P0 = (0,0) и P3 = (1,1), а контрольные точки P1 и P2 задают характер ускорения.

В mo.js это выражается строкой:

new mojs.Tween({
  duration: 1200,
  easing: 'cubic.out'
});

или пользовательской кривой:

new mojs.Tween({
  duration: 1200,
  easing: 'cubic-bezier(0.25, 0.1, 0.25, 1)'
});

Контроль формы кривой позволяет управлять «ощущением» движения: резкий старт, мягкое завершение или наоборот.

Кривые замедления и ускорения

Поведение easing-функций обычно делится на три базовых категории: ускорение (ease-in), замедление (ease-out) и комбинацию обоих эффектов (ease-in-out).

Функция ускорения характеризуется малым приростом в начале и увеличением скорости ближе к концу:

easing: 'quad.in'

Замедление действует наоборот — быстрый старт и плавное завершение:

easing: 'quad.out'

Комбинированное поведение создаёт симметричную кривую:

easing: 'quad.in-out'

Такие формы используются для имитации физических процессов, где объект сначала преодолевает инерцию, затем постепенно останавливается.

Кривые на основе математических функций

Помимо Безье-кривых, в mo.js применяются математические функции, описывающие более сложные динамики.

Экспоненциальное затухание:

easing: 'expo.out'

Функция такого типа может быть описана как:

p(t) = 1 - 2^{-10t}

Сильное ускорение в начале и почти мгновенное насыщение в конце создаёт эффект резкого завершения движения.

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

easing: 'sin.in-out'

Такие функции задают плавные колебательные изменения скорости:

p(t) = 0.5 * (1 - cos(πt))

Они часто применяются для мягких переходов, где требуется отсутствие резких скачков ускорения.

Пользовательские кривые через SVG path

Одной из наиболее мощных возможностей mo.js является использование SVG-путей для задания easing-функций. Кривая задаётся строкой path, интерпретируемой как траектория функции времени.

new mojs.Tween({
  duration: 1500,
  easing: 'M0,0 C0.2,0.8 0.2,1 1,1'
});

Такой подход позволяет строить произвольные кривые изменения, выходящие за рамки стандартных математических функций. SVG path интерпретируется как карта соответствия времени и прогресса, где координата X — нормализованное время, а Y — значение прогресса.

Преимущество такого подхода заключается в визуальном проектировании кривой: форма может быть создана графически и затем использована в анимации без аналитического описания.

Дискретизация и интерполяция кривых

Любая кривая изменения в конечном итоге сводится к вычислению значения прогресса на каждом кадре анимации. Это означает, что непрерывная функция дискретизируется с частотой кадров рендера.

Процесс можно описать следующим образом:

  1. Нормализация времени:

    t = elapsed / duration
  2. Вычисление значения кривой:

    p = easing(t)
  3. Интерполяция свойств объекта:

    value = start + (end - start) * p

Качество анимации напрямую зависит от стабильности вычисления p(t) и поведения кривой на отрезке [0,1].

Комбинирование кривых в сложных анимациях

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

new mojs.Html({
  el: '.box',
  x: { 0: 200, easing: 'expo.out' },
  scale: { 1: 0.5, easing: 'quad.in-out' },
  opacity: { 0: 1, easing: 'linear' }
});

Такой подход создаёт многослойную динамику, где объект одновременно перемещается, изменяет размер и проявляется с разной скоростью.

Кривые и временные зависимости

Кривые изменения тесно связаны с понятием временной шкалы. В mo.js таймлайн позволяет синхронизировать несколько анимаций, каждая из которых имеет собственную кривую поведения.

При наложении нескольких tween-эффектов с разными easing-функциями возникает сложная результирующая динамика, которая воспринимается как единое движение с внутренней структурой.

Пример:

const timeline = new mojs.Timeline();

timeline.add(
  new mojs.Tween({
    duration: 1000,
    easing: 'quad.out'
  }),
  new mojs.Tween({
    duration: 1000,
    delay: 200,
    easing: 'expo.out'
  })
);

Разные кривые формируют разную плотность движения во времени, создавая эффект «слоистой» анимации.

Искажения восприятия скорости

Человеческое восприятие скорости нелинейно, поэтому линейные кривые часто воспринимаются как механические. Кривые изменения компенсируют эту особенность восприятия.

Эксперименты с easing показывают, что:

  • ускорение в начале делает объект «тяжёлым»
  • замедление в конце создаёт эффект «инерции»
  • резкие перегибы воспринимаются как «рывки»
  • плавные синусоидальные формы дают ощущение мягкости

Таким образом, форма кривой напрямую влияет не только на математику анимации, но и на психологическое восприятие интерфейса.

Адаптация кривых под тип движения

Разные типы объектов требуют различных кривых:

  • UI-элементы часто используют quad.in-out
  • всплывающие эффекты — back.out
  • исчезновения — expo.in
  • фоновые движения — linear

Выбор кривой определяет характер взаимодействия между пользователем и интерфейсом, формируя ощущение отзывчивости или плавности среды.

Ограничения сложных кривых

При использовании пользовательских SVG-кривых важно учитывать вычислительную стабильность. Слишком сложные формы могут приводить к артефактам интерполяции или неравномерному распределению скорости.

Также критичным является соблюдение диапазона [0,1] по обеим осям, поскольку выход за пределы нарушает корректность интерпретации прогресса и может приводить к визуальным скачкам.

Кривые как инструмент управления динамикой сцены

Кривые изменения в mo.js выступают не просто параметром анимации, а механизмом управления общей динамикой сцены. Через них формируется ритм, плотность движения и визуальная структура интерфейса.

Комбинация разных типов кривых в пределах одной сцены позволяет создавать сложные хореографические последовательности, где каждый элемент движется по собственной временной логике, но остаётся синхронизированным с общей системой анимации.