Контроль воспроизведения в Popmotion строится вокруг идеи управляемого контроллера анимации, который позволяет вмешиваться в ход выполнения в любой момент: приостанавливать, возобновлять, останавливать, ускорять, замедлять и изменять текущую позицию анимации без пересоздания всей логики.
Любая анимация в Popmotion (tween, spring, keyframes, physics) возвращает объект управления. Этот объект представляет собой интерфейс между описанием движения и его фактическим выполнением.
Ключевая идея:
анимация ≠ процесс воспроизведения
Анимация описывает поведение, а контроллер управляет его жизненным циклом.
Типичный контроллер предоставляет методы:
stop() — полная остановкаpause() — временная паузаplay() — продолжениеseek() — переход к конкретному моменту времениcomplete() — принудительное завершениеtimeScale — масштаб времени (ускорение/замедление)Запуск анимации происходит автоматически при создании, если не указано обратное. Однако управление через контроллер позволяет отделить создание от старта.
import { animate } from "popmotion";
const animation = animate({
from: 0,
to: 100,
duration: 2000,
onUpdate: (v) => console.log(v)
});
Остановка выполняет полное прекращение работы:
animation.stop();
После вызова stop() анимация не может быть продолжена в
прежнем состоянии. Это важно отличать от паузы.
Пауза сохраняет текущее состояние прогресса, не обнуляя внутреннее время.
animation.pause();
Возобновление:
animation.play();
Поведение при паузе:
onUpdate перестаёт вызыватьсяplay() продолжение идёт с точки остановкиЭто делает Popmotion удобным для UI-интерактивных сценариев: модальные окна, скрытие вкладок, переключение сцен.
Критическое различие:
| Метод | Состояние прогресса | Возможность продолжения |
|---|---|---|
| pause | сохраняется | да |
| stop | завершён/сброшен | нет |
stop() используется, когда результат анимации больше не
нужен. pause() — когда важно сохранить контекст.
Popmotion позволяет управлять скоростью воспроизведения через масштаб времени.
animation.timeScale = 2;
Поведение:
1 — нормальная скорость2 — в 2 раза быстрее0.5 — в 2 раза медленнее0 — фактическая паузаЭто особенно полезно при создании эффектов:
Одной из наиболее мощных возможностей является управление текущей позицией анимации.
animation.seek(0.5);
Где значение:
0 — начало1 — конецПоведение seek():
Пример использования для скраббинга:
slider.onin put = (e) => {
animation.seek(e.target.value / 100);
};
Внутреннее состояние анимации опирается на:
Popmotion вычисляет значение по формуле:
from и toХотя формально это скрыто, контроль через seek()
позволяет вмешиваться в этот процесс напрямую.
В интерфейсных сценариях часто требуется заменить одну анимацию другой без резких скачков.
Типовой паттерн:
let currentAnimation;
function playNewAnimation() {
if (currentAnimation) currentAnimation.stop();
currentAnimation = animate({
from: 0,
to: 300,
duration: 1000,
onUpdate: (v) => console.log(v)
});
}
Это предотвращает:
Popmotion предоставляет обратные вызовы, которые тесно связаны с контролем воспроизведения:
onUpdate — каждое изменение значенияonComplete — завершениеonPlay — запускonStop — остановкаonPause — паузаПример синхронизации состояния UI:
const animation = animate({
from: 0,
to: 1,
onUpdate: (v) => {
element.style.opacity = v;
},
onComplete: () => {
console.log("готово");
}
});
Контроль воспроизведения часто связывается с событиями DOM:
buttonPlay.oncl ick = () => animation.play();
buttonPause.oncl ick = () => animation.pause();
buttonStop.oncl ick = () => animation.stop();
Более сложный сценарий — drag-to-control:
element.onmousem ove = (e) => {
const progress = e.clientX / window.innerWidth;
animation.seek(progress);
};
Такой подход превращает анимацию в управляемый параметр интерфейса.
При одновременных действиях важно учитывать приоритет:
stop() всегда завершает цикл немедленноpause() блокирует тик обновленияseek() может выполняться как в paused, так и running
состоянииtimeScale применяется мгновенноКонфликты могут возникать при частом вызове seek() и
play() одновременно, поэтому обычно вводится логика
блокировки:
let isScrubbing = false;
slider.onmoused own = () => isScrubbing = true;
slider.onmous eup = () => isScrubbing = false;
slider.onin put = (e) => {
if (isScrubbing) {
animation.seek(e.target.value / 100);
}
};
При использовании timeline управление становится
иерархическим.
import { timeline } from "popmotion";
const sequence = timeline([
{ track: "x", from: 0, to: 100, duration: 500 },
{ track: "x", from: 100, to: 200, duration: 500 }
]);
Контроль работает на уровне всей последовательности:
Это делает timeline основным инструментом для сложных интерфейсных переходов.
Контроллер обычно проходит через состояния:
Переходы между ними определяют, какие методы доступны в данный момент. Например:
stop() повторный play() может
требовать пересозданияpause() допустим play()seek() состояние не меняется автоматическиПри сложных интерфейсах часто требуется синхронный контроль:
const a1 = animate({ from: 0, to: 100 });
const a2 = animate({ from: 100, to: 200 });
function pauseAll() {
a1.pause();
a2.pause();
}
Для централизованного управления вводится абстракция контроллера группы:
Наиболее стабильные системы управления Popmotion-анимациями строятся по принципам:
seek() для интерактивности вместо
пересозданияТакой подход обеспечивает детерминированное поведение даже при высокой частоте событий и сложной UI-логике