Реалізація WebGL-анімацій та 3D-ефектів на сайті
При спробі додати 3D-анімацію через Canvas 2D продуктивність падає до 15 FPS на мобільних пристроях — GPU простоює. WebGL вирішує цю проблему, надаючи прямий доступ до графічного процесора. Коли потрібно рендерити тисячі частинок, деформувати геометрію за аудіосигналом або будувати інтерактивні 3D-сцени без плагінів — ми використовуємо WebGL 2.0 (підтримка 95%+ браузерів) через Three.js або напряму через WebGL API для нестандартних завдань. Наприклад, в одному проєкті для преміального лендінгу ми замінили CSS-анімацію шейдерним фоном — LCP впав з 4.2 до 1.8 секунд, а візуальна складність зросла втричі. Зв'яжіться з нами для оцінки вашого проєкту.
Чому WebGL — стандарт для 3D у вебі?
WebGL — єдина технологія, що забезпечує повноцінну 3D-графіку без плагінів. На відміну від CSS-анімацій або Canvas 2D, WebGL використовує шейдери на GPU, що дає продуктивність, недосяжну іншими засобами. Для візуалізації даних, гейміфікації або преміального дизайну це стандарт. Специфікація WebGL від Khronos Group підтримується всіма сучасними браузерами. За даними Google, інтерактивні 3D-елементи збільшують конверсію на 30–40% в e-commerce — але тільки при грамотній оптимізації.
Як ми реалізуємо 3D-ефекти?
Створюємо шейдерні фони (анімований шум, градієнти з реакцією на мишу), системи частинок (100k+ частинок з анімацією на GPU), деформацію зображень при hover, 3D-моделі продуктів з конфігуратором матеріалів та інтерактивні сцени. Нижче — таблиця з типовими ефектами.
| Ефект | Інструмент | Продуктивність | Термін прототипу |
|---|---|---|---|
| Шейдерний фон | Raw WebGL / Three.js | 60fps на десктопі | 1–2 дні |
| Система частинок (100k) | Three.js з BufferGeometry | 30–60fps на мобільних | 2–3 дні |
| Image distortion | Three.js з displacement map | 60fps | 1 день |
| 3D-модель продукту | Three.js + GLTF | Залежить від полігонів | 5–7 днів |
Технічна реалізація: шейдери, частинки, деформації
Three.js — стандарт де-факто для більшості веб-проєктів. Абстрагує шейдери та буфери, надає сцену, камеру, освітлення. Версія r169+ підтримує WebGPU як альтернативний рендерер. Raw WebGL застосовується, коли потрібна повна керованість: кастомні геометричні примітиви, нестандартні режими бленда, мінімальний bundle size. GLSL-шейдери пишуться вручну під кожен ефект.
// Вертексний шейдер — деформація площини за шумом
uniform float uTime;
uniform float uAmplitude;
varying vec2 vUv;
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
void main() {
vUv = uv;
vec3 pos = position;
float noise = snoise(vec2(pos.x * 0.5 + uTime * 0.3, pos.y * 0.5));
pos.z += noise * uAmplitude;
gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);
}
// Three.js — ініціалізація сцени з постпроцесингом
import * as THREE from 'three'
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js'
const renderer = new THREE.WebGLRenderer({
canvas: document.querySelector('#webgl'),
antialias: true,
alpha: true,
})
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2))
renderer.setSize(window.innerWidth, window.innerHeight)
renderer.toneMapping = THREE.ACESFilmicToneMapping
const composer = new EffectComposer(renderer)
composer.addPass(new RenderPass(scene, camera))
composer.addPass(new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
0.8, // strength
0.4, // radius
0.85 // threshold
))
Система частинок
Для 100k+ частинок використовується BufferGeometry з атрибутами у Float32Array. Анімація відбувається повністю у вертексному шейдері — CPU не задіяний у runtime.
const COUNT = 150000
const positions = new Float32Array(COUNT * 3)
const randoms = new Float32Array(COUNT)
for (let i = 0; i < COUNT; i++) {
positions[i * 3 + 0] = (Math.random() - 0.5) * 10
positions[i * 3 + 1] = (Math.random() - 0.5) * 10
positions[i * 3 + 2] = (Math.random() - 0.5) * 10
randoms[i] = Math.random()
}
const geometry = new THREE.BufferGeometry()
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3))
geometry.setAttribute('aRandom', new THREE.BufferAttribute(randoms, 1))
const material = new THREE.ShaderMaterial({
uniforms: {
uTime: { value: 0 },
uSize: { value: 3.0 * renderer.getPixelRatio() },
},
vertexShader: particleVertexShader,
fragmentShader: particleFragmentShader,
transparent: true,
depthWrite: false,
blending: THREE.AdditiveBlending,
})
Image distortion при hover
Текстура зображення деформується через displacement map за позицією курсора. Ефект «рідкого» наведення.
// Uniforms для передачі в шейдер
const uniforms = {
uTexture: { value: texture },
uDisplacement: { value: displacementTexture },
uMouse: { value: new THREE.Vector2(0, 0) },
uVelo: { value: 0 },
}
// Відстеження швидкості руху миші
let lastMouse = new THREE.Vector2()
let currentVelo = 0
window.addEventListener('mousemove', (e) => {
const current = new THREE.Vector2(
e.clientX / window.innerWidth,
1.0 - e.clientY / window.innerHeight
)
const delta = current.distanceTo(lastMouse)
currentVelo = Math.min(delta * 10, 1.0)
lastMouse.copy(current)
uniforms.uMouse.value.copy(current)
})
Завантаження асетів
3D-моделі — формат .glb (бінарний GLTF). Стиснення через Draco (geom) + KTX2 (текстури).
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
import { KTX2Loader } from 'three/addons/loaders/KTX2Loader.js'
const dracoLoader = new DRACOLoader()
dracoLoader.setDecoderPath('/draco/')
const ktx2Loader = new KTX2Loader()
ktx2Loader.setTranscoderPath('/basis/')
ktx2Loader.detectSupport(renderer)
const loader = new GLTFLoader()
loader.setDRACOLoader(dracoLoader)
loader.setKTX2Loader(ktx2Loader)
loader.load('/models/scene.glb', (gltf) => {
scene.add(gltf.scene)
}, (progress) => {
const pct = (progress.loaded / progress.total * 100).toFixed(0)
onProgress(pct)
})
Оптимізація продуктивності та адаптивність
Framerate target — 60fps на десктопі, 30fps на мобільних з автоматичним зниженням якості. Визначається через navigator.hardwareConcurrency та бенчмарк при першому рендері. Ключові правила: один drawcall замість тисячі (InstancedMesh), renderer.setPixelRatio(Math.min(devicePixelRatio, 2)), dispose при unmount, постпроцесинг тільки при prefersReducedMotion === false. Порівняння підходів наведене в таблиці.
| Параметр | Three.js | Raw WebGL |
|---|---|---|
| Швидкість розробки | Висока (готові компоненти) | Низька (ручне керування) |
| Продуктивність | Достатня для 90% завдань | Максимальна при кастомній оптимізації |
| Bundle size | ~600 KB (min) | ~50 KB (тільки шейдери) |
| Коли обирати | Стандартні ефекти, терміни критичні | Унікальні сцени, мінімальний розмір |
Як оптимізувати WebGL для слабких пристроїв?
Автоматично перевіряємо потужність GPU через бенчмарк при завантаженні. Якщо FPS падає нижче цільового, знижуємо піксель ратіо, кількість частинок, відключаємо постпроцесинг. Для мобільних використовуємо InstancedMesh і уникаємо прозорих матеріалів. Підтримка prefers-reduced-motion відключає анімацію повністю. Такий підхід економить до 40% трафіку та гарантує плавний досвід на будь-якому пристрої.
Що входить у проєкт?
- Прототип ефекту з вихідними шейдерами
- Інтеграція у ваш фреймворк (React, Vue, Angular, vanilla)
- Оптимізація під Core Web Vitals та мобільні пристрої
- Документація з налаштування та підтримки
- Доступ до репозиторію з кодом
Отримайте консультацію протягом робочого дня — зв'яжіться з нами для обговорення вашого завдання.
Етапи роботи та орієнтовні терміни
- Брифінг та аналіз вимог — 1–2 дні
- Прототипування основного ефекту — 3–5 днів
- Розробка та оптимізація — 5–10 днів
- Тестування на пристроях — 2–3 дні
- Деплой та документація — 2 дні
Загальний термін: від 10 до 20 робочих днів залежно від складності. Вартість розраховується індивідуально. Зв'яжіться з нами для оцінки вашого проєкту.







