Структура и архитектура Popmotion

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

В основе Popmotion лежит функциональный подход. Вместо классовой иерархии используется набор чистых функций, возвращающих либо поток значений, либо управляющую сущность (action).

Ключевая особенность архитектуры заключается в том, что:

  • каждая анимация — это функция, а не объект с методами
  • состояние не инкапсулируется внутри экземпляров классов
  • управление осуществляется через композицию функций

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

Action как базовая абстракция

Центральное понятие архитектуры — action. Action представляет собой исполняемый поток, который:

  • запускается
  • обновляет значения во времени
  • может быть остановлен
  • может быть скомбинирован с другими action

Любая анимация в Popmotion является action или производной от него.

Типичная модель action:

  • start() — инициализация выполнения
  • stop() — остановка
  • pipe() — передача данных дальше по цепочке
  • transform() — изменение выходных значений

Action можно рассматривать как минимальную единицу вычисления анимации, аналог «наблюдаемого потока», но без строгого соответствия RxJS.

Значения как поток (Value pipeline)

Вместо прямого изменения DOM или состояния объекта Popmotion оперирует значениями, которые проходят через цепочку преобразований.

Каждое значение:

  • генерируется источником (tween, physics, spring)
  • проходит через трансформеры
  • поступает в sink (например, стиль элемента)

Архитектурно это выглядит как однонаправленный поток:

Source → Transform → Sink

Такой подход делает систему предсказуемой и тестируемой, поскольку каждое звено цепочки изолировано.

Tween и временная модель

Tween в Popmotion — это временной интерполятор, работающий на основе:

  • начального значения
  • конечного значения
  • длительности
  • функции easing

В архитектуре tween не является отдельной системой анимации, а лишь одним из источников значений.

Временная модель построена вокруг:

  • requestAnimationFrame как базового тика
  • нормализованного времени (0 → 1)
  • функции прогресса

Tween превращает время в значение через функцию интерполяции, не зная ничего о DOM или рендеринге.

Physics-движок как независимый слой

Одним из ключевых архитектурных решений является отделение физики от временной модели.

Physics-based animation включает:

  • пружины (spring)
  • инерцию (inertia)
  • гравитационные модели (упрощённые)

Физический движок Popmotion работает не с временем, а с состоянием системы:

  • скорость
  • ускорение
  • сопротивление
  • сила возврата

Это создаёт отдельный класс action, где входом является текущее состояние, а выходом — обновлённое состояние.

Архитектурно physics-слой не зависит от tween-слоя, что позволяет смешивать их через композицию.

Компонентная композиция через pipe

Механизм pipe является фундаментальным для архитектуры Popmotion.

Pipe выполняет:

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

Структура pipeline:

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

Каждая функция в цепочке:

  • не имеет состояния
  • не знает о предыдущих или следующих шагах
  • выполняет одно преобразование

Это позволяет строить сложные анимации из простых математических операций.

Transformers как слой чистых функций

Transformers — это чистые функции преобразования значений:

  • нормализация диапазона
  • инверсия
  • clamp
  • easing
  • интерполяция

Они отделены от источников данных и от механизмов исполнения.

Архитектурное значение transformers:

  • они полностью статeless
  • легко тестируются
  • могут комбинироваться без ограничений

Фактически Popmotion разделяет «генерацию» и «обработку» данных.

Управление временем через scheduler

Scheduler в Popmotion отвечает за синхронизацию всех action.

Он выполняет:

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

Scheduler использует requestAnimationFrame как базовый механизм, но логически отделён от конкретных анимаций.

Это позволяет:

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

Композиция actions

Одна из сильных сторон архитектуры — возможность композиции.

Actions можно:

  • объединять последовательно
  • запускать параллельно
  • переключать условно
  • останавливать независимо

Типы композиции:

  • sequence — выполнение по порядку
  • parallel — одновременное выполнение
  • chain — передача результата следующему action

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

Абстракция render-слоя

Popmotion сознательно отделяет анимационную логику от рендеринга.

Render layer:

  • не является частью core
  • подключается через sink-функции
  • может быть DOM, canvas или любой другой системой

Пример архитектурного принципа:

  • core генерирует числа
  • render слой интерпретирует их

Это делает Popmotion независимым от UI-фреймворков.

Иммутабельность потоков

Потоки значений в Popmotion не мутируют состояние.

Каждый новый кадр:

  • создаётся новое значение
  • передаётся дальше по цепочке
  • старое значение не изменяется

Это уменьшает количество побочных эффектов и делает поведение анимации детерминированным.

Разделение ответственности между уровнями

Архитектура Popmotion можно разделить на несколько слоёв:

1. Source layer

  • tween
  • spring
  • inertia
  • keyframes

2. Transformation layer

  • pipe
  • easing
  • mapping функций

3. Execution layer

  • action
  • scheduler

4. Output layer

  • DOM updates
  • canvas rendering
  • пользовательские эффекты

Каждый слой не зависит от конкретной реализации другого.

Реактивная модель исполнения

Popmotion реализует упрощённую реактивную модель:

  • источник генерирует значения
  • значения проходят через цепочку
  • подписчик получает результат

Но в отличие от классических reactive libraries, Popmotion не строит сложный graph зависимостей. Потоки остаются линейными и предсказуемыми.

Минимизация глобального состояния

Архитектура намеренно избегает:

  • глобальных singleton-объектов состояния
  • централизованного store
  • скрытых зависимостей

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

Расширяемость через композицию функций

Расширение Popmotion не требует изменения ядра.

Новые возможности создаются через:

  • добавление новых transformers
  • создание новых source actions
  • комбинирование существующих блоков

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

Синхронизация и управление кадрами

Popmotion опирается на frame-based execution:

  • каждый кадр обновляет все активные action
  • время нормализуется относительно предыдущего кадра
  • отсутствует фиксированная частота обновлений

Это обеспечивает плавность и адаптивность под производительность устройства.

Изоляция побочных эффектов

Все взаимодействие с внешним миром происходит на уровне sink-функций.

Core библиотека:

  • не знает о DOM
  • не знает о React или других фреймворках
  • не выполняет прямых побочных эффектов

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

Архитектурная роль easing-функций

Easing-функции являются математическим слоем поверх временной модели.

Они:

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

Easing интегрируется в pipeline как обычный transformer, а не как часть tween-логики.

Модель прерываемости (interruptibility)

Каждый action может быть прерван в любой момент.

Это достигается за счёт:

  • отсутствия блокирующих операций
  • контроля исполнения через scheduler
  • независимости состояния каждого action

Прерывание не ломает pipeline, так как значения не сохраняются глобально.

Итоговая архитектурная модель

Popmotion можно описать как систему, в которой:

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

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