Framer Motion построен вокруг React-абстракций и декларативных
компонентов. Анимации описываются через motion.div,
variants, animate, initial,
exit, а жизненный цикл синхронизируется с рендером React.
Вся система тесно связана с виртуальным DOM и паттернами React.
Motion One опирается на Web Animations API и императивный API уровня
DOM. Основной механизм — функция animate(), работающая
напрямую с DOM-элементами или CSS-селекторами. Отсутствует слой
React-обёрток, что делает библиотеку универсальной для любых
фронтенд-стеков.
Разница в подходе формирует фундамент миграции:
variants заменяются объектами ключевых кадров или
последовательностямиFramer Motion использует концепцию variants, где состояния описываются как именованные наборы стилей:
const variants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
}
Motion One заменяет эту модель на явное описание ключевых кадров:
import { animate } from "motion"
animate(
element,
{ opacity: [0, 1], transform: ["translateY(20px)", "translateY(0px)"] },
{ duration: 0.4, easing: "ease-out" }
)
Семантика смещается от «состояний» к «интерполяции значений».
Ключевой момент миграции — переход от описания состояний UI к описанию изменения значений во времени.
В Framer Motion базовая единица — компонент:
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
/>
В Motion One отсутствует JSX-слой. Эквивалент строится через ссылку на DOM:
import { animate } from "motion"
const el = document.querySelector(".box")
animate(el, {
opacity: [0, 1]
})
В React-проектах DOM-элемент обычно получают через
ref:
import { useEffect, useRef } from "react"
import { animate } from "motion"
function Box() {
const ref = useRef(null)
useEffect(() => {
animate(ref.current, {
opacity: [0, 1],
transform: ["scale(0.9)", "scale(1)"]
})
}, [])
return <div ref={ref} />
}
Таким образом исчезает слой motion.div, а управление
анимацией переходит в эффекты жизненного цикла.
Framer Motion активно использует каскадные variants:
const list = {
hidden: {},
visible: {
transition: {
staggerChildren: 0.1
}
}
}
В Motion One аналогичная логика реализуется через последовательности и таймлайны.
import { stagger, animate } from "motion"
const items = document.querySelectorAll(".item")
animate(
items,
{ opacity: [0, 1], y: [10, 0] },
{ delay: stagger(0.1) }
)
Система stagger становится функцией, а не частью
декларативного объекта состояния.
Для сложных сценариев используется timeline:
import { timeline } from "motion"
timeline([
[".title", { opacity: [0, 1] }, { duration: 0.3 }],
[".subtitle", { opacity: [0, 1], y: [10, 0] }, { at: "-0.1" }],
[".button", { scale: [0.8, 1] }, { at: 0.2 }]
])
Таймлайн заменяет систему вложенных variants и
родительских контроллеров.
В Framer Motion используется AnimatePresence:
<AnimatePresence>
{show && (
<motion.div exit={{ opacity: 0 }} />
)}
</AnimatePresence>
В Motion One отсутствует виртуальный слой управления удалением DOM. Анимация выхода реализуется вручную:
import { animate } from "motion"
if (!show) {
animate(
el,
{ opacity: [1, 0] },
{
duration: 0.2,
onComplete: () => el.remove()
}
)
}
Контроль жизненного цикла становится явным этапом логики приложения.
Framer Motion предоставляет встроенные абстракции drag,
whileHover, whileTap.
Motion One разделяет поведение на отдельные модули и ручную обработку событий DOM:
let isDragging = false
el.addEventListener("pointerdown", () => {
isDragging = true
})
el.addEventListener("pointermove", (e) => {
if (!isDragging) return
el.style.transform = `translate(${e.clientX}px, ${e.clientY}px)`
})
el.addEventListener("pointerup", () => {
isDragging = false
})
Для анимации возврата используется animate():
animate(el, {
transform: ["translate(300px, 200px)", "translate(0px, 0px)"]
}, { duration: 0.4 })
Framer Motion использует useScroll и
useTransform:
const { scrollYProgress } = useScroll()
В Motion One используется scroll API:
import { scroll } from "motion"
scroll(({ y }) => {
el.style.transform = `translateY(${y * 100}px)`
})
Также возможна привязка прогресса к анимации:
scroll(animate(".progress", {
scaleX: [0, 1]
}))
Framer Motion управляет синхронизацией через React state и props.
Motion One использует явную композицию анимационных задач:
timelineat, delay,
staggerПример параллельного запуска:
animate(".a", { opacity: [0, 1] })
animate(".b", { y: [20, 0] })
Пример синхронизированного запуска:
timeline([
[".a", { opacity: [0, 1] }],
[".b", { opacity: [0, 1] }, { at: 0 }]
])
Framer Motion предоставляет imperative API:
controls.start({ opacity: 1 })
В Motion One управление осуществляется через сохранение экземпляра анимации:
import { animate } from "motion"
const animation = animate(el, { opacity: [0, 1] })
animation.pause()
animation.play()
animation.stop()
Контроллер становится объектом результата, а не отдельной абстракцией.
Framer Motion активно использует объектный стиль:
{ opacity: 1, y: 20 }
Motion One использует массивы для интерполяции:
{ opacity: [0, 1], transform: ["translateY(20px)", "translateY(0px)"] }
Это фундаментальное изменение:
Framer Motion работает через React reconciliation и собственный scheduler. Каждое обновление состояния может приводить к пересчёту анимационных пропсов.
Motion One использует Web Animations API, что даёт:
Миграция часто сопровождается переносом логики из React в DOM-слой, что уменьшает количество ререндеров.
Типичная замена архитектуры выглядит следующим образом:
Framer Motion:
Motion One:
Пример переноса компонента карточки:
<motion.div
whileHover={{ scale: 1.05 }}
animate={{ opacity: 1 }}
/>
Эквивалент:
el.addEventListener("pointerenter", () => {
animate(el, { transform: ["scale(1)", "scale(1.05)"] })
})
el.addEventListener("pointerleave", () => {
animate(el, { transform: ["scale(1.05)", "scale(1)"] })
})
Переход от Framer Motion к Motion One означает смещение от декларативного UI к процедурному управлению анимацией.
Вместо описания «что должно быть» формируется последовательность «что происходит во времени»:
Такой переход особенно заметен в сложных интерфейсах с большим количеством синхронных анимаций, где Motion One обеспечивает более низкоуровневый и контролируемый слой управления движением элементов.