Временные функции и интерполяция

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

Любая анимация в Popmotion сводится к отображению времени в нормализованный диапазон:

  • начало анимации → 0
  • конец анимации → 1

Этот диапазон называется прогрессом (progress). Временные функции отвечают за преобразование реального времени (миллисекунды) в значение прогресса.

Базовая модель:

time → progress (0 → 1) → transformation → output value

Ключевой момент — отделение времени от результата. Это позволяет применять единый механизм к разным типам анимаций: tween, spring, decay.


Tween как временная функция линейного изменения

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

Внутри tween происходит:

  • вычисление прошедшего времени
  • деление на длительность
  • ограничение диапазона 0–1
  • применение easing-функции (если задана)

Простейшая форма линейного tween:

import { tween } from 'popmotion';

tween({
  from: 0,
  to: 100,
  duration: 1000
}).start(v => {
  console.log(v);
});

Фактически каждое значение v — результат функции:

v = from + (to - from) * progress

Интерполяция как основа трансформации

Интерполяция — процесс преобразования нормализованного прогресса в конкретное значение.

В Popmotion используется универсальная функция интерполяции:

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

Базовая линейная интерполяция:

lerp(a, b, t) = a + (b - a) * t

где:

  • a — начальное значение
  • b — конечное значение
  • t — прогресс (0–1)

Утилита interpolate

Popmotion предоставляет инструмент для создания собственных интерполяций:

import { interpolate } from 'popmotion';

const mixer = interpolate([0, 50, 100]);

mixer(0);   // 0
mixer(0.5); // 50
mixer(1);   // 100

Здесь интерполяция разбивает диапазон на сегменты. Если вход выходит за пределы, применяется ограничение или extrapolation.


Clamp и ограничение диапазона

Временные функции почти всегда требуют ограничения входных значений. Clamp обеспечивает фиксацию диапазона:

clamp(min, max, value)

Применение:

import { clamp } from 'popmotion';

const safe = clamp(0, 1, 1.5); // 1

Clamp используется перед интерполяцией, чтобы прогресс не выходил за пределы.


Easing как модификатор времени

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

Типичная форма:

easedProgress = easing(t)

Примеры поведения:

  • linear: равномерное изменение
  • ease-in: ускорение
  • ease-out: замедление
  • ease-in-out: комбинация

Пример:

import { tween, easing } from 'popmotion';

tween({
  from: 0,
  to: 100,
  duration: 1000,
  ease: easing.easeInOut
}).start(v => {
  console.log(v);
});

Временная дискретизация через requestAnimationFrame

Временные функции Popmotion опираются на requestAnimationFrame. Это обеспечивает:

  • синхронизацию с рендером браузера
  • стабильный FPS
  • минимизацию дрожания анимации

Алгоритм обновления:

  1. фиксируется стартовое время

  2. при каждом кадре вычисляется delta

  3. вычисляется прогресс:

    progress = (now - start) / duration
  4. применяется easing

  5. выполняется интерполяция


Комбинирование временных функций и интерполяции

Важный принцип Popmotion — разделение временной логики и логики значения.

Пример композиции

import { tween, interpolate, easing } from 'popmotion';

const mixer = interpolate([0, 100, 200]);

tween({
  duration: 1000,
  ease: easing.easeOut
}).start(v => {
  const result = mixer(v / 100);
});

Здесь:

  • tween управляет временем
  • easing изменяет характер прогресса
  • interpolate формирует значения

Нормализация времени

Перед интерполяцией время всегда приводится к диапазону 0–1:

t = (currentTime - startTime) / duration

Далее:

t = clamp(0, 1, t)
t = easing(t)

После этого значение передается в интерполяцию.


Transform pipeline

Внутренне Popmotion использует цепочку преобразований:

time → clamp → easing → interpolate → output

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


Pipe как механизм композиции функций

Pipe объединяет несколько функций в последовательный поток обработки значений:

import { pipe, clamp } from 'popmotion';

const process = pipe(
  clamp(0, 1),
  t => t * 2,
  t => t - 1
);

В контексте временных функций pipe часто используется для:

  • нормализации времени
  • применения easing
  • преобразования выходных значений

Интерполяция цветов и сложных структур

Интерполяция не ограничивается числами. Popmotion поддерживает сложные типы данных:

Цвета

rgb(0,0,0) → rgb(255,255,255)

Алгоритм:

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

Объекты

{ x: 0, y: 0 } → { x: 100, y: 200 }

Применяется рекурсивная интерполяция свойств.


Keyframes как дискретная интерполяция

Keyframes позволяют задавать промежуточные точки:

0 → 50 → 20 → 100

Интерполяция разбивается на сегменты:

  • 0–0.33
  • 0.33–0.66
  • 0.66–1

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


Decay и временное затухание

Decay — особый тип временной функции, где значение не привязано к конечной точке, а уменьшается по экспоненте.

Модель:

velocity → friction → gradual stop

Интерполяция здесь основана не на позиции, а на скорости изменения.


Связь времени и физической модели

Временные функции Popmotion могут моделировать физику:

  • spring — упругая система
  • decay — затухание
  • tween — идеализированное время

Интерполяция в этом контексте становится функцией состояния системы:

state(t) = physicsEquation(t)

Переиспользуемые временные трансформации

Одной из сильных сторон Popmotion является возможность комбинировать временные функции:

  • easing применяется поверх spring
  • clamp ограничивает decay
  • interpolate формирует финальную структуру

Пример цепочки:

spring → clamp → interpolate → render

Разделение времени и представления

Архитектурно Popmotion строится на принципе:

  • время не зависит от UI
  • интерполяция не зависит от источника времени
  • функции являются чистыми преобразованиями

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

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

Нелинейная интерполяция как основа выразительности

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

Например:

  • линейное время → механическое движение
  • ease-out → естественное замедление
  • spring → физическая инерция

Интерполяция остается неизменной, меняется только входной параметр времени.