Реалізація Particles.js / tsParticles ефектів на сайті

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

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

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

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

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація Particles.js / tsParticles ефектів на сайті
Проста
від 1 робочого дня до 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

Реалізація Particles.js / tsParticles ефектів на сайті

tsParticles — наступник оригінального Particles.js з активною підтримкою, TypeScript-типами та значно ширшими можливостями. Оригінальний Particles.js заброшений з 2016 року. Якщо проект новий — використовуйте tsParticles. Він дає: частинки, конфеті, феєрверки, сніг, бульбашки, зв'язки між частинками, інтерактивність з мишею.

Установка (модульна, лише необхідні пресети)

# Мінімальна установка — ядро + базові елементи
npm install @tsparticles/react @tsparticles/engine @tsparticles/slim

# Або повна — усі пресети (~180 КБ gzip)
npm install @tsparticles/react @tsparticles/all

Модульна збірка переважніша — @tsparticles/slim важить ~40 КБ gzip проти ~180 КБ у @tsparticles/all.

Базова інтеграція з React

// components/ParticlesBackground.tsx
'use client'
import { useEffect, useState, useCallback } from 'react'
import Particles, { initParticlesEngine } from '@tsparticles/react'
import { loadSlim } from '@tsparticles/slim'
import type { ISourceOptions } from '@tsparticles/engine'

const particleOptions: ISourceOptions = {
  background: {
    color: { value: 'transparent' },
  },
  fpsLimit: 60,
  interactivity: {
    events: {
      onHover: {
        enable: true,
        mode: 'repulse',  // відтягувати від курсора
      },
      onClick: {
        enable: true,
        mode: 'push',     // додавати частинки при кліку
      },
    },
    modes: {
      repulse: { distance: 100, duration: 0.4 },
      push: { quantity: 4 },
    },
  },
  particles: {
    color: { value: '#3b82f6' },
    links: {
      color: '#3b82f6',
      distance: 150,
      enable: true,
      opacity: 0.3,
      width: 1,
    },
    move: {
      enable: true,
      speed: 1.5,
      direction: 'none',
      random: false,
      straight: false,
      outModes: { default: 'bounce' },
    },
    number: {
      value: 60,
      density: { enable: true, area: 800 },
    },
    opacity: { value: 0.5 },
    shape: { type: 'circle' },
    size: { value: { min: 1, max: 3 } },
  },
  detectRetina: true,
}

export function ParticlesBackground() {
  const [engineReady, setEngineReady] = useState(false)

  useEffect(() => {
    initParticlesEngine(async (engine) => {
      await loadSlim(engine)
    }).then(() => setEngineReady(true))
  }, [])

  if (!engineReady) return null

  return (
    <Particles
      id="tsparticles"
      options={particleOptions}
      className="absolute inset-0 -z-10"
    />
  )
}

Пресет: пов'язана мережа

// presets/network.ts
import type { ISourceOptions } from '@tsparticles/engine'

export const networkPreset: ISourceOptions = {
  fpsLimit: 60,
  particles: {
    number: { value: 80, density: { enable: true, area: 1000 } },
    color: { value: ['#3b82f6', '#8b5cf6', '#06b6d4'] },
    shape: { type: 'circle' },
    opacity: {
      value: { min: 0.3, max: 0.8 },
      animation: { enable: true, speed: 1, minimumValue: 0.1 },
    },
    size: {
      value: { min: 1, max: 4 },
      animation: { enable: true, speed: 2, minimumValue: 0.5 },
    },
    links: {
      enable: true,
      distance: 120,
      color: { value: '#94a3b8' },
      opacity: 0.2,
      width: 1,
      triangles: {
        enable: false,
      },
    },
    move: {
      enable: true,
      speed: { min: 0.5, max: 1.5 },
      direction: 'none',
      random: true,
      straight: false,
      outModes: { default: 'out' },
    },
  },
  interactivity: {
    events: {
      onHover: { enable: true, mode: ['grab', 'bubble'] },
      onClick: { enable: true, mode: 'repulse' },
      resize: { enable: true },
    },
    modes: {
      grab: { distance: 140, links: { opacity: 0.8 } },
      bubble: { distance: 100, size: 8, duration: 0.3, opacity: 0.8 },
      repulse: { distance: 150, duration: 0.4 },
    },
  },
  detectRetina: true,
}

Конфеті при події (успіх, форма відправлена)

// hooks/useConfetti.ts
import { useCallback } from 'react'
import { tsParticles } from '@tsparticles/engine'

export function useConfetti() {
  const fire = useCallback(async (originX = 0.5, originY = 0.6) => {
    await tsParticles.load({
      id: 'confetti-' + Date.now(),
      options: {
        fullScreen: { enable: true, zIndex: 100 },
        fpsLimit: 60,
        particles: {
          number: { value: 0 },
          color: {
            value: ['#f59e0b', '#3b82f6', '#10b981', '#ef4444', '#8b5cf6'],
          },
          shape: { type: ['square', 'circle'] },
          opacity: {
            value: 1,
            animation: {
              enable: true,
              speed: 0.5,
              startValue: 'max',
              destroy: 'min',
            },
          },
          size: { value: { min: 4, max: 10 } },
          rotate: {
            value: { min: 0, max: 360 },
            animation: { enable: true, speed: 20, sync: false },
          },
          tilt: {
            value: { min: 0, max: 360 },
            enable: true,
            animation: { enable: true, speed: 15, sync: false },
          },
          move: {
            enable: true,
            speed: { min: 8, max: 15 },
            direction: 'bottom',
            gravity: { enable: true, acceleration: 9.8 },
            drift: { min: -2, max: 2 },
            decay: { min: 0.02, max: 0.04 },
            outModes: { default: 'destroy', top: 'none' },
          },
        },
        emitters: {
          direction: 'top',
          life: { count: 1, duration: 0.1, delay: 0 },
          rate: { delay: 0, quantity: 150 },
          size: { width: 0, height: 0 },
          position: { x: originX * 100, y: originY * 100 },
        },
      },
    })
  }, [])

  return { fire }
}
// Використання
const { fire } = useConfetti()

const handleFormSubmit = async () => {
  await submitForm()
  fire() // запускаємо конфеті після успіху
}

Продуктивність і відключення на мобільних

// components/ParticlesBackground.tsx (з адаптивом)
import { useEffect, useState } from 'react'

export function ParticlesBackground() {
  const [shouldRender, setShouldRender] = useState(false)

  useEffect(() => {
    // Не рендеримо на слабких пристроях та при prefers-reduced-motion
    const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches
    const isMobile = window.innerWidth < 768
    const isLowEndDevice = navigator.hardwareConcurrency <= 2

    setShouldRender(!reducedMotion && !isMobile && !isLowEndDevice)
  }, [])

  if (!shouldRender) return null

  return <ParticlesCore />
}

Типові терміни

Базовий фон з частинками — 3–4 години. Кілька пресетів з кастомними налаштуваннями, конфеті, адаптивним відключенням та оптимізацією продуктивності — 1–2 робочих дні.