Mapping функций

Преобразование значений как основа анимации

Любая анимация сводится к отображению одного диапазона значений в другой. В простейшем виде это функция, которая принимает прогресс t в диапазоне от 0 до 1 и возвращает вычисленное значение свойства: позицию, прозрачность, масштаб, цвет.

Формально это записывается как:

  • вход: нормализованный прогресс анимации t ∈ [0, 1]
  • выход: значение свойства y

Такое отображение лежит в основе всех механизмов интерполяции в Motion One: keyframes, easing, физические модели и пользовательские трансформации.


Функциональные keyframes

В Motion One ключевым способом задания динамики является возможность использовать функции вместо статических значений.

Анимация перестает быть фиксированным набором точек и превращается в вычисляемую зависимость:

import { animate } from "motion";

animate(element, {
  x: (latest) => latest * 200,
  opacity: (latest) => 1 - latest
});

Здесь latest — нормализованный прогресс, который Motion One передает в функцию. Каждое обновление кадра вычисляет новое значение.

Такой подход позволяет:

  • строить нелинейные зависимости без keyframes
  • комбинировать несколько математических моделей
  • подключать внешние данные (scroll, pointer, time)

Линейное отображение через transform

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

[ f(x) : [a, b] ]

В Motion One это выражается через transform:

import { transform } from "motion";

const map = transform([0, 1], [0, 100]);

map(0.5); // 50

Механика работы

Функция вычисляет относительное положение входного значения в диапазоне:

[ t = ]

И применяет его к выходному диапазону:

[ y = c + t(d - c)]


Нормализация прогресса как базовый слой

Любая анимация в Motion One приводит данные к нормализованной форме. Даже сложные сценарии — скролл, жесты, физика — сводятся к значению progress.

Пример преобразования scroll в диапазон:

const opacity = transform([0, 300], [1, 0]);

window.addEventListener("scroll", () => {
  const value = opacity(window.scrollY);
  element.style.opacity = value;
});

Здесь происходит двойное отображение:

  • пиксели прокрутки → нормализованный прогресс
  • прогресс → визуальное свойство

Композиция mapping-функций

Mapping-функции в Motion One можно комбинировать, формируя цепочки преобразований.

Пример композиции:

import { transform } from "motion";

const scaleMap = transform([0, 1], [1, 1.5]);
const easeMap = (t) => t * t;

const result = (t) => scaleMap(easeMap(t));

Здесь происходит последовательное преобразование:

  1. линейный прогресс
  2. нелинейное ускорение
  3. масштабирование в целевой диапазон

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


Маппинг в keyframes как функция времени

Keyframes в Motion One можно рассматривать как дискретную форму mapping-функции.

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

Внутри происходит:

  • интерполяция между точками
  • вычисление сегмента по прогрессу
  • применение easing к каждому сегменту

Фактически создается кусочно-заданная функция:

[ f(t) = f_1(t) f_2(t) f_3(t)]


Нелинейные mapping-функции

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

Полиномиальные функции

const easeIn = (t) => t * t;
const easeOut = (t) => 1 - Math.pow(1 - t, 2);

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

  • ускорение в начале
  • замедление в конце

Тригонометрические функции

const wave = (t) => Math.sin(t * Math.PI * 2);

Используются для:

  • колебаний
  • циклических движений
  • пульсаций

Mapping цвета через функции

Цветовые значения также могут быть результатом отображения.

import { transform } from "motion";

const colorMap = transform(
  [0, 1],
  ["#ff0000", "#00ff00"]
);

Внутри Motion One происходит интерполяция каналов RGB:

  • разложение цвета
  • линейное отображение каналов
  • сборка итогового значения

Функции на основе времени

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

const rotate = (t) => t * 360;

animate(element, {
  rotate: (latest) => rotate(latest)
});

При этом latest фактически отражает текущий тик анимационного цикла.


Маппинг жестов и pointer input

Входные события мыши или касания также приводятся к нормализованным значениям.

const mapX = transform([0, window.innerWidth], [-1, 1]);

window.addEventListener("pointermove", (e) => {
  const normalized = mapX(e.clientX);
  element.style.transform = `translateX(${normalized * 100}px)`;
});

Такое преобразование используется для:

  • интерактивных интерфейсов
  • параллакса
  • адаптивных эффектов

Функциональные значения в animate API

Motion One поддерживает использование функций как вычисляемых значений свойств.

animate(element, {
  x: (progress, element) => progress * 300 + element.offsetLeft
});

Здесь mapping получает доступ к:

  • прогрессу анимации
  • текущему DOM-элементу

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


Смешивание mapping и физики

Физические модели (spring, inertia) также можно рассматривать как mapping-функции времени.

[ f(t) = (t, x_0, x_1)]

В этом случае отображение становится неявным:

  • вход: время
  • выход: положение, вычисленное физической моделью

Кусочно-линейные преобразования

Иногда требуется комбинировать разные диапазоны:

const map = (t) => {
  if (t < 0.5) return t * 2;
  return 1 - (t - 0.5) * 2;
};

Такие функции создают:

  • зеркальные эффекты
  • возвратные движения
  • сложные траектории

Универсальная модель mapping в Motion One

Все описанные механизмы сводятся к единому принципу:

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

В рамках Motion One mapping-функции выступают универсальным уровнем абстракции между данными и визуальным состоянием, позволяя строить анимации как чистые математические зависимости без жесткой привязки к ключевым кадрам или фиксированным значениям