Динамические последовательности

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

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


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

  • tween (интерполяция между значениями)
  • spring (физическая модель пружины)
  • decay (затухание скорости)
  • keyframes (набор контрольных точек)

Каждая из этих единиц в 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 представляют собой вычисляемые графы действий, где:

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

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