Синтаксис объявления keyframes

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

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

На уровне API animate ключевые кадры передаются вторым аргументом:

import { animate } from "motion"

animate(element, {
  x: [0, 200]
})

В этом случае библиотека автоматически интерполирует значение x от 0 до 200.

Расширенная форма включает несколько промежуточных состояний:

animate(element, {
  x: [0, 200, 100]
})

Здесь движение происходит от 0 к 200, затем возврат к 100.

Множественные свойства в keyframes

Каждое анимируемое свойство может иметь собственный набор ключевых кадров. Синхронизация выполняется по индексу массива.

animate(element, {
  x: [0, 200, 100],
  opacity: [0, 1, 0.5]
})
  • первый кадр: x = 0, opacity = 0
  • второй кадр: x = 200, opacity = 1
  • третий кадр: x = 100, opacity = 0.5

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

Объектная форма keyframes

Помимо массивов допускается объектная форма, где каждый кадр задаётся явно через набор объектов:

animate(element, {
  keyframes: [
    { x: 0, opacity: 0 },
    { x: 200, opacity: 1 },
    { x: 100, opacity: 0.5 }
  ]
})

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

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

В Motion One поддерживается управление временной шкалой через свойство offset. Оно позволяет привязывать ключевые кадры к конкретным моментам анимации в диапазоне от 0 до 1.

animate(element, {
  x: [0, 200, 100],
  offset: [0, 0.7, 1]
})

В данном случае:

  • 0 соответствует началу анимации
  • 0.7 задаёт положение второго кадра
  • 1 завершает цикл

Использование offset обеспечивает точное распределение ключевых кадров независимо от их количества.

Ключевые кадры с объектами и явными значениями

Объектный стиль с offset позволяет комбинировать значения более явно:

animate(element, {
  keyframes: [
    { x: 0, opacity: 0, offset: 0 },
    { x: 200, opacity: 1, offset: 0.5 },
    { x: 100, opacity: 0.2, offset: 1 }
  ]
})

Такая форма объединяет декларацию состояния и временную позицию в одном объекте.

Ключевые кадры для сложных transform-свойств

В Motion One трансформации могут задаваться как отдельными свойствами или как строка transform.

Раздельные трансформации

animate(element, {
  x: [0, 100, 50],
  rotate: [0, 180, 90],
  scale: [1, 1.5, 1]
})

Каждая трансформация интерполируется независимо, но синхронизированно по ключевым кадрам.

Комплексная форма transform

animate(element, {
  transform: [
    "translateX(0px) rotate(0deg)",
    "translateX(100px) rotate(180deg)",
    "translateX(50px) rotate(90deg)"
  ]
})

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

Автоматическая интерполяция типов значений

Ключевые кадры в Motion One поддерживают различные типы значений:

  • числа: 0 → 100
  • единицы длины: px, %, rem
  • цвета: rgba, hex, hsl
  • углы: deg, rad
animate(element, {
  backgroundColor: ["#000000", "#ff0000", "#00ff00"],
  rotate: ["0deg", "180deg", "360deg"],
  x: ["0px", "200px", "50px"]
})

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

Ключевые кадры как функция

Вместо статического массива допускается использование функции, возвращающей набор keyframes. Такой подход применяется при динамической генерации анимаций.

animate(element, (progress) => ({
  x: [0, progress * 300, 100]
}))

Функциональная форма используется при необходимости привязки анимации к внешним данным или состоянию.

Нормализация длины массивов

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

animate(element, {
  x: [0, 100],
  opacity: [0, 1, 0.5, 0.2]
})

В этом случае временная шкала автоматически растягивается, чтобы все значения были учтены без потери синхронизации.

Комбинирование keyframes с easing

Хотя easing задаётся на уровне опций, его влияние распространяется на весь набор ключевых кадров:

animate(element, {
  x: [0, 300, 150]
}, {
  easing: "ease-in-out",
  duration: 2
})

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

Поведение при циклических анимациях

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

animate(element, {
  x: [0, 200, 0]
}, {
  repeat: Infinity
})

Последний кадр может совпадать с первым для обеспечения плавного цикла без скачков значений.

Особенности интерполяции массива keyframes

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

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

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