Переход с Anime.js

Архитектура Motion One отличается минимализмом и опорой на нативные Web Animations API, что напрямую влияет на способ переноса логики из Anime.js. В отличие от Anime.js, где анимация строится через централизованный движок и объектную конфигурацию с собственным интерпретатором ключевых кадров, Motion One работает поверх браузерного слоя анимаций, делая основной упор на декларативные вызовы и прямое управление эффектами.

Ключевое различие заключается в модели исполнения: Anime.js создаёт внутренний таймлайн и обновляет свойства через requestAnimationFrame, тогда как Motion One делегирует большую часть работы браузеру, оставляя библиотеке роль координатора параметров.


В Anime.js базовая анимация обычно описывается через функцию anime:

anime({
  targets: '.box',
  translateX: 250,
  opacity: 0.5,
  duration: 800,
  easing: 'easeInOutQuad'
});

Эквивалент в Motion One строится через функцию animate:

import { animate } from "motion";

animate(
  ".box",
  {
    x: 250,
    opacity: 0.5
  },
  {
    duration: 0.8,
    easing: "ease-in-out"
  }
);

Основные отличия проявляются в нескольких деталях:

  • единицы времени выражаются в секундах, а не миллисекундах
  • трансформации разделены на логические свойства (x, y, scale), а не строковые transform-цепочки
  • селектор передаётся напрямую, без обязательной обёртки в targets

Ключевые кадры и переходные состояния

Anime.js активно использует массивы keyframes:

anime({
  targets: ".box",
  translateX: [0, 100, 200],
  opacity: [1, 0.5, 1],
  duration: 1200
});

В Motion One ключевые кадры выражаются через массив значений:

animate(
  ".box",
  {
    x: [0, 100, 200],
    opacity: [1, 0.5, 1]
  },
  {
    duration: 1.2
  }
);

Различие заключается в том, что Motion One интерпретирует массивы как часть Web Animations Keyframes без промежуточного преобразования в собственный формат. Это уменьшает слой абстракции и делает поведение более предсказуемым при сложных анимациях.


Таймлайны и композиция анимаций

В Anime.js используется объект timeline:

const tl = anime.timeline();

tl.add({
  targets: ".box",
  translateX: 100,
  duration: 500
}).add({
  targets: ".box",
  translateY: 100,
  duration: 500
});

В Motion One композиция строится через timeline:

import { timeline } from "motion";

timeline([
  [".box", { x: 100 }, { duration: 0.5 }],
  [".box", { y: 100 }, { duration: 0.5 }]
]);

Здесь наблюдается сдвиг парадигмы:

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

Единицы измерения и трансформации

Anime.js оперирует строковыми значениями трансформаций:

translateX: "100px"

Motion One разделяет числовые значения и единицы автоматически:

x: 100

Система преобразования встроена в библиотеку и учитывает тип свойства:

  • трансформации (x, y, rotate, scale) работают без единиц
  • свойства стилей, требующие единиц, могут задаваться числом или строкой
  • цветовые значения поддерживаются в стандартных CSS-форматах

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


Управление easing-функциями

Anime.js использует строковые идентификаторы:

easing: "easeOutExpo"

Motion One поддерживает как строки, так и функции:

easing: "ease-out"

или

import { spring } from "motion";

animate(".box", {
  x: 200
}, {
  easing: spring()
});

Поддержка физических моделей, таких как spring, делает Motion One ближе к системам анимации UI уровня iOS и современных дизайн-систем.


Задержки и последовательности

Anime.js:

anime({
  targets: ".item",
  translateY: 50,
  delay: anime.stagger(100)
});

Motion One:

import { stagger, animate } from "motion";

animate(
  ".item",
  { y: 50 },
  {
    delay: stagger(0.1)
  }
);

Существенное отличие заключается в единицах времени: в Motion One задержки выражаются в секундах, что сохраняет консистентность всей временной модели библиотеки.


Управление жизненным циклом анимации

Anime.js возвращает объект анимации с методами управления:

const anim = anime({ ... });

anim.pause();
anim.play();
anim.seek(500);

Motion One возвращает controls-объект:

import { animate } from "motion";

const controls = animate(".box", { x: 100 });

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

Дополнительно поддерживается подписка на прогресс:

controls.on("update", latest => {
  console.log(latest);
});

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


Scroll и триггеры появления

Anime.js требует сторонних решений для работы со скроллом. Motion One включает встроенные утилиты.

import { inView } from "motion";

inView(".box", ({ target }) => {
  animate(target, { opacity: 1, y: 0 });
});

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


Переход от CSS-подобных строк к структурированным свойствам

Anime.js часто использует строковые значения transform:

translate: "100px 50px"

Motion One разделяет координаты:

x: 100,
y: 50

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


Обработка сложных сцен анимации

При миграции многошаговых сценариев из Anime.js структура обычно разбивается на независимые вызовы animate или массивы timeline.

Anime.js:

anime({
  targets: ".box",
  translateX: 100,
  opacity: 0,
  duration: 600,
  delay: 200
});

Motion One:

animate(
  ".box",
  { x: 100, opacity: 0 },
  {
    duration: 0.6,
    delay: 0.2
  }
);

Сложные сценарии часто декомпозируются:

timeline([
  [".box", { x: 100 }, { duration: 0.4 }],
  [".box", { opacity: 0 }, { duration: 0.2 }]
]);

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

Anime.js выполняет вычисления анимаций через собственный цикл обновления, что даёт гибкость, но увеличивает нагрузку при большом количестве элементов.

Motion One делегирует интерполяцию браузеру:

  • используется GPU-ускорение через Web Animations API
  • минимизируется JavaScript-логика на кадр
  • снижается overhead при массовых анимациях

Это особенно заметно при анимации списков, сеток и интерфейсных переходов с большим количеством DOM-узлов.


Итоговые сопоставления паттернов миграции

Anime.js Motion One
targets селектор или элемент
translateX x
translateY y
duration: 1000 duration: 1
easing: "easeOut" "ease-out" или функция
anime.timeline() timeline([...])
anime.stagger() stagger()

Работа с состоянием и повторным запуском

Anime.js часто использует повторные инстансы анимаций или reset через параметры.

Motion One позволяет повторно использовать controls:

const controls = animate(".box", { x: 100 });

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

Поведение становится более линейным: анимация рассматривается как управляемый процесс, а не одноразовый запуск конфигурации.


Преобразование архитектуры проектов

При переносе крупных проектов наблюдается типовая структурная трансформация:

  • централизованные конфигурации Anime.js заменяются локальными вызовами animate
  • таймлайны переходят в массивные декларации timeline
  • кастомные easing-функции заменяются встроенными или spring-моделями
  • управление DOM-селекторами становится более прямым и менее абстрактным

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