WebGL Animations and 3D Effects: Development and Optimization

WebGL Animations and 3D Effects: Development and Optimization

Development and maintenance of all types of websites:

Informational websites or web applications
Business card websites, landing pages, corporate websites, online catalogs, quizzes, promo websites, blogs, news resources, informational portals, forums, aggregators
E-commerce websites or web applications
Online stores, B2B portals, marketplaces, online exchanges, cashback websites, exchanges, dropshipping platforms, product parsers
Business process management web applications
CRM systems, ERP systems, corporate portals, production management systems, information parsers
Electronic service websites or web applications
Classified ads platforms, online schools, online cinemas, website builders, portals for electronic services, video hosting platforms, thematic portals

These are just some of the technical types of websites we work with, and each of them can have its own specific features and functionality, as well as be customized to meet the specific needs and goals of the client.

Our competencies:

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1419
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1287
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    983
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1248
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    984
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    998

WebGL Animations and 3D Effects: Development and Optimization

When trying to add 3D animation through Canvas 2D, performance drops to 15 FPS on mobile devices — GPU sits idle. WebGL solves this by providing direct access to the graphics processor. When we need to render thousands of particles, deform geometry based on an audio signal, or build interactive 3D scenes without plugins — we use WebGL 2.0 (supported by 95%+ of browsers) via Three.js or directly through the WebGL API for custom tasks. For example, on a premium landing page project we replaced a CSS animation with a shader background — LCP dropped from 4.2 to 1.8 seconds, while visual complexity tripled. Contact us to assess your project.

Why WebGL Is the Standard for 3D on the Web?

WebGL is the only technology providing full 3D graphics without plugins. Unlike CSS animations or Canvas 2D, WebGL uses shaders on the GPU, delivering performance unattainable by other means. For data visualization, gamification, or premium design, it's the standard. The WebGL specification by Khronos Group is supported by all modern browsers. According to Google, interactive 3D elements increase conversion by 30–40% in e-commerce — but only with proper optimization.

How We Implement 3D Effects

We create shader backgrounds (animated noise, gradients that react to mouse), particle systems (100k+ particles animated on GPU), image deformation on hover, 3D product models with material configurators, and interactive scenes. Below is a table of typical effects.

Effect Tool Performance Prototype Time
Shader background Raw WebGL / Three.js 60fps on desktop 1–2 days
Particle system (100k) Three.js with BufferGeometry 30–60fps on mobile 2–3 days
Image distortion Three.js with displacement map 60fps 1 day
3D product model Three.js + GLTF Depends on polygons 5–7 days

Technical Implementation: Shaders, Particles, Deformations

Three.js and Raw WebGL

Three.js is the de facto standard for most web projects. It abstracts shaders and buffers, providing scene, camera, lighting. Version r169+ supports WebGPU as an alternative renderer. Raw WebGL is used when full control is needed: custom geometric primitives, non-standard blend modes, minimal bundle size. GLSL shaders are written manually for each effect.

// Vertex shader — plane deformation by noise 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 — scene initialization with post-processing 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 )) 

Particle System

For 100k+ particles, we use BufferGeometry with attributes in Float32Array. Animation runs entirely in the vertex shader — CPU is not involved at 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 on Hover

The image texture is deformed using a displacement map based on cursor position. A 'liquid' hover effect.

// Uniforms for passing to shader const uniforms = { uTexture: { value: texture }, uDisplacement: { value: displacementTexture }, uMouse: { value: new THREE.Vector2(0, 0) }, uVelo: { value: 0 }, } // Tracking mouse movement speed 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) }) 

Loading Assets

3D models in .glb format (binary GLTF). Compression via Draco (geometry) + KTX2 (textures).

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) }) 

Performance Optimization and Adaptivity

Framerate target is 60 FPS on desktop, 30 FPS on mobile with automatic quality reduction. Determined via navigator.hardwareConcurrency and a benchmark on first render. Key rules: one drawcall instead of a thousand (InstancedMesh), renderer.setPixelRatio(Math.min(devicePixelRatio, 2)), dispose on unmount, post-processing only when prefersReducedMotion === false. A comparison of approaches is below.

Parameter Three.js Raw WebGL
Development speed High (ready-made components) Low (manual control)
Performance Sufficient for 90% of tasks Maximum with custom optimization
Bundle size ~600 KB (min) ~50 KB (only shaders)
When to choose Standard effects, critical deadlines Unique scenes, minimal size

How to Optimize WebGL for Weak Devices?

Automatically check GPU power via a benchmark on load. If FPS drops below target, reduce pixel ratio, particle count, disable post-processing. For mobile, use InstancedMesh and avoid transparent materials. Support for prefers-reduced-motion disables animation entirely. This approach saves up to 40% of traffic and ensures a smooth experience on any device.

What's Included in the Project?

  • Prototype of the effect with source shaders
  • Integration into your framework (React, Vue, Angular, vanilla)
  • Optimization for Core Web Vitals and mobile devices
  • Documentation for setup and maintenance
  • Access to the code repository

Get a consultation within one business day — contact us to discuss your task.

Work Stages and Estimated Timelines

  1. Briefing and requirements analysis — 1–2 days
  2. Prototyping the main effect — 3–5 days
  3. Development and optimization — 5–10 days
  4. Device testing — 2–3 days
  5. Deployment and documentation — 2 days

Total: from 10 to 20 business days depending on complexity. Cost is calculated individually. Contact us to assess your project.