Метки времени (timestamps) — это числовые значения, отражающие конкретный момент времени в процессе анимации. В контексте библиотеки Popmotion они играют ключевую роль в управлении ходом анимации, синхронизации событий и вычислении промежуточных состояний.
В основе любой анимации лежит прогресс во времени, и именно метки времени позволяют точно определить, на каком этапе находится движение.
В Popmotion метки времени используются для:
Каждый кадр анимации сопровождается временной меткой, которая обычно измеряется в миллисекундах.
Основным источником времени в браузере является метод:
performance.now()
Он возвращает высокоточное время с момента загрузки страницы. Popmotion использует аналогичный подход внутри своих внутренних механизмов.
Также часто применяется:
requestAnimationFrame((timestamp) => {
// timestamp — метка времени текущего кадра
})
Этот timestamp автоматически передаётся браузером и
синхронизирован с частотой обновления экрана.
Рассмотрим пример простой анимации с использованием Popmotion:
import { animate } from "popmotion";
animate({
from: 0,
to: 100,
duration: 1000,
onUpdate: (latest) => {
console.log(latest);
}
});
Внутри animate происходит:
Захват начальной метки времени
На каждом кадре вычисление разницы:
elapsed = currentTime - startTimeОпределение прогресса:
progress = elapsed / durationИнтерполяция значения
Прогресс — это нормализованное значение от 0 до
1, вычисляемое на основе времени:
progress = elapsed / duration
Где:
elapsed — прошедшее времяduration — длительность анимацииPopmotion автоматически ограничивает прогресс в диапазоне
[0, 1].
Иногда требуется более точный контроль над временем. Это возможно
через кастомные драйверы или использование framesync.
Пример с ручным управлением:
import { animate } from "popmotion";
let startTime;
animate({
from: 0,
to: 100,
duration: 1000,
driver: (update) => {
startTime = performance.now();
function frame() {
const currentTime = performance.now();
update(currentTime);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
return () => {};
}
});
В этом примере:
update получает текущую метку времениМетки времени позволяют синхронизировать несколько анимаций, чтобы они двигались согласованно.
import { animate } from "popmotion";
const start = performance.now();
const options = {
duration: 1000,
driver: (update) => {
function frame() {
update(performance.now() - start);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
return () => {};
}
};
animate({
...options,
from: 0,
to: 100,
onUpdate: v => console.log("A:", v)
});
animate({
...options,
from: 100,
to: 200,
onUpdate: v => console.log("B:", v)
});
Обе анимации используют одну и ту же временную базу
(start), что обеспечивает их синхронность.
Метки времени можно масштабировать для изменения скорости анимации:
const speed = 0.5; // замедление в 2 раза
const elapsed = (currentTime - startTime) * speed;
speed < 1 — замедлениеspeed > 1 — ускорениеЭто позволяет реализовать эффекты:
Использование времени даёт возможность реализовать перемотку:
let manualTime = 0;
animate({
from: 0,
to: 100,
duration: 1000,
driver: (update) => {
function frame() {
manualTime += 16; // имитация времени
update(manualTime);
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
return () => {};
}
});
Здесь:
performance.nowПауза реализуется через остановку накопления времени:
let paused = false;
let pauseTime = 0;
function frame() {
if (!paused) {
const current = performance.now() - pauseTime;
update(current);
}
requestAnimationFrame(frame);
}
При возобновлении:
pauseTimeМетки времени напрямую влияют на easing:
import { easeInOut } from "popmotion";
const progress = elapsed / duration;
const eased = easeInOut(progress);
Easing-функции:
Таким образом:
Если кадры пропускаются (например, при нагрузке), метки времени позволяют компенсировать это:
const delta = currentTime - previousTime;
Использование delta:
Popmotion использует внутренний механизм framesync,
который:
Пример:
import sync from "framesync";
sync.update(({ timestamp }) => {
console.log(timestamp);
});
Это обеспечивает:
Особенности работы с метками времени:
performance.now() более точен, чем
Date.now()Важно учитывать:
performance.now() для точных
вычисленийdelta), а не на
кадрыУпрощённая схема:
elapsedprogressonUpdateКаждый шаг зависит от корректной работы с временными метками, что делает их фундаментальной частью всей системы анимаций.