Popmotion строит анимации как композицию независимых потоков значений, где каждое движение рассматривается как функция во времени. Динамические последовательности в этом подходе — способ объединять несколько анимационных действий в гибкую, изменяемую структуру, которая может формироваться на лету, реагировать на состояние приложения и изменять порядок исполнения без жесткой привязки к фиксированному сценарию.
Popmotion предоставляет примитивы, которые позволяют рассматривать анимацию как данные: массивы действий, функции преобразования и композиции могут комбинироваться так же, как обычные структуры управления в языке программирования. Это делает последовательности не статическим набором шагов, а вычисляемой системой.
Любая динамическая последовательность строится из базовых анимационных единиц:
Каждая из этих единиц в Popmotion является “action” — объектом, который можно запускать, останавливать, комбинировать.
Сама последовательность формируется как комбинация таких действий:
import { tween, spring, sequence } from 'popmotion';
const animation = sequence([
tween({ from: 0, to: 100, duration: 300 }),
spring({ from: 100, to: 50, stiffness: 200 }),
tween({ from: 50, to: 200, duration: 500 })
]);
Последовательность здесь представляет линейное выполнение, где следующий шаг начинается только после завершения предыдущего. Однако ключевая особенность заключается в том, что каждый элемент может быть вычислен в момент запуска, а не заранее.
В отличие от статически заданных сценариев, последовательности могут создаваться программно. Это позволяет учитывать состояние приложения, пользовательский ввод или внешние данные.
const createSequence = (values) => {
return sequence(
values.map((v, index) =>
tween({
from: index === 0 ? 0 : values[index - 1],
to: v,
duration: 200 + index * 50
})
)
);
};
Здесь структура анимации зависит от массива values.
Последовательность становится функцией от данных, а не фиксированным
набором шагов.
Динамика проявляется не только в генерации шагов, но и в изменении логики исполнения. Последовательности могут содержать условные переходы, формируя разные траектории анимации.
import { tween, sequence } from 'popmotion';
const createConditionalSequence = (isActive) =>
isActive
? sequence([
tween({ from: 0, to: 100, duration: 300 }),
tween({ from: 100, to: 200, duration: 300 })
])
: sequence([
tween({ from: 0, to: 50, duration: 200 }),
tween({ from: 50, to: 0, duration: 200 })
]);
Логика перестает быть частью анимации и становится частью построения графа действий.
Последовательности могут содержать другие последовательности, формируя иерархические структуры исполнения. Это позволяет моделировать сложные сцены анимации, где группы объектов движутся согласованно.
const childSequence = sequence([
tween({ from: 0, to: 100, duration: 300 }),
spring({ from: 100, to: 80, stiffness: 150 })
]);
const mainSequence = sequence([
childSequence,
tween({ from: 80, to: 200, duration: 400 })
]);
Вложенность позволяет переиспользовать анимационные блоки как функции, но в терминах временного исполнения.
Важной характеристикой последовательностей является возможность изменения временных параметров во время построения.
const buildSequence = (baseDuration, steps) =>
sequence(
steps.map((step, i) =>
tween({
from: step.from,
to: step.to,
duration: baseDuration * (i + 1)
})
)
);
Здесь длительность каждого шага зависит от позиции в структуре. Таким образом, временная ось становится вычисляемой величиной.
Часто последовательности строятся из внешних данных: координат, состояний UI, сеток или анимационных сценариев.
const points = [0, 20, 80, 40, 120];
const pathSequence = sequence(
points.map((point, i) =>
tween({
from: i === 0 ? 0 : points[i - 1],
to: point,
duration: 150
})
)
);
Такая модель позволяет превращать любую числовую структуру в анимационный маршрут.
Хотя последовательности по определению линейны, их можно комбинировать с параллельными действиями, создавая гибридные структуры.
import { parallel, tween, sequence } from 'popmotion';
const animation = sequence([
parallel([
tween({ from: 0, to: 100, duration: 500 }),
tween({ from: 50, to: 150, duration: 500 })
]),
tween({ from: 100, to: 0, duration: 300 })
]);
Параллельные блоки внутри последовательности позволяют моделировать сложные сцены, где несколько параметров изменяются одновременно.
Динамические последовательности могут быть не только сгенерированы, но и изменены до запуска или даже во время исполнения через внешние триггеры.
let steps = [0, 50, 100];
const build = () =>
sequence(
steps.map((v, i) =>
tween({
from: i === 0 ? 0 : steps[i - 1],
to: v,
duration: 200
})
)
);
steps.push(150);
const updatedAnimation = build();
Таким образом структура анимации отделяется от момента ее исполнения, позволяя изменять сценарий без пересоздания всей системы.
Последовательности могут включать функции, возвращающие действия. Это добавляет уровень ленивой композиции.
const dynamicStep = (value) =>
tween({
from: 0,
to: value,
duration: value * 2
});
const sequenceWithFunctions = sequence([
() => dynamicStep(50),
() => dynamicStep(100),
() => dynamicStep(30)
]);
Функции позволяют откладывать вычисление анимации до момента исполнения конкретного шага.
Динамические последовательности часто связываются с состоянием приложения. Изменение состояния приводит к пересборке графа анимаций.
const state = {
progress: 0,
speed: 1
};
const buildSequenceFromState = (state) =>
sequence([
tween({
from: 0,
to: 100 * state.speed,
duration: 300 / state.speed
}),
tween({
from: 100 * state.speed,
to: 0,
duration: 200
})
]);
Зависимость от состояния превращает последовательность в реактивный объект.
Порядок шагов может определяться не кодом, а данными, что делает систему анимаций конфигурируемой.
const config = [
{ type: 'tween', to: 100, duration: 300 },
{ type: 'spring', to: 50 },
{ type: 'tween', to: 200, duration: 400 }
];
const buildFromConfig = (cfg) =>
sequence(
cfg.map((item) => {
if (item.type === 'tween') {
return tween({ from: 0, to: item.to, duration: item.duration });
}
return spring({ from: 0, to: item.to });
})
);
Такой подход превращает анимации в декларативную систему, где сценарий может приходить извне.
Динамические последовательности часто используются как часть более крупных систем оркестрации анимаций, где несколько последовательностей запускаются с разными задержками и синхронизацией.
const intro = sequence([
tween({ from: 0, to: 100, duration: 300 }),
tween({ from: 100, to: 200, duration: 300 })
]);
const outro = sequence([
tween({ from: 200, to: 100, duration: 200 }),
tween({ from: 100, to: 0, duration: 200 })
]);
const full = sequence([
intro,
tween({ from: 200, to: 200, duration: 500 }),
outro
]);
Такая структура позволяет формировать сложные сценарии без потери модульности.
Последовательности в Popmotion представляют собой вычисляемые графы действий, где:
Это превращает анимацию из линейного процесса в программируемую систему, где временные зависимости становятся частью логики приложения, а не фиксированным сценарием исполнения.