Индивидуальные easing для сегментов

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

В Popmotion ключевым инструментом для сегментированного движения выступают keyframes. Они позволяют задать массив значений и сопоставить им временные точки, формируя дискретные участки траектории.

Каждый сегмент определяется парой соседних ключевых значений. Например, если заданы значения:

  • 0
  • 100
  • 50

то формируются два сегмента:

  1. 0 → 100
  2. 100 → 50

Именно к этим переходам применяется логика easing.

Индивидуальные easing для каждого участка

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

Структура сопоставления выглядит следующим образом:

import { keyframes } from 'popmotion';

const animation = keyframes({
  values: [0, 100, 50],
  duration: 2000,
  easings: [
    easeOut,   // 0 → 100
    easeIn     // 100 → 50
  ]
});

Количество easing-функций всегда равно количеству сегментов, то есть values.length - 1.

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

Поведение интерполяции внутри сегмента

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

Если обозначить:

  • t — общее время анимации
  • t₁, t₂ — границы сегмента

то внутри сегмента время приводится к диапазону [0, 1], и уже затем применяется easing:

progress = easing((t - t₁) / (t₂ - t₁))

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

Комбинирование различных типов easing

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

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

Пример с разнообразной динамикой:

import { keyframes, easeIn, easeOut, linear } from 'popmotion';

const motion = keyframes({
  values: [0, 300, 150, 400],
  duration: 3000,
  easings: [
    easeOut,   // быстрый старт
    linear,    // равномерное движение
    easeIn     // плавное завершение с ускорением
  ]
});

Первый сегмент задаёт энергичный старт, второй — стабилизацию движения, третий — ускоренное завершение.

Синхронизация длины сегментов и поведения easing

Хотя easing влияет на форму кривой, визуальное восприятие сильно зависит от длительности сегмента. Короткие сегменты с сильным easing создают резкие скачки, тогда как длинные сглаживают даже агрессивные функции.

Распределение времени может быть задано через times:

const animation = keyframes({
  values: [0, 100, 200],
  times: [0, 0.2, 1],
  duration: 2000,
  easings: [easeOut, easeIn]
});

Здесь первый сегмент занимает 20% времени всей анимации, второй — оставшиеся 80%. Это усиливает контраст между фазами движения.

Использование пользовательских easing-функций

Помимо встроенных вариантов Popmotion поддерживает передачу произвольных функций. Это позволяет реализовать уникальные модели ускорения.

Функция easing принимает значение от 0 до 1 и возвращает трансформированное значение в том же диапазоне.

Пример нелинейной функции:

const customEase = t => Math.pow(t, 3);

const animation = keyframes({
  values: [0, 500],
  duration: 1000,
  easings: [customEase]
});

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

const motion = keyframes({
  values: [0, 200, 600],
  duration: 2000,
  easings: [
    t => t * t,          // мягкое ускорение
    t => 1 - Math.pow(1 - t, 3) // резкое замедление
  ]
});

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

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

Сглаживание таких переходов достигается за счёт:

  • увеличения количества промежуточных ключевых точек
  • уменьшения контраста между easing-функциями
  • перераспределения длительности сегментов

Практика построения сложных движений

Сегментное easing часто используется для имитации реальных физических процессов:

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

Пример движения с эффектом удара:

const impact = keyframes({
  values: [0, 300, 260, 280],
  duration: 1500,
  easings: [
    easeOut,   // резкий разгон
    easeIn,    // удар и возврат
    easeOut    // затухающий отскок
  ]
});

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

Управление визуальным ритмом

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

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

const rhythm = keyframes({
  values: [0, 100, 0, 100, 0],
  duration: 2500,
  easings: [
    easeInOut,
    easeInOut,
    easeInOut,
    easeInOut
  ]
});

Хотя easing одинаковый, изменение направлений сегментов создаёт визуальный пульсирующий эффект.

Особенности масштабирования сложности

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

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