Алгоритмическая анимация

Алгоритмическая анимация — это подход, при котором поведение анимации определяется не заранее заданными ключевыми кадрами, а вычисляется на основе параметров, состояния прокрутки и пользовательского ввода. В контексте ScrollMagic это означает прямую зависимость визуальных изменений от позиции скролла.

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

Ключевая идея:

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

Архитектура ScrollMagic

Основные компоненты:

  • Controller — управляет всеми сценами
  • Scene — описывает конкретную анимацию или реакцию
  • Tween (GSAP) — отвечает за изменение свойств элементов

Пример базовой структуры:

const controller = new ScrollMagic.Controller();

const scene = new ScrollMagic.Scene({
    triggerElement: "#trigger",
    duration: 500,
    triggerHook: 0.5
})
.setTween("#box", {
    x: 300
})
.addTo(controller);

Прогресс сцены как основа алгоритма

Каждая сцена имеет параметр progress — число от 0 до 1, отражающее степень прохождения сцены.

  • 0 — начало сцены
  • 1 — завершение

ScrollMagic вычисляет это значение автоматически, но его можно использовать для собственных алгоритмов:

scene.on("progress", function (event) {
    const progress = event.progress;
    console.log(progress);
});

Преобразование прогресса в анимацию

Алгоритмическая анимация строится на преобразовании progress в визуальные параметры:

Линейное преобразование

scene.on("progress", function (event) {
    const progress = event.progress;
    const translateX = progress * 500;

    document.querySelector("#box").style.transform =
        `translateX(${translateX}px)`;
});

Нелинейные функции

Для более сложного поведения используются математические функции:

const easeInOut = (t) => t < 0.5
    ? 2 * t * t
    : 1 - Math.pow(-2 * t + 2, 2) / 2;

scene.on("progress", function (event) {
    const progress = easeInOut(event.progress);
    const scale = 1 + progress;

    document.querySelector("#box").style.transform =
        `scale(${scale})`;
});

Связь нескольких параметров

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

scene.on("progress", function (event) {
    const p = event.progress;

    const x = p * 300;
    const opacity = 1 - p;
    const rotate = p * 360;

    const el = document.querySelector("#box");

    el.style.transform = `translateX(${x}px) rotate(${rotate}deg)`;
    el.style.opacity = opacity;
});

Работа с временными функциями

ScrollMagic не ограничивает выбор функций интерполяции. Можно использовать:

  • полиномы
  • синусоиды
  • экспоненты

Пример синусоидального движения:

scene.on("progress", function (event) {
    const p = event.progress;
    const y = Math.sin(p * Math.PI) * 100;

    document.querySelector("#box").style.transform =
        `translateY(${y}px)`;
});

Разбиение сцены на фазы

Для сложных анимаций сцену делят на логические участки:

scene.on("progress", function (event) {
    const p = event.progress;

    if (p < 0.33) {
        // фаза 1
    } else if (p < 0.66) {
        // фаза 2
    } else {
        // фаза 3
    }
});

Пример:

scene.on("progress", function (event) {
    const p = event.progress;
    const el = document.querySelector("#box");

    if (p < 0.5) {
        const local = p / 0.5;
        el.style.transform = `translateX(${local * 200}px)`;
    } else {
        const local = (p - 0.5) / 0.5;
        el.style.transform = `translateY(${local * 200}px)`;
    }
});

Интерполяция значений

Для гибкости используется универсальная функция интерполяции:

function lerp(start, end, t) {
    return start + (end - start) * t;
}

Применение:

scene.on("progress", function (event) {
    const p = event.progress;

    const width = lerp(100, 300, p);
    const opacity = lerp(1, 0, p);

    const el = document.querySelector("#box");
    el.style.width = `${width}px`;
    el.style.opacity = opacity;
});

Управление цветами

Цвет также можно анимировать алгоритмически:

function lerpColor(a, b, t) {
    return a + (b - a) * t;
}

scene.on("progress", function (event) {
    const p = event.progress;

    const r = Math.round(lerpColor(255, 0, p));
    const g = Math.round(lerpColor(0, 255, p));
    const b = 100;

    document.querySelector("#box").style.backgroundColor =
        `rgb(${r}, ${g}, ${b})`;
});

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

ScrollMagic часто используется вместе с GSAP, но алгоритмический подход позволяет комбинировать оба метода.

Пример ручного управления таймлайном:

const tween = gsap.to("#box", {
    x: 500,
    paused: true
});

scene.on("progress", function (event) {
    tween.progress(event.progress);
});

Параллакс как алгоритм

Параллакс — классический пример алгоритмической анимации:

scene.on("progress", function (event) {
    const p = event.progress;

    document.querySelector(".bg").style.transform =
        `translateY(${p * 100}px)`;

    document.querySelector(".fg").style.transform =
        `translateY(${p * 300}px)`;
});

Сглаживание (smoothing)

Резкие изменения можно сгладить:

let current = 0;

scene.on("progress", function (event) {
    const target = event.progress;

    current += (target - current) * 0.1;

    const x = current * 500;

    document.querySelector("#box").style.transform =
        `translateX(${x}px)`;
});

Производительность

Алгоритмическая анимация требует оптимизации:

Рекомендации:

  • использовать transform вместо top/left
  • избегать частых DOM-запросов
  • кэшировать элементы
  • применять requestAnimationFrame при сложных вычислениях

Пример:

const el = document.querySelector("#box");

scene.on("progress", function (event) {
    requestAnimationFrame(() => {
        const x = event.progress * 400;
        el.style.transform = `translateX(${x}px)`;
    });
});

Композиция сцен

Несколько сцен могут работать совместно:

const scene1 = new ScrollMagic.Scene({ duration: 300 });
const scene2 = new ScrollMagic.Scene({ duration: 300, offset: 300 });

scene1.on("progress", handler1);
scene2.on("progress", handler2);

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


Связь с пользовательским вводом

ScrollMagic можно комбинировать с событиями мыши или клавиатуры:

let factor = 1;

document.addEventListener("mousemove", (e) => {
    factor = e.clientX / window.innerWidth;
});

scene.on("progress", function (event) {
    const x = event.progress * 500 * factor;

    document.querySelector("#box").style.transform =
        `translateX(${x}px)`;
});

Дебаг и визуализация

Для анализа сцен используется:

scene.addIndicators();

Это помогает понять:

  • где начинается сцена
  • её длительность
  • текущий прогресс

Паттерны алгоритмической анимации

1. Прямое отображение (mapping) Скролл напрямую управляет свойствами

2. Функциональная трансформация Использование математических функций

3. Состояния и переходы Разделение на фазы

4. Интеграция с физикой Имитация ускорения, инерции


Интеграция с физическими моделями

Пример простого ускорения:

scene.on("progress", function (event) {
    const p = event.progress;

    const velocity = p * p;
    const x = velocity * 400;

    document.querySelector("#box").style.transform =
        `translateX(${x}px)`;
});

Ограничение значений

Иногда требуется ограничить диапазон:

function clamp(value, min, max) {
    return Math.max(min, Math.min(max, value));
}

Применение:

scene.on("progress", function (event) {
    const p = clamp(event.progress, 0.2, 0.8);

    const opacity = (p - 0.2) / 0.6;

    document.querySelector("#box").style.opacity = opacity;
});

Декомпозиция логики

Для поддержки кода логика выносится в функции:

function updateBox(progress) {
    const x = progress * 300;
    const scale = 1 + progress;

    const el = document.querySelector("#box");

    el.style.transform = `translateX(${x}px) scale(${scale})`;
}

scene.on("progress", (e) => updateBox(e.progress));

Синхронизация нескольких элементов

scene.on("progress", function (event) {
    const p = event.progress;

    document.querySelectorAll(".item").forEach((el, i) => {
        const delay = i * 0.1;
        const local = Math.max(0, Math.min(1, p - delay));

        el.style.transform =
            `translateY(${local * 100}px)`;
    });
});

Управление длительностью как параметром алгоритма

Длительность сцены влияет на чувствительность анимации:

new ScrollMagic.Scene({
    duration: window.innerHeight * 2
});

Чем больше длительность, тем плавнее изменение progress.


Динамическое изменение параметров

Сцены можно адаптировать:

scene.duration(window.innerHeight * 1.5);
scene.refresh();

Комбинирование с CSS-переменными

scene.on("progress", function (event) {
    document.documentElement.style.setProperty(
        "--progress",
        event.progress
    );
});

CSS:

#box {
    transform: translateX(calc(var(--progress) * 300px));
}

Управление камерой (эффект “viewport”)

scene.on("progress", function (event) {
    const p = event.progress;

    document.querySelector(".container").style.transform =
        `translateY(${-p * 100}vh)`;
});

Масштабируемость

Алгоритмическая анимация в ScrollMagic позволяет:

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

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