Управление скоростью Timeline

В библиотеке mo.js временная шкала (Timeline) выступает центральным механизмом координации анимаций. Скорость воспроизведения определяет, насколько быстро проходят все связанные tween- и shape-анимации внутри одной композиции, сохраняя при этом синхронизацию между ними. Контроль скорости становится ключевым инструментом при создании адаптивных, интерактивных и событийно-зависимых эффектов.

Базовая модель времени в Timeline

В основе работы Timeline лежит относительная шкала времени. Каждая анимация внутри таймлайна получает прогресс в диапазоне от 0 до 1, который затем интерполируется во внутренние параметры объекта.

Изменение скорости не влияет на длительность анимаций напрямую — вместо этого модифицируется коэффициент времени:

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

В mo.js скорость часто задаётся через параметр speed при создании или через динамическое изменение свойства экземпляра Timeline.

const timeline = new mojs.Timeline({
  speed: 1
});

Значение 1 соответствует нормальному воспроизведению, 2 — ускорению в два раза, 0.5 — замедлению вдвое.

Динамическое изменение скорости

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

timeline.speed(2);
timeline.speed(0.3);
timeline.speed(0);

Изменение скорости применяется ко всей иерархии анимаций, включая вложенные timelines, если они подключены через .add().

При резкой смене скорости важно учитывать текущий прогресс. Без дополнительной логики может возникнуть визуальный скачок из-за перерасчёта времени.

Масштабирование времени и playbackRate

Внутренне mo.js оперирует концепцией time-scaling, аналогичной playbackRate в Web Animations API. При увеличении коэффициента времени все tween’ы получают более быстрые значения прогресса.

const timeline = new mojs.Timeline();

timeline.add([
  new mojs.Html({
    el: '.box',
    x: { 0: 100 },
    duration: 1000
  })
]);

timeline.play();
timeline.setSpeed(1.5);

Изменение скорости не изменяет duration объектов. Это принципиально важно: длительность остаётся фиксированной, меняется только способ прохождения времени.

Влияние скорости на синхронизацию анимаций

При работе с несколькими объектами внутри одной Timeline синхронизация зависит от общего временного делителя.

Если один элемент имеет длительность 1000ms, а другой 500ms, ускорение Timeline в 2 раза приводит к фактическому завершению за:

  • 500ms вместо 1000ms
  • 250ms вместо 500ms

Однако относительная структура сохраняется, и оба объекта завершаются одновременно.

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

Ограничения резкого изменения скорости

Резкие скачки скорости могут привести к:

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

Особенно заметно это при использовании сложных кривых сглаживания (easing), так как интерполяция зависит от временного шага.

const tween = new mojs.Html({
  el: '.circle',
  x: { 0: 300 },
  duration: 2000,
  easing: 'cubic.out'
});

При ускорении Timeline кривая остаётся неизменной, но вычисляется за меньшее количество кадров, что визуально “сжимает” плавность.

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

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

  • наведение курсора
  • прокрутка страницы
  • изменение состояния интерфейса
  • аудиосинхронизация
const timeline = new mojs.Timeline({
  speed: 1
});

timeline.add(animation);

document.addEventListener('mouseenter', () => {
  timeline.speed(2);
});

document.addEventListener('mouseleave', () => {
  timeline.speed(0.5);
});

Такой подход позволяет использовать Timeline как реактивный механизм, а не только как последовательный проигрыватель.

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

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

let currentSpeed = 1;
let targetSpeed = 3;

function updateSpeed() {
  currentSpeed += (targetSpeed - currentSpeed) * 0.1;
  timeline.speed(currentSpeed);
  requestAnimationFrame(updateSpeed);
}

updateSpeed();

Такой подход создаёт эффект “инерционного” ускорения, особенно полезный в интерактивных сценах.

Вложенные Timeline и каскадная скорость

mo.js позволяет вкладывать Timeline друг в друга. В этом случае изменение скорости родительского таймлайна распространяется вниз по иерархии.

const innerTimeline = new mojs.Timeline();

innerTimeline.add(animation);

const outerTimeline = new mojs.Timeline();
outerTimeline.add(innerTimeline);

outerTimeline.speed(2);

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

Сочетание скорости и repeat

При использовании повторов (repeat) скорость влияет на каждый цикл воспроизведения. Это позволяет создавать эффекты:

  • ускоряющихся пульсаций
  • замедляющихся циклов
  • ритмических колебаний
const pulse = new mojs.Html({
  el: '.dot',
  scale: { 1: 2 },
  duration: 500,
  repeat: 5
});

const timeline = new mojs.Timeline({
  speed: 1
});

timeline.add(pulse);
timeline.play();

Изменение скорости во время повторов может привести к изменению восприятия ритма без изменения структуры анимации.

Работа скорости в контексте pause и play

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

timeline.pause();
timeline.play();

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

Практика управления скоростью в сложных сценах

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

  • базовая скорость задаётся на уровне Timeline
  • локальные эффекты компенсируются duration отдельных tween’ов
  • интерактивные события изменяют speed глобально

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

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

Поведение easing при изменении скорости

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

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

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

Архитектурные паттерны управления скоростью

В продвинутых сценариях управление скоростью выносится в отдельный слой логики:

  • контроллер сцены хранит глобальный speed
  • UI-события изменяют состояние контроллера
  • Timeline подписывается на изменения состояния
const state = {
  speed: 1
};

function setSpeed(value) {
  state.speed = value;
  timeline.speed(state.speed);
}

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

Ограничение минимальной и максимальной скорости

Практически всегда вводятся границы:

  • минимальная скорость близка к 0, но не равна ему (избежание зависания логики)
  • максимальная скорость ограничивается производительностью и восприятием пользователя

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