Lottie Web работает с JSON-анимациями, экспортированными из After Effects через Bodymovin, и по своей природе является 2D-движком. Любая «глубина» в таких анимациях создаётся не геометрией, а имитацией пространственных эффектов через трансформации слоёв, масштабирование, размытие и управление порядком отрисовки.
Ключевой принцип псевдо-3D в Lottie — разложение сцены на независимые визуальные плоскости и управление их поведением во времени или в зависимости от внешних параметров (скролл, курсор, таймлайн).
Основные инструменты:
transform.positiontransform.scaletransform.rotationopacityНаиболее распространённый способ имитации 3D — параллакс-движение. Слои разделяются по «глубине», и каждый слой движется с разной скоростью относительно базового смещения.
В Lottie Web это достигается через программное управление прогрессом анимации или внешними трансформациями контейнеров.
Пример внешнего управления слоями:
const animation = lottie.loadAnimation({
container: document.getElementById('scene'),
renderer: 'svg',
loop: true,
autoplay: true,
path: 'animation.json'
});
window.addEventListener('mousemove', (e) => {
const x = (e.clientX / window.innerWidth - 0.5) * 2;
document.querySelectorAll('.layer').forEach((layer, index) => {
const depth = (index + 1) * 10;
layer.style.transform = `translateX(${x * depth}px)`;
});
});
Слои, экспортированные из Lottie, оборачиваются в дополнительные контейнеры, что позволяет добавлять псевдопространственное смещение без изменения JSON.
Перспектива в 2D достигается через изменение масштаба объектов в зависимости от их «удалённости».
Чем дальше слой, тем меньше масштаб и ниже контраст.
function applyDepthScale(elements) {
elements.forEach((el, i) => {
const depth = i / elements.length;
const scale = 1 - depth * 0.4;
el.style.transform = `scale(${scale})`;
el.style.opacity = `${1 - depth * 0.6}`;
});
}
В Lottie JSON это может быть реализовано через keyframes масштаба, но
более гибкий вариант — постобработка DOM-слоёв при
renderer: 'svg'.
SVG-рендерер Lottie строго следует порядку слоёв, заданному в композиции After Effects. Однако визуальная глубина может быть изменена динамически:
z-index (при HTML-обёртке)function reorderByDepth(container) {
const layers = Array.from(container.children);
layers.sort((a, b) => {
return parseFloat(a.dataset.depth) - parseFloat(b.dataset.depth);
});
layers.forEach(layer => container.appendChild(layer));
}
Такой подход позволяет создавать эффект «камера движется сквозь сцену».
Размытие активно используется как визуальный маркер расстояния. В псевдо-3D сценах ближние объекты резкие, дальние — размытые.
function applyDepthBlur(elements) {
elements.forEach((el, i) => {
const depth = i / elements.length;
const blur = depth * 6;
el.style.filter = `blur(${blur}px)`;
});
}
В Lottie SVG-фильтры ограничены производительностью, поэтому предпочтительнее использовать CSS-фильтры на контейнере.
В Lottie нет камеры, но её поведение можно симулировать через глобальные трансформации сцены.
Основная идея — все слои помещаются в общий контейнер, который управляется как «камера»:
const camera = document.getElementById('camera');
function moveCamera(x, y, zoom) {
camera.style.transform = `
translate(${-x}px, ${-y}px)
scale(${zoom})
`;
}
Дополнительная логика:
requestAnimationFrameИнтерактивность усиливает иллюзию глубины. Чаще всего используются:
Пример управления прогрессом анимации через скролл:
window.addEventListener('scroll', () => {
const scrollTop = window.scrollY;
const maxScroll = document.body.scrollHeight - window.innerHeight;
const progress = scrollTop / maxScroll;
animation.goToAndStop(progress * animation.totalFrames, true);
});
Таким образом сцена начинает вести себя как «камера в пространстве времени».
Сильный эффект глубины достигается через многократное использование одной и той же Lottie-композиции с разными параметрами трансформации.
<div class="scene">
<div class="layer back"></div>
<div class="layer mid"></div>
<div class="layer front"></div>
</div>
[lottie.loadAnimation({...}), lottie.loadAnimation({...}), lottie.loadAnimation({...})]
Каждый экземпляр:
Это создаёт эффект объёмной сцены без 3D-движка.
Для более сложных сцен Lottie используется как текстурный слой внутри WebGL-контекста.
Суть подхода:
Пример интеграции с Three.js:
const texture = new THREE.CanvasTexture(lottieCanvas);
const material = new THREE.MeshBasicMaterial({
map: texture,
transparent: true
});
const plane = new THREE.PlaneGeometry(5, 5);
const mesh = new THREE.Mesh(plane, material);
scene.add(mesh);
Такой подход позволяет комбинировать 2D-анимации с реальной 3D-сценой.
Ещё один способ усиления псевдо-3D — изменение скорости воспроизведения в зависимости от «глубины слоя».
function setLayerSpeed(layer, depth) {
const speed = 1 - depth * 0.7;
layer.setSpeed(speed);
}
Ближние объекты «живут» быстрее, дальние — медленнее, что совпадает с естественным восприятием перспективы.
SVG-рендерер Lottie имеет особенности, влияющие на реализацию глубины:
Для сцен с высокой плотностью слоёв предпочтительнее
renderer: 'canvas', где управление пикселями даёт больше
свободы для постобработки глубины.
Маски используются для имитации перспективного перекрытия объектов.
layer.style.maskImage = 'linear-gradient(to top, transparent, black)';
Также применяется техника «вырезания» слоёв при пересечении виртуальной плоскости камеры, создавая эффект прохождения объектов через пространство.
Реалистичность псевдо-3D усиливается инерцией движения:
let targetX = 0;
let currentX = 0;
function animate() {
currentX += (targetX - currentX) * 0.08;
camera.style.transform = `translateX(${currentX}px)`;
requestAnimationFrame(animate);
}
animate();
Такая модель создаёт ощущение массы у сцены, несмотря на её 2D-природу.
На практике используются повторяемые структуры:
Эта структура позволяет масштабировать сложность сцены без потери управляемости.
Даже без настоящего 3D освещение можно симулировать:
el.style.filter = `brightness(${1 - depth * 0.5}) contrast(${1 + depth * 0.3})`;
Так формируется визуальная иерархия пространства.
При работе с комплексными сценами важна синхронизация:
const animations = layers.map(layer => lottie.loadAnimation({
container: layer,
renderer: 'svg',
loop: false,
autoplay: false,
path: 'scene.json'
}));
function sync(progress) {
animations.forEach(anim => {
anim.goToAndStop(progress * anim.totalFrames, true);
});
}
Это позволяет добиться согласованного движения «объёмной» сцены, собранной из нескольких 2D-компонентов.