Motion — открытая библиотека анимаций для React, JavaScript и Vue

· 6 мин чтения
animation react frontend typescript open-source
📂 Исходный код на GitHub

Открытая библиотека анимаций для JavaScript, React и Vue (бывший Framer Motion). Гибридный движок, жесты, пружины, анимация раскладки и скролла, готовый скилл и MCP-сервер для ИИ-агентов. Лицензия MIT.

Motion — открытая библиотека анимаций для React, JavaScript и Vue

Motion — это библиотека анимаций с открытым кодом для JavaScript, React и Vue. Раньше она называлась Framer Motion, теперь проект называется Motion, а импорт идёт из motion/react вместо framer-motion. Лицензия — MIT. Установка для React и обычного JavaScript: npm install motion, для Vue нужен отдельный пакет npm install motion-v.

Главная особенность — гибридный движок. Он сначала пробует выполнить анимацию нативными средствами браузера (Web Animations API, ScrollTimeline, CSS-переменные), а когда их не хватает, переключается на JavaScript. За счёт этого проект обещает 120 кадров в секунду и плавные анимации на слабых телефонах. При этом есть готовые жесты, пружины, анимации раскладки, эффекты, связанные со скроллом, и таймлайны.

Почему им пользуются

В README и документации перечислены четыре причины:

  • Простой API. Отдельные пакеты для React, обычного JavaScript и Vue.
  • Гибридный движок. Мощь JavaScript вместе с нативными браузерными API, ускорение на GPU.
  • Готов к продакшену. TypeScript, большая тестовая база, tree shaking, маленький размер пакета.
  • Всё сразу из коробки. Жесты, пружины, анимация раскладки, эффекты, связанные со скроллом, таймлайны.

При этом авторы честно пишут, когда CSS лучше. Для простого локального эффекта вроде смены цвета при наведении обычный CSS-переход легче и понятнее.

Анимирует движок всё, до чего не дотягивается CSS: отдельные оси трансформаций, mask-image, градиенты, CSS-переменные, пути SVG, цвета, строки, числа и обычные JavaScript-объекты. Анимации Framer работают на сайтах, собранных в Framer, а на главной странице Cursor включены анимации Motion.

Минимальный пример на React

Базовый элемент — компонент <motion />. К любому HTML- или SVG-тегу добавляется префикс motion., и сразу появляются пропсы animate, whileHover, exit:

import { motion } from "motion/react"

function Component() {
  return <motion.div animate={{ x: 100 }} />
}

Анимация появления задаётся через initial и animate. Если initial не задать, начальные значения читаются из DOM. Чтобы отключить стартовую анимацию, в initial передают false:

<motion.button initial={{ scale: 0 }} animate={{ scale: 1 }} />
<motion.button initial={false} animate={{ scale: 1 }} />

Жесты работают как отдельные пропсы: наведение, нажатие, фокус и перетаскивание:

<motion.button
  whileHover={{ scale: 1.1 }}
  whileTap={{ scale: 0.95 }}
  onHoverStart={() => console.log('hover started!')}
/>

Значения по умолчанию выбраны по физике. Свойства x и scale по умолчанию анимируются через пружину, а визуальные свойства вроде opacity — через смягчение (tween). Тип, длительность, функцию смягчения и задержку переопределяют через пропс transition.

Скролл, раскладка и исчезновение

Три возможности, которых нет в CSS, разобраны в отдельных разделах документации.

Скролл бывает двух видов. Первый запускает анимацию, когда элемент попал в экран, — это пропс whileInView. Второй привязывает значение прямо к позиции скролла через MotionValue и хук useScroll:

const { scrollYProgress } = useScroll()

return <motion.div style={{ scaleX: scrollYProgress }} />

Анимация раскладки ловит изменение размера, позиции или порядка элементов и плавно переезжает между состояниями через трансформации. В отличие от обычной техники FLIP, движок учитывает и искажение от масштаба. Включается одним пропсом:

<motion.div layout />

Чтобы плавно переключаться между разными элементами, используют общий layoutId:

<motion.div layoutId="underline" />

Анимация исчезновения требует обёртки <AnimatePresence> из react-animate-presence. Она даёт доступ к пропсу exit:

<AnimatePresence>
  {show ? <motion.div key="box" exit={{ opacity: 0 }} /> : null}
</AnimatePresence>

SVG поддержан полностью, включая анимацию viewBox и рисование линий через pathLength:

<motion.circle animate={{ pathLength: 1 }} />

animate() для обычного JavaScript

Для проектов без React есть функция animate(). Она существует в двух размерах: mini весит 2,3 КБ, hybrid — 18 КБ. Mini умеет только стили HTML и SVG через нативные API браузера. Hybrid добавляет независимые трансформации, CSS-переменные, пути SVG, последовательности анимаций, цвета, числа и объекты JavaScript.

// Hybrid
import { animate } from "motion"

// Mini
import { animate } from "motion/mini"

animate("#box", { opacity: 0 })

Первым аргументом передают элемент или CSS-селектор, вторым — конечные значения, третьим — параметры перехода:

animate("div", { opacity: 0 }, { duration: 0.5 })
animate("div", { rotate: 360 })
animate("circle", { pathLength: [0, 1] })

Последовательности собирают в массив. По умолчанию шаги идут один за другим, а опция at двигает момент запуска. Время можно задать числом, меткой, знаком < (начало предыдущего шага) или строкой вида +0.5 (относительно конца предыдущего):

const sequence = [
  ["nav", { opacity: 1 }],
  ["li", { opacity: 1 }, { at: "<" }],
  ["nav", { x: 100 }, { at: "+0.5" }]
]

animate(sequence, { repeat: 2 })

Для списков есть функция stagger, которая растягивает задержку между элементами:

import { stagger, animate } from "motion"

animate(".item", { x: 300 }, { delay: stagger(0.1) })

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

animate("#fff", "#000", { duration: 2, onUpdate: latest => console.log(latest) })

const values = { x: 100, color: "#f00" }
const animation = animate(values, { x: 200, color: "#00f" })

await animation.finished
console.log(values.x) // 200

Функция animate() возвращает управление воспроизведением. Через него ставят паузу, меняют скорость, проматывают время вручную и отменяют анимацию:

const animation = animate(element, { opacity: 1 })

animation.time = 0.5
animation.speed = 2
animation.pause()
animation.play()
animation.cancel()
animation.stop()

По умолчанию duration равен 0,3 секунды, а если задано несколько ключевых кадров — 0,8 секунды. У пружины есть параметры stiffness, damping, mass и velocity, а у duration-варианта пружины — bounce и visualDuration. Если задать stiffness, damping или mass, то bounce и duration перезаписываются.

Возможности для ИИ-агентов

Отдельная часть README посвящена работе с агентами. Команда npx motion-ai ставит бесплатный MIT-скилл /motion и настраивает MCP-серверы Motion для Claude Code, Cursor, Amp, OpenCode, Gemini CLI и Copilot. Исходники лежат в репозитории ai-kit.

MCP-сервер доступен по адресу mcp.motion.dev. Он ищет по документации Motion и по метаданным примеров, работает бесплатно и не требует аккаунта. Для агентов есть и файл llms.txt — он перечисляет все страницы документации.

Платная подписка Motion+ добавляет исходники примеров и компонентов Motion UI, аудит производительности MotionScore, генерацию CSS-пружин, редактор переходов для Cursor и VS Code, закрытый Discord и ранний доступ. Визуальный редактор Motion Studio позволяет править ключевые кадры, кривые смягчения и пружины на живой шкале времени, а затем переносить результат прямо в код.

Документация и примеры

Документация разделена по платформам: React, JavaScript и Vue, а также есть разделы по Svelte, Three.js и vgpu. Отдельно лежит сравнение с GSAP.

На сайте собрано больше 450 официальных примеров с готовым кодом, а у 110 из них на странице есть пошаговое руководство. Вклад в проект описан в CONTRIBUTING.md.

Источник: https://github.com/motiondivision/motion