Path-анимация в контексте Popmotion строится вокруг идеи движения
объекта вдоль заранее заданной кривой. В веб-разработке такие кривые
чаще всего представлены SVG-путями (<path>), которые
описывают сложные траектории через команды линий, кривых Безье и
дуг.
Ключевая особенность SVG-пути заключается в том, что он одновременно является и визуальным элементом, и математическим описанием траектории. Браузер предоставляет API для работы с такими траекториями:
getTotalLength() — возвращает общую длину путиgetPointAtLength(distance) — возвращает координаты
точки на пути по смещениюИменно эта модель становится базой для построения path-анимаций: вместо работы с уравнениями кривых используется параметр длины пути.
Popmotion не навязывает готовую систему path-follow, но предоставляет
инструменты (tween, value,
spring, physics), которые позволяют построить
такую систему вручную через композицию значений.
Любая path-анимация сводится к преобразованию нормализованного
прогресса t ∈ [0, 1] в координаты на пути.
Алгоритм:
Получить SVG-path
Вычислить его длину
На каждом шаге анимации вычислять позицию:
distance = length * tpoint = path.getPointAtLength(distance)Таким образом, траектория становится функцией отображения:
t → (x, y)
Основой выступает value из Popmotion, который позволяет
хранить и обновлять состояние анимации в реальном времени.
import { value, tween } from 'popmotion';
const path = document.querySelector('path');
const box = document.querySelector('.box');
const length = path.getTotalLength();
const motion = value(0, (v) => {
const point = path.getPointAtLength(v * length);
box.style.transform = `translate(${point.x}px, ${point.y}px)`;
});
tween({
from: 0,
to: 1,
duration: 2000,
}).start(motion);
В данной схеме:
tween отвечает за временную интерполяциюvalue обрабатывает каждый кадрtween в Popmotion представляет собой детерминированную
анимацию, основанную на времени. Это делает path-анимацию
воспроизводимой и легко синхронизируемой.
Важные параметры:
duration — длительность движенияease — функция сглаживанияloop — зацикливаниеflip — обратное воспроизведениеПример нелинейного движения:
import { tween, easing } from 'popmotion';
tween({
from: 0,
to: 1,
duration: 3000,
ease: easing.easeInOut,
}).start((v) => {
const point = path.getPointAtLength(v * length);
box.style.transform = `translate(${point.x}px, ${point.y}px)`;
});
Использование easing влияет не на геометрию пути, а на распределение времени вдоль него. Это позволяет создавать эффекты ускорения на прямых участках и замедления на поворотах без изменения самой траектории.
Для реалистичной path-анимации важно учитывать не только позицию, но и ориентацию объекта.
Направление вычисляется через разницу двух близких точек на пути:
const delta = 0.001;
const p1 = path.getPointAtLength(t * length);
const p2 = path.getPointAtLength((t + delta) * length);
const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x);
Применение:
box.style.transform = `
translate(${p1.x}px, ${p1.y}px)
rotate(${angle}rad)
`;
Такой подход позволяет объекту «смотреть» по направлению движения, что критично для симуляции транспорта, частиц или персонажей.
Path-анимация часто используется для распределения множества элементов вдоль одной траектории.
Подход основан на смещении прогресса:
const items = Array.from(document.querySelectorAll('.item'));
tween({
from: 0,
to: 1,
duration: 4000,
}).start((v) => {
items.forEach((item, i) => {
const offset = i * 0.05;
const t = (v + offset) % 1;
const point = path.getPointAtLength(t * length);
item.style.transform = `translate(${point.x}px, ${point.y}px)`;
});
});
Так формируется эффект потока объектов, распределённых по одной траектории.
Вместо tween можно использовать физические модели
Popmotion, такие как spring и physics.
Spring-модель:
import { spring, value } from 'popmotion';
const motion = value(0, (v) => {
const point = path.getPointAtLength(v * length);
box.style.transform = `translate(${point.x}px, ${point.y}px)`;
});
spring({
from: 0,
to: 1,
stiffness: 80,
damping: 20,
}).start(motion);
Особенность такого подхода — отсутствие фиксированного времени. Движение зависит от физической модели, что позволяет имитировать инерцию при старте и остановке.
Physics-модель позволяет управлять скоростью напрямую:
import { physics, value } from 'popmotion';
physics({
velocity: 0.2,
friction: 0.15,
}).start((v) => {
const t = v % 1;
const point = path.getPointAtLength(t * length);
box.style.transform = `translate(${point.x}px, ${point.y}px)`;
});
SVG path может содержать сложные кривые, где равномерное движение по длине визуально выглядит неравномерным. Для компенсации применяются техники ресэмплинга:
Пример предвычисления:
const samples = 200;
const points = [];
for (let i = 0; i <= samples; i++) {
const t = i / samples;
const point = path.getPointAtLength(t * length);
points.push(point);
}
Далее анимация может работать не с SVG API, а с массивом координат, что снижает нагрузку на основной поток.
Popmotion предоставляет трансформационные утилиты, которые позволяют расширять path-анимацию:
Пример комбинирования:
const update = (x, y, angle) => {
box.style.transform = `
translate(${x}px, ${y}px)
rotate(${angle}rad)
scale(1.2)
`;
};
Path становится источником базовой геометрии, а transform-цепочка отвечает за визуальную модификацию.
При интенсивной анимации важно учитывать производительность:
getPointAtLengthrequestAnimationFrame (Popmotion делает
это автоматически)Дополнительно снижение нагрузки достигается переносом вычислений в отдельные структуры данных и уменьшением DOM-операций.
SVG path рассматривается не как визуальный элемент, а как математическая функция.
Каждый кадр — это функция:
state(t) → position → transform
Каждый объект имеет собственный offset, но общий path и timeline.
Сложные сцены используют несколько уровней траекторий:
Комбинация этих уровней позволяет создавать органичное движение без ручной анимации ключевых кадров.
Хотя стандартный подход предполагает равномерное распределение по длине, скорость можно модулировать через ремаппинг прогресса:
Это достигается через кастомные функции интерполяции между
t и distance, заменяющие линейное
масштабирование.