Физическая модель пружины

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

  • Сила упругости (spring force) — стремится вернуть объект в равновесное положение
  • Демпфирование (damping) — снижает энергию системы, постепенно останавливая движение
  • Масса (mass) — влияет на инерцию объекта

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

Математическая модель

Поведение пружины описывается дифференциальным уравнением второго порядка:

m + c + kx = 0

где:

  • ( m ) — масса
  • ( c ) — коэффициент демпфирования
  • ( k ) — коэффициент жесткости (stiffness)
  • ( x ) — смещение от положения равновесия

В контексте анимации это означает, что позиция объекта зависит не только от времени, но и от его текущей скорости и ускорения.

Основные параметры в Popmotion

В Popmotion управление пружиной осуществляется через набор параметров:

1. Stiffness (жесткость)

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

  • Высокое значение → быстрое, резкое движение
  • Низкое значение → медленное, «мягкое» возвращение
import { spring } from "popmotion";

spring({
  from: 0,
  to: 100,
  stiffness: 200
}).start(v => console.log(v));

2. Damping (демпфирование)

Контролирует затухание колебаний.

  • Низкое значение → выраженные колебания (bounce)
  • Высокое значение → быстрое затухание без колебаний
spring({
  from: 0,
  to: 100,
  damping: 5
}).start(v => console.log(v));

3. Mass (масса)

Влияет на инерцию системы.

  • Большая масса → медленное ускорение и замедление
  • Малая масса → быстрый отклик
spring({
  from: 0,
  to: 100,
  mass: 2
}).start(v => console.log(v));

Типы поведения пружины

В зависимости от соотношения параметров система может находиться в разных режимах:

Недодемпфированная система (Underdamped)

  • Объект колеблется вокруг целевого значения
  • Характерно для «пружинящих» интерфейсов
spring({
  from: 0,
  to: 100,
  stiffness: 150,
  damping: 10
})

Критическое демпфирование (Critically damped)

  • Быстрое достижение цели без колебаний
  • Оптимально для интерфейсов без лишней «игривости»
spring({
  stiffness: 200,
  damping: 20
})

Передемпфированная система (Overdamped)

  • Очень плавное и медленное движение
  • Без колебаний, но с заметной задержкой
spring({
  stiffness: 100,
  damping: 50
})

Начальная скорость (Velocity)

Параметр velocity задаёт начальную скорость объекта. Это особенно важно при прерывании анимаций или взаимодействии с жестами.

spring({
  from: 0,
  to: 100,
  velocity: 300
})

Высокая начальная скорость может привести к:

  • более сильному «перелёту» цели
  • увеличению количества колебаний

Rest conditions (условия остановки)

Popmotion завершает анимацию, когда выполняются два условия:

  • скорость ниже порога (restSpeed)
  • расстояние до цели меньше порога (restDelta)
spring({
  to: 100,
  restSpeed: 0.01,
  restDelta: 0.01
})

Это предотвращает бесконечные микроколебания.

Работа с единицами и значениями

Пружина может анимировать не только числа:

  • пиксели ("100px")
  • проценты ("50%")
  • цвета
  • сложные структуры (объекты, массивы)
spring({
  from: "0px",
  to: "200px"
}).start(v => {
  element.style.transform = `translateX(${v})`;
});

Комбинирование с другими действиями

Пружины можно комбинировать с другими анимациями:

С chain

import { chain, tween } from "popmotion";

chain(
  tween({ to: 100 }),
  spring({ to: 0 })
).start(console.log);

С parallel

import { parallel, spring } from "popmotion";

parallel(
  spring({ to: 100 }),
  spring({ to: 200 })
).start(v => console.log(v));

Практические паттерны

Эффект «резиновой кнопки»

spring({
  from: 1,
  to: 1.2,
  stiffness: 300,
  damping: 10
})

Используется для масштабирования (scale) при нажатии.

Перетаскивание с возвратом

spring({
  from: dragPosition,
  to: 0,
  velocity: dragVelocity
})

Создаёт ощущение физического возврата элемента.

Overshoot-анимация

spring({
  from: 0,
  to: 100,
  stiffness: 250,
  damping: 8
})

Объект слегка «перелетает» цель и возвращается обратно.

Влияние параметров друг на друга

Параметры не работают изолированно:

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

Баланс параметров — ключ к реалистичной анимации.

Оптимизация и производительность

  • Использование requestAnimationFrame внутри Popmotion обеспечивает плавность
  • Пружины часто эффективнее, чем сложные ключевые кадры
  • Избегание чрезмерно малых restDelta снижает нагрузку

Сравнение с tween-анимацией

Характеристика Spring Tween
Поведение Физическое Линейное/кривые
Реакция на ввод Высокая Ограниченная
Реализм Высокий Средний
Контроль Через физику Через easing

Пружины лучше подходят для:

  • интерактивных интерфейсов
  • drag-and-drop
  • жестовых взаимодействий

Внутренний механизм Popmotion

Popmotion интегрирует численное решение дифференциального уравнения с использованием пошаговой интеграции:

  • вычисляется ускорение
  • обновляется скорость
  • обновляется позиция

Этот цикл выполняется на каждом кадре:

velocity += acceleration * deltaTime;
position += velocity * deltaTime;

Такой подход обеспечивает:

  • стабильность
  • предсказуемость
  • независимость от FPS

Управление временем и кадрами

Popmotion автоматически учитывает:

  • разную частоту кадров
  • задержки между кадрами

Это делает анимации консистентными даже при просадках производительности.

Расширенные техники

Управление через физические коэффициенты

Вместо привычных параметров можно использовать:

  • stiffness
  • damping
  • mass

или более абстрактные:

  • duration
  • bounce

Popmotion может автоматически преобразовывать одни параметры в другие.

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

Пружина может использоваться как источник значений:

spring({ to: 100 }).start(v => {
  customRender(v);
});

Это позволяет интегрировать её в любые рендер-системы.

Отладка поведения

Типичные проблемы:

  • «дрожание» — слишком маленький restDelta
  • слишком долгие колебания — низкий damping
  • резкость — слишком высокий stiffness

Корректировка параметров решает большинство из них.

Интуитивное понимание

  • Жесткость — «насколько сильно тянет назад»
  • Демпфирование — «насколько быстро успокаивается»
  • Масса — «насколько трудно сдвинуть»

Их комбинация формирует характер движения — от мягкого и плавного до резкого и пружинистого.