Повторение всей последовательности

Повторяемость анимации в mo.js строится вокруг управления объектами Timeline, Tween, Shape, Burst и их состояниями выполнения. Любая сложная последовательность фактически представляет собой граф зависимостей времени, где каждый элемент может быть перезапущен, перемотан или синхронизирован с другими.

Ключевая особенность системы — отделение описания анимации от её исполнения. Это позволяет многократно запускать одну и ту же композицию без пересоздания объектов.


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

Любой анимационный объект поддерживает методы управления состоянием:

  • play() — запуск с текущей позиции
  • pause() — остановка
  • stop() — сброс в начало
  • replay() — остановка и запуск с начала

На уровне отдельного tween:

const tween = new mojs.Tween({
  duration: 1000,
  onUpdate: (p) => {
    console.log(p);
  }
});

tween.play();
tween.replay();

Метод replay() эквивалентен последовательности stop()play(), но выполняется атомарно, без промежуточных кадровых состояний.


Повторение сложных последовательностей через Timeline

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

const circle = new mojs.Shape({
  shape: 'circle',
  radius: { 0: 50 },
  duration: 800
});

const square = new mojs.Shape({
  shape: 'rect',
  radius: { 0: 40 },
  duration: 800,
  delay: 200
});

const timeline = new mojs.Timeline({
  repeat: 0
});

timeline.add(circle, square);

timeline.play();
timeline.replay();

При вызове replay() происходит:

  • сброс времени всех вложенных анимаций
  • синхронная установка прогресса в 0
  • повторная инициализация внутренних интерполяций

Полный сброс состояния перед повтором

Для корректного повторного запуска важно учитывать внутренние состояния tween:

  • прогресс (progress)
  • текущее время (t)
  • активные задержки (delay)
  • завершённые флаги (isFinished)

Принудительный сброс реализуется через setProgress(0):

timeline.setProgress(0);
timeline.play();

Такой подход используется при сложных композициях, где replay() недостаточно из-за внешних зависимостей состояния.


Управление повторяемостью через repeat

Встроенный механизм циклического воспроизведения задаётся параметром repeat.

const tween = new mojs.Tween({
  duration: 600,
  repeat: 3
});

Поведение:

  • repeat: 0 — однократное выполнение
  • repeat: 3 — три дополнительных повтора после первого запуска
  • repeat: -1 — бесконечный цикл

При каждом цикле выполняется полный пересчёт прогресса от 0 до 1.


Контроль последовательности через callbacks

Для точного управления повтором используются события жизненного цикла:

  • onStart
  • onUpdate
  • onComplete
  • onRepeat
const tween = new mojs.Tween({
  duration: 1000,
  repeat: 2,
  onRepeat: () => {
    console.log('цикл завершён, начинается повтор');
  }
});

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


Перезапуск групп анимаций

Групповые конструкции mojs требуют синхронизации всех дочерних элементов.

const burst = new mojs.Burst({
  radius: { 0: 100 },
  count: 5
});

const timeline = new mojs.Timeline();

timeline.add(burst);

function restart() {
  timeline.stop();
  timeline.setProgress(0);
  timeline.play();
}

Такой подход гарантирует полное восстановление исходного состояния всех вложенных объектов.


Повтор через управление временем

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

timeline.tune({}).setProgress(0.5);
timeline.play();

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

  • начало (0)
  • середина (0.5)
  • конец (1)

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


Комбинирование replay и repeat

replay() и repeat решают разные задачи:

  • replay() — ручной перезапуск
  • repeat — автоматический цикл

Пример комбинированного использования:

const tween = new mojs.Tween({
  duration: 800,
  repeat: 2
});

tween.play();

// внешний перезапуск всей серии
setTimeout(() => {
  tween.replay();
}, 5000);

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


Сброс вложенных состояний при сложных композициях

При работе с несколькими уровнями вложенности (Timeline → Timeline → Tween) возникает необходимость каскадного сброса.

Алгоритм восстановления:

  • остановка верхнего уровня
  • обнуление прогресса
  • последовательный reset вложенных элементов
  • повторный запуск корневого узла
function fullReset(timeline) {
  timeline.stop();
  timeline.setProgress(0);

  timeline.children.forEach(child => {
    child.stop && child.stop();
    child.setProgress && child.setProgress(0);
  });

  timeline.play();
}

Особенности повторения Burst-анимаций

Burst генерирует набор независимых tween-элементов. При повторном запуске важно учитывать:

  • пересоздание частиц
  • сброс радиального распределения
  • восстановление начальной геометрии
const burst = new mojs.Burst({
  count: 8,
  radius: { 0: 120 },
  children: {
    shape: 'circle',
    radius: { 10: 0 }
  }
});

function replayBurst() {
  burst.replay();
}

Каждый повтор приводит к новой генерации внутренних объектов, а не к их реанимации.


Синхронизация повторов между несколькими таймлайнами

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

const t1 = new mojs.Timeline();
const t2 = new mojs.Timeline();

const master = new mojs.Timeline();

master.add(t1, t2);

function restartAll() {
  master.stop();
  master.setProgress(0);
  master.play();
}

Синхронный reset обеспечивает отсутствие рассинхронизации фаз между анимациями.


Повтор с изменением параметров на каждом цикле

Для динамических последовательностей используется модификация состояния в onRepeat:

let radius = 50;

const shape = new mojs.Shape({
  shape: 'circle',
  radius: radius,
  duration: 600,
  repeat: 5,
  onRepeat: () => {
    radius += 10;
    shape.tune({ radius });
  }
});

Каждый цикл изменяет конфигурацию без пересоздания объекта.


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

При длительных циклах важны:

  • предотвращение накопления ошибок интерполяции
  • явный reset прогресса
  • контроль памяти при Burst-генерации
  • минимизация вложенных setTimeout/RAF

Стабильная схема повторения строится на комбинации:

  • stop()
  • setProgress(0)
  • play()

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