Возвращаемые значения и управление анимацией

Вызов animate() в Motion One всегда возвращает объект управления анимацией, через который можно синхронно и асинхронно контролировать жизненный цикл анимации. Этот объект является ключевой точкой взаимодействия между логикой приложения и системой интерполяции значений.

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

import { animate } from "motion";

const controls = animate(
  ".box",
  { opacity: [0, 1], transform: ["translateY(20px)", "translateY(0px)"] },
  { duration: 0.6 }
);

переменная controls содержит набор методов и свойств, позволяющих управлять процессом выполнения анимации.

Основные методы управления

play()

Метод play() запускает или возобновляет анимацию с текущего состояния прогресса.

controls.play();

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


pause()

Метод pause() фиксирует текущее состояние анимации без сброса прогресса.

controls.pause();

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


stop()

stop() завершает анимацию и оставляет элементы в текущем промежуточном состоянии.

controls.stop();

Это отличается от завершения: конечные значения не гарантируются, а текущий стиль фиксируется как итоговый.


finish()

Метод finish() мгновенно переводит анимацию в конечное состояние.

controls.finish();

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


cancel()

cancel() полностью отменяет анимацию и откатывает изменения, если это возможно в рамках движка.

controls.cancel();

В отличие от stop(), данный метод стремится вернуть элемент к исходному состоянию до запуска анимации.


Асинхронное завершение через finished

Каждая анимация содержит промис finished, который резолвится при завершении анимации естественным образом.

const animation = animate(".box", { x: 200 }, { duration: 1 });

animation.finished.then(() => {
  console.log("Анимация завершена");
});

Поведение finished

  • Резолвится при нормальном завершении
  • Не срабатывает при cancel()
  • Может быть использован для последовательных цепочек анимаций

Состояние прогресса и контроль времени

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

playbackRate

controls.playbackRate = 2;

Ускоряет или замедляет анимацию без изменения ключевых кадров.

  • 1 — нормальная скорость
  • 0.5 — замедление в два раза
  • 2 — ускорение в два раза

Изменение скорости применяется мгновенно, без перезапуска анимации.


time и progress (внутренние механизмы)

Хотя напрямую доступ к time и progress зависит от версии, концептуально Motion One оперирует временной шкалой, где:

  • время измеряется в миллисекундах
  • прогресс нормализован в диапазоне от 0 до 1

Это позволяет синхронизировать несколько анимаций между собой или привязывать их к внешним источникам времени (скролл, жесты, Web Audio API).


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

Объект управления можно использовать повторно после остановки.

controls.stop();
controls.play();

Однако важно учитывать различие между состояниями:

  • после stop() анимация остаётся в текущем положении
  • после cancel() требуется повторное создание или сброс состояния
  • после finish() повторный запуск зависит от конфигурации ключевых кадров

Управление через внешние события

Контроллер анимации часто используется как реакция на пользовательские действия.

const controls = animate(".box", { x: 300 }, { duration: 1 });

button.addEventListener("mouseenter", () => {
  controls.play();
});

button.addEventListener("mouseleave", () => {
  controls.reverse();
});

Метод reverse() инвертирует направление воспроизведения, позволяя реализовывать интерактивные эффекты без пересоздания анимации.


Согласование нескольких анимаций

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

const a = animate(".a", { x: 100 }, { duration: 1 });
const b = animate(".b", { x: 200 }, { duration: 1.5 });

a.pause();
b.pause();

a.play();
b.play();

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

const animations = [
  animate(".a", { opacity: 1 }),
  animate(".b", { scale: 1 }),
  animate(".c", { rotate: 45 })
];

animations.forEach(a => a.pause());
animations.forEach(a => a.play());

Динамическое изменение параметров во время выполнения

Motion One позволяет изменять параметры без пересоздания анимации.

controls.speed = 1.5;
controls.playbackRate = 0.8;

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


Интеграция с цепочками анимаций

Контроллеры могут использоваться для последовательного исполнения:

animate(".box", { x: 100 }, { duration: 0.5 }).finished.then(() => {
  return animate(".box", { y: 100 }, { duration: 0.5 }).finished;
});

Такой подход строит цепочку, где каждый следующий этап зависит от завершения предыдущего.


Работа с состояниями жизненного цикла

Анимация в Motion One проходит через несколько логических состояний:

  • инициализация
  • воспроизведение
  • пауза
  • завершение
  • отмена

Контроллер выступает интерфейсом между этими состояниями и кодом приложения.

Пример управления состояниями:

const controls = animate(".box", { opacity: 1 });

if (shouldPause) {
  controls.pause();
}

if (shouldReset) {
  controls.cancel();
}

Повторное проигрывание и циклы

Хотя базовый animate() не всегда предполагает бесконечный цикл, управление позволяет эмулировать повтор:

controls.finished.then(() => {
  controls.play();
});

или через внешнюю логику:

function loop() {
  const anim = animate(".box", { x: 200 }, { duration: 1 });

  anim.finished.then(loop);
}

loop();

Практическая модель управления

В архитектурных решениях объект управления анимацией рассматривается как состояние:

  • хранится в переменной или сторе
  • передаётся между компонентами
  • управляется событиями UI
  • синхронизируется с маршрутизацией или состоянием приложения
let currentAnimation = null;

function start() {
  currentAnimation = animate(".box", { x: 300 });
}

function stop() {
  currentAnimation?.stop();
}

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