Расширение системы действий Popmotion опирается на идею унифицированных потоков значений, где любая анимация, физическая модель или пользовательская логика представляется как action. Внутренняя архитектура построена вокруг композиции небольших функций, которые можно соединять, преобразовывать и переиспользовать без привязки к конкретному типу анимации.
В основе лежит контракт действия: объект, который можно запустить, подписаться на его значения и остановить. Любое расширение Popmotion фактически создаёт новый тип действия, совместимый с системой исполнения.
Ключевые элементы:
Любая кастомизация API сводится к созданию новой реализации этого контракта или модификации существующих потоков.
Popmotion предоставляет фабричный подход для создания собственных actions. Это позволяет интегрировать любую логику: от сетевых событий до сложных вычислительных моделей.
Типовой паттерн построения:
import { action } from 'popmotion';
const customAction = (config) => {
return action(({ update, complete }) => {
let count = 0;
const interval = setInterval(() => {
count += 1;
upd ate(count);
if (count >= config.max) {
clearInterval(interval);
complete();
}
}, config.delay);
return {
stop: () => clearInterval(interval)
};
});
};
Такая структура демонстрирует фундаментальный принцип: любое поведение превращается в поток обновлений.
Композиция является основным механизмом расширения функциональности без изменения исходных действий. Popmotion использует подход функциональных цепочек, где выход одного действия становится входом другого.
Основные операторы композиции:
pipe — последовательное преобразование значенийmap — трансформация каждого значенияfilter — фильтрация потокаmerge — объединение нескольких потоковПример композиции:
import { pipe, transform } from 'popmotion';
const scaleAndClamp = pipe(
transform.map(v => v * 2),
transform.clamp(0, 100)
);
Композиционный подход исключает необходимость создания сложных монолитных анимационных объектов, заменяя их цепочками простых функций.
Transformers представляют собой чистые функции, изменяющие поток данных без побочных эффектов. Они служат базовым механизмом адаптации значений между различными действиями.
Основные виды трансформаций:
Пример пользовательского трансформера:
const invert = v => 1 - v;
const normalizeRange = (min, max) => v =>
(v - min) / (max - min);
Такие функции легко подключаются к любому action, создавая гибкую систему адаптации данных.
Easing в Popmotion рассматривается как функция преобразования прогресса анимации. Расширение easing API заключается в создании собственных математических моделей поведения времени.
Стандартная форма:
const customEase = t => t * t * (3 - 2 * t);
Расширенные варианты используют составные функции:
const elasticEase = t => {
const p = 0.3;
return Math.pow(2, -10 * t) *
Math.sin((t - p / 4) * (2 * Math.PI) / p) + 1;
};
Easing-функции легко комбинируются через композицию, формируя новые временные кривые без изменения ядра библиотеки.
Popmotion включает физические модели (spring, decay), которые также могут быть модифицированы или заменены.
Расширение spring-модели обычно происходит через изменение параметров жесткости, демпфирования и массы:
spring({
stiffness: 200,
damping: 20,
mass: 1.5
});
Построение собственной физической модели возможно через реализацию интеграционного шага:
const customPhysics = ({ velocity, friction }) =>
action(({ update, complete }) => {
let v = velocity;
let x = 0;
const step = () => {
v *= friction;
x += v;
update(x);
if (Math.abs(v) < 0.01) complete();
else requestAnimationFrame(step);
};
step();
});
Такой подход позволяет заменять стандартные модели полностью, не нарушая интерфейс системы.
Одним из ключевых механизмов расширения является подключение внешних источников данных как потоков. Любое событие может быть преобразовано в action.
Примеры источников:
Пример интеграции события мыши:
const mouseMoveAction = () =>
action(({ update }) => {
const handler = e => update({ x: e.clientX, y: e.clientY });
window.addEventListener('mousemove', handler);
return {
stop: () => window.removeEventListener('mousemove', handler)
};
});
Таким образом API расширяется за счёт превращения внешнего мира в поток значений.
Actions в Popmotion могут быть преобразованы в другие actions. Это создаёт слой мета-расширения, где поведение одного действия модифицируется другим.
Пример обёртки:
const withThreshold = (threshold, actionFactory) =>
(...args) =>
action(({ update, complete }) => {
let started = false;
const child = actionFactory(...args);
const subscription = child.start({
update: v => {
if (v > threshold) started = true;
if (started) update(v);
},
complete
});
return {
stop: subscription.stop
};
});
Такой подход позволяет строить middleware-подобные системы поверх базовых действий.
Фабрики действий являются основным способом масштабирования API без изменения ядра. Они позволяют инкапсулировать сложную логику создания потоков.
Типовая структура фабрики:
const createSequencedAction = actions =>
action(({ update, complete }) => {
let index = 0;
const runNext = () => {
if (index >= actions.length) {
complete();
return;
}
actions[index++].start({
update,
complete: runNext
});
};
runNext();
});
Фабрики формируют уровень абстракции, позволяющий собирать сложные анимационные сценарии из простых блоков.
Value layer отвечает за хранение и распространение текущего состояния анимации. Расширение этого слоя позволяет подключать реактивные модели обновления.
Типовые расширения:
Пример синхронизации:
const syncValues = (a, b) =>
a.subscribe(v => b.se t(v));
Эта модель превращает Popmotion в основу для реактивных систем управления состоянием.
Расширение API часто реализуется через wrapping существующих actions. Обёртка позволяет модифицировать поток без изменения исходной логики.
Пример логирования:
const withLogger = actionFactory =>
(...args) =>
action(({ update, complete }) => {
const child = actionFactory(...args);
return child.start({
update: v => {
console.log(v);
update(v);
},
complete
});
});
Такой подход создаёт слой наблюдаемости над любым действием.
Расширения Popmotion логически группируются в независимые модули:
Каждый модуль не зависит от конкретного типа анимации и может использоваться отдельно или в комбинации с другими.
Все расширения Popmotion объединяются общей моделью исполнения: поток значений проходит через цепочку трансформаций, поступает в подписчиков и управляет внешними эффектами.
Общая схема расширяемого API сводится к трём уровням:
Любое расширение попадает в один из этих уровней, сохраняя совместимость с системой без необходимости изменения ядра библиотеки.