Реалізація Liquid/Blob ефектів на сайті

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація Liquid/Blob ефектів на сайті
Складна
~2-3 робочих дні
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація Liquid/Blob ефектів на сайті

Blob та liquid ефекти — органічні, "живі" форми: плями з плавно мінливими краями, рідкі переходи між станами, деформація геометрії за шумом. У вебі це реалізується через SVG (прості випадки), CSS-фільтри (трюк з blur+contrast), Canvas та WebGL (повний контроль).

SVG Blob з анімованим path

Базовий варіант: SVG-форма з анімацією контрольних точок через JS.

// Генерація blob-шляху через cubicBezier контрольні точки
function createBlobPath(
  cx: number,
  cy: number,
  radius: number,
  points: number,
  variance: number,
  seed: number
): string {
  const angleStep = (Math.PI * 2) / points
  const coords: [number, number][] = []

  for (let i = 0; i < points; i++) {
    const angle = i * angleStep - Math.PI / 2
    const r = radius + (Math.random() * variance * 2 - variance)
    coords.push([
      cx + Math.cos(angle) * r,
      cy + Math.sin(angle) * r,
    ])
  }

  // Будуємо smooth path через catmull-rom -> bezier
  const d: string[] = []
  const n = coords.length

  for (let i = 0; i < n; i++) {
    const p0 = coords[(i - 1 + n) % n]
    const p1 = coords[i]
    const p2 = coords[(i + 1) % n]
    const p3 = coords[(i + 2) % n]

    const cp1x = p1[0] + (p2[0] - p0[0]) / 6
    const cp1y = p1[1] + (p2[1] - p0[1]) / 6
    const cp2x = p2[0] - (p3[0] - p1[0]) / 6
    const cp2y = p2[1] - (p3[1] - p1[1]) / 6

    if (i === 0) {
      d.push(`M ${p1[0]},${p1[1]}`)
    }
    d.push(`C ${cp1x},${cp1y} ${cp2x},${cp2y} ${p2[0]},${p2[1]}`)
  }

  d.push('Z')
  return d.join(' ')
}

// Анімація: морфинг між двома blob-формами
class AnimatedBlob {
  private path: SVGPathElement
  private pathA: string
  private pathB: string
  private progress = 0
  private direction = 1
  private speed = 0.005

  constructor(path: SVGPathElement, cx: number, cy: number, radius: number) {
    this.path = path
    this.pathA = createBlobPath(cx, cy, radius, 8, radius * 0.25, 1)
    this.pathB = createBlobPath(cx, cy, radius, 8, radius * 0.25, 2)
    this.animate()
  }

  private animate() {
    this.progress += this.speed * this.direction
    if (this.progress >= 1 || this.progress <= 0) this.direction *= -1

    // GSAP morphSVG або нативний інтерполятор
    this.path.setAttribute('d', this.interpolatePaths(
      this.pathA,
      this.pathB,
      this.progress
    ))

    requestAnimationFrame(() => this.animate())
  }
}

Простіше використовувати GSAP MorphSVGPlugin (Club GreenSock):

import gsap from 'gsap'
import MorphSVGPlugin from 'gsap/MorphSVGPlugin'

gsap.registerPlugin(MorphSVGPlugin)

// Морфинг між путями
gsap.to('#blob-path', {
  morphSVG: '#blob-path-b',
  duration: 3,
  ease: 'sine.inOut',
  repeat: -1,
  yoyo: true,
})

CSS Blob через filter: blur + contrast

Дешевий, але ефективний трюк. Кілька кругів з blur, обгорнуті в контейнер з contrast(20). На границях blur перекриваючихся кругів виникає рідке слипання.

<div class="blob-container">
  <div class="blob blob--1"></div>
  <div class="blob blob--2"></div>
  <div class="blob blob--3"></div>
  <div class="blob blob--cursor"></div>
</div>
.blob-container {
  position: fixed;
  inset: 0;
  filter: blur(40px) contrast(20);
  /* contrast() — ключ ефекту */
}

.blob {
  position: absolute;
  border-radius: 50%;
  background: #7000ff;
}

.blob--1 {
  width: 300px;
  height: 300px;
  top: 20%;
  left: 30%;
  animation: blob-float-1 8s ease-in-out infinite alternate;
}

.blob--2 {
  width: 200px;
  height: 200px;
  top: 50%;
  left: 60%;
  animation: blob-float-2 10s ease-in-out infinite alternate;
}

.blob--3 {
  width: 250px;
  height: 250px;
  top: 70%;
  left: 20%;
  animation: blob-float-3 12s ease-in-out infinite alternate;
}

@keyframes blob-float-1 {
  0%   { transform: translate(0, 0) scale(1); }
  50%  { transform: translate(80px, -60px) scale(1.1); }
  100% { transform: translate(-40px, 40px) scale(0.9); }
}

@keyframes blob-float-2 {
  0%   { transform: translate(0, 0) scale(1); }
  100% { transform: translate(-100px, 80px) scale(1.2); }
}

@keyframes blob-float-3 {
  0%   { transform: translate(0, 0) scale(1); }
  100% { transform: translate(60px, -80px) scale(0.8); }
}

Blob-cursor — слідує за мишею:

const blobCursor = document.querySelector('.blob--cursor')
let mouseX = 0, mouseY = 0
let currentX = 0, currentY = 0

document.addEventListener('mousemove', (e) => {
  mouseX = e.clientX
  mouseY = e.clientY
})

function animateCursor() {
  currentX += (mouseX - currentX) * 0.08
  currentY += (mouseY - currentY) * 0.08

  blobCursor.style.transform = `translate(${currentX - 75}px, ${currentY - 75}px)`
  requestAnimationFrame(animateCursor)
}

animateCursor()

WebGL Liquid через шейдер

Повний контроль над формою, кольором, поведінкою — через GLSL. Шейдер на основі sdf (signed distance function):

// Fragment shader — liquid metaballs
uniform float uTime;
uniform vec2 uMouse;
uniform vec2 uResolution;

// SDF для кола
float circle(vec2 p, vec2 center, float r) {
  return length(p - center) - r;
}

// Smooth union — "слипання" форм
float smoothUnion(float d1, float d2, float k) {
  float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0);
  return mix(d2, d1, h) - k * h * (1.0 - h);
}

void main() {
  vec2 uv = (gl_FragCoord.xy - uResolution * 0.5) / min(uResolution.x, uResolution.y);
  vec2 mouse = (uMouse - uResolution * 0.5) / min(uResolution.x, uResolution.y);

  // Три блоба з незалежним рухом
  vec2 p1 = vec2(sin(uTime * 0.7) * 0.3, cos(uTime * 0.5) * 0.2);
  vec2 p2 = vec2(cos(uTime * 0.4) * 0.25, sin(uTime * 0.8) * 0.25);
  vec2 p3 = mouse * 0.5;  // слідує за мишею

  float d1 = circle(uv, p1, 0.18);
  float d2 = circle(uv, p2, 0.14);
  float d3 = circle(uv, p3, 0.12);

  float merged = smoothUnion(smoothUnion(d1, d2, 0.08), d3, 0.06);

  // Колір: градієнт всередині форми, rim-lighting по краях
  vec3 colorInner = vec3(0.4, 0.0, 1.0);
  vec3 colorRim = vec3(0.0, 0.8, 1.0);

  float fill = smoothstep(0.005, -0.005, merged);
  float rim = smoothstep(0.02, 0.0, merged) - smoothstep(0.0, -0.02, merged);

  vec3 color = mix(vec3(0.0), colorInner, fill);
  color += colorRim * rim * 0.8;

  gl_FragColor = vec4(color, fill + rim * 0.5);
}

React-компонент з CSS blob

import { useEffect, useRef } from 'react'

export function LiquidBackground() {
  const containerRef = useRef<HTMLDivElement>(null)
  const cursorBlobRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const cursor = cursorBlobRef.current
    if (!cursor) return

    let mx = 0, my = 0, cx = 0, cy = 0
    let rafId: number

    const onMove = (e: MouseEvent) => { mx = e.clientX; my = e.clientY }
    window.addEventListener('mousemove', onMove)

    const tick = () => {
      cx += (mx - cx) * 0.08
      cy += (my - cy) * 0.08
      cursor.style.transform = `translate(${cx - 75}px, ${cy - 75}px)`
      rafId = requestAnimationFrame(tick)
    }
    rafId = requestAnimationFrame(tick)

    return () => {
      window.removeEventListener('mousemove', onMove)
      cancelAnimationFrame(rafId)
    }
  }, [])

  return (
    <div ref={containerRef} className="blob-container">
      <div className="blob blob--1" />
      <div className="blob blob--2" />
      <div ref={cursorBlobRef} className="blob blob--cursor" />
    </div>
  )
}

Терміни

CSS blob з cursor-following — 1 день. SVG морфинг через GSAP — 2–3 дні. WebGL metaballs з кастомним шейдером та інтерактивністю — 5–7 днів.