Распределение времени между кадрами

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

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

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

Popmotion использует этот timestamp как базовую точку отсчёта. Вместо того чтобы полагаться на фиксированные шаги времени, система вычисляет разницу между текущим и предыдущим кадром:

const delta = currentTime - previousTime;

Эта разница и становится фундаментом всей логики обновления состояния.

Если бы система использовала фиксированный шаг, например 16.67 мс (60 FPS), любые колебания частоты кадров приводили бы к рассинхронизации анимации. Реальные устройства редко обеспечивают идеально стабильный FPS, поэтому Popmotion опирается на фактическое время между кадрами.

Проблема переменной частоты кадров

В реальной среде интервал между кадрами может существенно меняться:

  • при высокой нагрузке CPU кадры задерживаются;
  • при сворачивании вкладки обновления замедляются;
  • на слабых устройствах частота падает до 30 FPS и ниже;
  • при резких скачках нагрузки возникают микропровалы.

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

Popmotion устраняет эту проблему, переводя всю модель анимации в пространство времени, а не кадров.

Нормализация времени и масштабирование

Одним из ключевых этапов обработки является нормализация delta time. В Popmotion часто используется масштабирование времени относительно базовой частоты 60 FPS:

[ scaledDelta = ]

Это позволяет интерпретировать каждое обновление как «эквивалент» стандартного кадра, даже если реальный интервал отличается.

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

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

Накопление времени и предотвращение скачков

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

Простейшая обработка привела бы к резкому скачку анимации. Popmotion решает это через ограничение максимального delta:

const maxDelta = 40; // ограничение ~25 FPS
const cappedDelta = Math.min(delta, maxDelta);

Такой приём предотвращает «телепортацию» анимации после лагов и делает движение более контролируемым.

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

while (remainingTime > step) {
  update(step);
  remainingTime -= step;
}

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

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

Popmotion не обновляет значения напрямую на каждом кадре без промежуточных вычислений. Вместо этого используется интерполяция — вычисление промежуточного состояния между начальным и конечным значением на основе прогресса времени.

Прогресс обычно выражается в диапазоне от 0 до 1:

[ progress = ]

Далее применяется функция сглаживания (easing), которая преобразует линейный прогресс в нелинейный:

  • линейное движение: равномерное изменение
  • ease-in: ускорение
  • ease-out: замедление
  • ease-in-out: комбинированное поведение

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

Физические анимации и интеграция времени

В spring-анимациях Popmotion время напрямую участвует в численном интегрировании уравнений движения. Здесь кадр не просто обновляет значение, а является шагом симуляции.

Базовая модель включает:

  • положение
  • скорость
  • ускорение

Каждый кадр вычисляет новое состояние системы:

velocity += acceleration * delta;
position += velocity * delta;

Если delta нестабилен, система становится либо чрезмерно «энергичной», либо затухающей. Поэтому корректная обработка времени между кадрами критична для физической достоверности.

Разделение логики обновления и рендера

Внутренне Popmotion разделяет два процесса:

  • вычисление состояния (update)
  • применение состояния к DOM (render)

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

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

Выравнивание анимации при джанке кадров

Jank — это пропуск или задержка кадра. В таких ситуациях важно не пытаться «додумать» промежуточные состояния, а корректно пересчитать прогресс.

Popmotion применяет стратегию временного позиционирования:

  • вычисляется фактическое прошедшее время
  • прогресс пересчитывается заново
  • состояние переопределяется, а не инкрементируется

Это предотвращает накопление ошибок и дрейф анимации.

Тайм-менеджмент в цепочках анимаций

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

Popmotion использует глобальный «мастер-таймер», от которого каждый сегмент берёт свою часть:

  • первый элемент активен в интервале 0–300 мс
  • второй — 300–800 мс
  • третий — 800–1200 мс

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

Компенсация дрейфа времени

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

Вместо:

time += delta;

используется:

time = currentTime - startTime;

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

Приоритет кадров и синхронизация с браузером

requestAnimationFrame синхронизирует выполнение кода с циклом рендеринга браузера. Popmotion использует это для автоматического выравнивания анимации с:

  • repaint
  • layout
  • compositing

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

Поведение при изменении частоты обновления экрана

Современные дисплеи могут иметь 60, 120 и более герц. Это означает, что интервал между кадрами меняется динамически.

Popmotion не привязывается к фиксированному FPS. Вместо этого:

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

Это обеспечивает одинаковое поведение анимации на разных устройствах без ручной адаптации.

Ограничение избыточных обновлений

При высоком FPS возникает проблема чрезмерного количества обновлений логики. Чтобы избежать лишней нагрузки, Popmotion может объединять близкие по времени кадры и пропускать промежуточные вычисления, если они не влияют на итоговое состояние.

Это особенно важно для сложных анимаций с большим количеством объектов, где каждый update включает расчёт трансформаций и интерполяций.

Стабильность при асинхронных задержках

JavaScript не гарантирует точную периодичность выполнения requestAnimationFrame. Поэтому Popmotion рассматривает каждое обновление как событие с произвольным интервалом.

Система проектируется так, чтобы:

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

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

Итоговая модель распределения времени

Внутри Popmotion время между кадрами формирует не просто интервал, а основную ось всей анимационной системы. Каждый кадр рассматривается как функция времени:

[ state = f(time)]

а не как последовательность приращений:

[ state_{n+1} = state_n + ]

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