Алгоритмическая анимация — это подход, при котором поведение анимации определяется не заранее заданными ключевыми кадрами, а вычисляется на основе параметров, состояния прокрутки и пользовательского ввода. В контексте ScrollMagic это означает прямую зависимость визуальных изменений от позиции скролла.
ScrollMagic предоставляет механизм синхронизации прокрутки с анимацией через объекты Scene, которые реагируют на положение страницы относительно определённых триггеров.
Ключевая идея:
Основные компоненты:
Пример базовой структуры:
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})`;
});
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)`;
});
Резкие изменения можно сгладить:
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/leftrequestAnimationFrame при сложных
вычисленияхПример:
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();
scene.on("progress", function (event) {
document.documentElement.style.setProperty(
"--progress",
event.progress
);
});
CSS:
#box {
transform: translateX(calc(var(--progress) * 300px));
}
scene.on("progress", function (event) {
const p = event.progress;
document.querySelector(".container").style.transform =
`translateY(${-p * 100}vh)`;
});
Алгоритмическая анимация в ScrollMagic позволяет:
Основная сила подхода — в превращении прокрутки в универсальный управляющий сигнал, который можно преобразовать в любую визуальную логику.