tsParticles 完全ガイド - リッチなパーティクルアニメーションをReactで実装

tsParticles 完全ガイド - リッチなパーティクルアニメーションをReactで実装

作成日:

tsParticlesとは

tsParticlesは、高度にカスタマイズ可能なパーティクルアニメーションを作成するためのJavaScriptライブラリです。かつて人気を博した「particles.js」の後継として開発され、TypeScriptで書き直されたモダンなライブラリです。

Webサイトの背景に漂う幻想的なパーティクル、成功時の紙吹雪エフェクト、冬をテーマにした雪、お祝いの花火など、様々な視覚効果を簡単に実装できます。ゲーム、ランディングページ、ポートフォリオサイトなど、ユーザーの目を引く演出が必要なあらゆる場面で活躍します。

主な特徴

  • 多様なエフェクト: 紙吹雪、雪、星空、花火、バブルなど、すぐに使えるプリセットが豊富
  • 高いカスタマイズ性: パーティクルの形状、色、動き、インタラクションを細かく設定可能
  • フレームワーク対応: React、Vue、Angular、Svelte、Solid など主要なフレームワークをサポート
  • 軽量バンドル: 必要な機能だけを読み込める(slim、basic、full)ため、バンドルサイズを最適化
  • インタラクティブ: マウスホバー、クリック、タッチ操作に反応するアニメーションを簡単に実装
  • TypeScript対応: 完全な型サポートにより、開発時の補完と型チェックが可能

インストール

tsParticlesはモジュール化されており、必要な機能に応じてパッケージを選択できます。React/Next.jsで使用する場合は、Reactバインディングと機能バンドルの2つをインストールします。

Shell
npm install @tsparticles/react @tsparticles/slim

バンドルの種類

tsParticlesは用途に応じて3種類のバンドルを提供しています。プロジェクトの要件に合わせて適切なバンドルを選択することで、最終的なバンドルサイズを最適化できます。

バンドルサイズ用途
@tsparticles/slim小(約50KB gzipped)基本的なエフェクト(推奨)。links、move、opacity、sizeなど
@tsparticles/basic最小(約30KB gzipped)最小限の機能のみ。シンプルなパーティクル表示
tsparticles大(約100KB+ gzipped)全機能。花火、エミッター、absorbers、polygon maskなど

選び方の目安:

  • ほとんどのケース: @tsparticles/slim で十分です
  • シンプルな背景パーティクルのみ: @tsparticles/basic でサイズ節約
  • 花火、エミッター、複雑なエフェクト: tsparticles(full)が必要

紙吹雪パッケージ

紙吹雪(confetti)エフェクトを使用する場合は、専用のパッケージをインストールします。このパッケージは他のバンドルとは独立しており、紙吹雪のみを軽量に実装できます。

Shell
npm install @tsparticles/confetti

基本的な使い方

tsParticlesをReact/Next.jsで使用するには、Particlesコンポーネントと初期化関数を組み合わせます。Next.js App Routerを使用している場合は、クライアントコンポーネントとして宣言する必要があります。

Reactコンポーネントの基本構造

以下は最もシンプルな実装例です。エンジンの初期化、パーティクルの設定、コンテナの読み込み完了時のコールバックという3つの要素で構成されています。

TypeScript
'use client'
 
import { useCallback } from 'react'
import Particles from '@tsparticles/react'
import type { Container, Engine } from '@tsparticles/engine'
import { loadSlim } from '@tsparticles/slim'
 
export function ParticlesDemo() {
  // エンジンの初期化
  const particlesInit = useCallback(async (engine: Engine) => {
    await loadSlim(engine)
  }, [])
 
  // コンテナ読み込み完了時のコールバック
  const particlesLoaded = useCallback(async (container?: Container) => {
    console.log('Particles loaded:', container?.id)
  }, [])
 
  return (
    <Particles
      id="tsparticles"
      init={particlesInit}
      loaded={particlesLoaded}
      options={{
        background: {
          color: { value: '#0d1117' },
        },
        particles: {
          number: { value: 80 },
          color: { value: '#667eea' },
          links: {
            enable: true,
            distance: 150,
            color: '#667eea',
          },
          move: {
            enable: true,
            speed: 2,
          },
        },
      }}
    />
  )
}

Loading...

上のデモでは、マウスをホバーするとパーティクルが反発(repulse)し、クリックすると新しいパーティクルが追加(push)されます。このようなインタラクティブな動作は、interactivityオプションで簡単に設定できます。

パーティクル設定の詳細

tsParticlesの設定は大きく分けて「particles(パーティクル自体の設定)」と「interactivity(ユーザー操作への反応)」の2つに分かれます。ここでは各オプションの詳細を解説します。

particles オプション

particlesオプションでは、パーティクルの数、色、形状、サイズ、動き、接続線など、パーティクル自体の見た目と動作を定義します。

TypeScript
particles: {
  // パーティクル数
  number: {
    value: 80,
    density: {
      enable: true,
      // 800px²あたりのパーティクル数
    },
  },
  
  // 色(単一または配列)
  color: {
    value: ['#667eea', '#764ba2', '#f093fb'],
  },
  
  // 形状
  shape: {
    type: 'circle', // circle, square, polygon, star, image, emoji
    options: {
      polygon: { sides: 6 },
      star: { sides: 5, inset: 2 },
    },
  },
  
  // 透明度
  opacity: {
    value: { min: 0.3, max: 0.8 },
    animation: {
      enable: true,
      speed: 1,
      sync: false,
    },
  },
  
  // サイズ
  size: {
    value: { min: 1, max: 5 },
    animation: {
      enable: true,
      speed: 3,
    },
  },
  
  // 移動
  move: {
    enable: true,
    speed: 2,
    direction: 'none', // none, top, bottom, left, right, etc.
    random: false,
    straight: false,
    outModes: {
      default: 'out', // out, bounce, destroy, none
    },
  },
  
  // パーティクル間のリンク線
  links: {
    enable: true,
    distance: 150,
    color: '#667eea',
    opacity: 0.4,
    width: 1,
  },
}

interactivity オプション

interactivityオプションでは、マウスやタッチ操作に対するパーティクルの反応を定義します。ホバー時とクリック時に異なるモードを設定でき、ユーザーとのインタラクションを演出できます。

モード説明
grabパーティクルとマウスの間に線を描画
repulseパーティクルがマウスから逃げる
bubbleパーティクルがマウス付近で大きくなる
attractパーティクルがマウスに引き寄せられる
pushクリックで新しいパーティクルを追加
removeクリックでパーティクルを削除
TypeScript
interactivity: {
  events: {
    onHover: {
      enable: true,
      mode: 'grab', // grab, repulse, bubble, attract
    },
    onClick: {
      enable: true,
      mode: 'push', // push, remove, bubble, repulse
    },
  },
  modes: {
    grab: {
      distance: 200,
      links: {
        opacity: 0.8,
        color: '#ff0000',
      },
    },
    repulse: {
      distance: 100,
      duration: 0.4,
    },
    bubble: {
      distance: 200,
      size: 20,
      duration: 2,
      opacity: 1,
    },
    attract: {
      distance: 200,
      duration: 0.4,
    },
    push: {
      quantity: 4,
    },
  },
}

Loading...

上のデモでは、マウスをホバーするとパーティクルとの間に線が描画され(grab)、パーティクルがマウスに引き寄せられます(attract)。クリックするとパーティクルが追加されます。これらのインタラクションを組み合わせることで、ユーザーを引き込む体験を作り出せます。


紙吹雪(Confetti)エフェクト

紙吹雪エフェクトは、フォーム送信成功、目標達成、お祝いの演出など、ポジティブなフィードバックを視覚的に表現するのに最適です。@tsparticles/confettiパッケージを使用すると、わずか数行のコードで本格的な紙吹雪を実装できます。

紙吹雪はワンショット(一度だけ発射)のエフェクトなので、イベントハンドラ内で呼び出すのが一般的です。

TypeScript
import { confetti } from '@tsparticles/confetti'
 
// 基本的な紙吹雪
await confetti({
  particleCount: 100,
  spread: 70,
  origin: { y: 0.6 },
})
 
// カスタマイズ
await confetti({
  particleCount: 150,
  angle: 60,
  spread: 55,
  origin: { x: 0, y: 0.5 },
  colors: ['#bb0000', '#ffffff', '#0000bb'],
  shapes: ['circle', 'square', 'star'],
  scalar: 1.2,
  gravity: 1,
  drift: 0.5,
  ticks: 200,
})

Confettiオプション

オプション説明デフォルト
particleCountパーティクル数50
spread拡散角度(度)45
angle発射角度(度)90
origin発射位置 { x, y }{ x: 0.5, y: 0.5 }
colors色の配列デフォルト色
shapes形状の配列['square', 'circle']
gravity重力1
drift横方向のドリフト0
ticksアニメーションフレーム数200
scalarサイズ倍率1

紙吹雪エフェクト(Confetti)

ボタンをクリックして紙吹雪を発射!


雪エフェクト

冬をテーマにしたWebサイト、クリスマスキャンペーン、季節限定のランディングページなどに最適な雪エフェクトです。パーティクルを上から下に落下させ、drift(横揺れ)とwobble(ふらつき)を組み合わせることで、自然な雪の動きを再現できます。

雪エフェクトのポイントは、パーティクルのサイズと速度にバリエーションを持たせることです。小さく遠くにある雪はゆっくり、大きく近くの雪は速く落下するように設定すると、奥行き感のある演出になります。

TypeScript
const snowOptions = {
  particles: {
    number: { value: 150 },
    color: { value: '#ffffff' },
    shape: { type: 'circle' },
    opacity: {
      value: { min: 0.3, max: 0.8 },
    },
    size: {
      value: { min: 1, max: 5 },
    },
    move: {
      enable: true,
      speed: { min: 1, max: 3 },
      direction: 'bottom',
      drift: {
        min: -0.5,
        max: 0.5,
      },
    },
    wobble: {
      enable: true,
      distance: 10,
      speed: 10,
    },
  },
}

wobbleオプション

wobbleを使用すると、パーティクルがふらふらと揺れながら落下する自然な動きを実現できます。

Loading...


星空エフェクト

夜空の星をテーマにしたエフェクトです。ポートフォリオサイト、ゲームのタイトル画面、瞑想アプリなど、落ち着いた雰囲気や幻想的な演出を求める場面で活躍します。

星空エフェクトの魅力はtwinkle(瞬き)オプションです。これにより、星がランダムに明滅し、実際の夜空のような動きを再現できます。また、複数の色(白、金、水色など)を組み合わせることで、より自然な星空を表現できます。

TypeScript
const starsOptions = {
  particles: {
    number: { value: 200 },
    color: {
      value: ['#ffffff', '#ffd700', '#87ceeb', '#ffa500'],
    },
    opacity: {
      value: { min: 0.1, max: 1 },
      animation: {
        enable: true,
        speed: 1,
      },
    },
    size: {
      value: { min: 0.5, max: 3 },
    },
    move: {
      enable: true,
      speed: 0.3,
      random: true,
    },
    // 星の瞬き
    twinkle: {
      particles: {
        enable: true,
        frequency: 0.05,
        opacity: 1,
        color: { value: '#ffff00' },
      },
    },
  },
}

Loading...


バブルエフェクト

水中やアクアリウムをテーマにしたエフェクトです。飲料メーカーのサイト、スパ・リラクゼーション関連、水族館のWebサイトなど、水や清涼感を演出したい場面に適しています。

バブルエフェクトの特徴は、下から上に浮かび上がる動きと、emitters(エミッター)による定期的なパーティクル生成です。エミッターを使用すると、特定の位置から継続的にパーティクルを発生させることができます。また、stroke(境界線)を追加することで、泡の輪郭を表現できます。

TypeScript
const bubbleOptions = {
  particles: {
    number: { value: 30 },
    color: {
      value: ['#90e0ef', '#caf0f8', '#ffffff'],
    },
    shape: { type: 'circle' },
    size: {
      value: { min: 5, max: 30 },
    },
    stroke: {
      width: 1,
      color: { value: '#ffffff' },
    },
    move: {
      enable: true,
      speed: { min: 1, max: 3 },
      direction: 'top',
      outModes: {
        top: 'destroy',
        bottom: 'none',
      },
    },
    life: {
      duration: {
        value: 5,
      },
      count: 1,
    },
  },
  // エミッター(発生源)
  emitters: {
    direction: 'top',
    position: {
      x: 50,
      y: 100,
    },
    rate: {
      delay: 0.2,
      quantity: 2,
    },
    size: {
      width: 100,
      height: 0,
    },
  },
}

Loading...


絵文字パーティクル

絵文字をパーティクルとして使用できる、遊び心のあるエフェクトです。SNSアプリ、ゲーム、キッズ向けサイト、イベントページなど、カジュアルで楽しい雰囲気を演出したい場面に最適です。

emojiシェイプを使用すると、任意の絵文字をパーティクルとして表示できます。複数の絵文字を配列で指定すると、ランダムに選択されて表示されます。また、rotateオプションでパーティクルを回転させることで、より動きのある演出になります。

TypeScript
const emojiOptions = {
  particles: {
    number: { value: 40 },
    shape: {
      type: 'emoji',
      options: {
        emoji: {
          value: ['🎉', '🎊', '🎈', '🎁', '', '🌟', '💫'],
        },
      },
    },
    size: {
      value: { min: 20, max: 40 },
    },
    rotate: {
      value: { min: 0, max: 360 },
      animation: {
        enable: true,
        speed: 5,
      },
    },
    move: {
      enable: true,
      speed: { min: 1, max: 3 },
      outModes: {
        default: 'bounce',
      },
    },
  },
}

Loading...


花火エフェクト

打ち上げ花火を再現した、最も華やかなエフェクトです。新年のカウントダウン、記念日のお祝い、達成報告など、特別な瞬間を演出するのに最適です。

花火エフェクトは、tsParticlesの中でも最も複雑な設定を必要とします。仕組みとしては:

  1. エミッターが打ち上げパーティクル(白い光点)を下から上に発射
  2. 打ち上げパーティクルが重力の影響で減速
  3. パーティクルの寿命が尽きるとdestroy.mode: 'split'により分裂
  4. 分裂した多数のパーティクルが重力で落下しながら消えていく

この一連の流れを実現するため、fullバンドルtsparticles)が必要です。@tsparticles/slimにはemittersとsplit機能が含まれていません。

TypeScript
const fireworksOptions = {
  particles: {
    number: { value: 0 },
    // ... 基本設定
    destroy: {
      mode: 'split',
      split: {
        count: 50, // 分裂するパーティクル数
        factor: {
          value: 3,
        },
        rate: {
          value: 1,
        },
        particles: {
          color: {
            value: ['#ff0000', '#ffa500', '#ffff00'],
          },
          opacity: {
            animation: {
              enable: true,
              speed: 1,
              destroy: 'min',
            },
          },
          move: {
            speed: { min: 5, max: 15 },
            gravity: {
              enable: true,
              acceleration: 10,
            },
          },
          life: {
            duration: {
              value: { min: 1, max: 2 },
            },
            count: 1,
          },
        },
      },
    },
  },
  emitters: [
    {
      direction: 'top',
      position: { x: 50, y: 100 },
      rate: {
        delay: 1.5,
        quantity: 1,
      },
      // 打ち上げパーティクルの設定
      particles: {
        move: {
          speed: 35,
          direction: 'top',
          gravity: {
            enable: true,
            acceleration: 5,
          },
        },
        life: {
          duration: { value: 1.2 },
          count: 1,
        },
        destroy: {
          mode: 'split',
          // 上記の分裂設定
        },
      },
    },
  ],
}

Loading...


パフォーマンス最適化

パーティクルアニメーションはCPU/GPUリソースを消費するため、特にモバイルデバイスではパフォーマンスに注意が必要です。以下のベストプラクティスを参考に、スムーズなアニメーションを維持しましょう。

1. 適切なバンドルを選択

必要な機能に応じて最小限のバンドルを選択することで、初期読み込み時間を短縮できます。ほとんどのユースケースでは@tsparticles/slimで十分です。

TypeScript
// 基本機能のみ(推奨)
import { loadSlim } from '@tsparticles/slim'
 
// 最小限の機能
import { loadBasic } from '@tsparticles/basic'
 
// 全機能(サイズ大)
import { loadFull } from 'tsparticles'

2. パーティクル数の制限

パーティクル数はパフォーマンスに直接影響します。デスクトップでは100個程度でも問題ありませんが、モバイルでは50個以下を推奨します。densityを有効にすると、画面サイズに応じて自動的にパーティクル数が調整されます。

TypeScript
particles: {
  number: {
    value: 80, // モバイルでは50以下を推奨
    density: {
      enable: true, // 画面サイズに応じて自動調整
    },
  },
}

3. FPSの制限

アニメーションのフレームレートを制限することで、不必要なリソース消費を抑えられます。多くの場合、60fpsで十分滑らかに見えます。バッテリー消費を抑えたい場合は30fpsも検討してください。

TypeScript
{
  fpsLimit: 60, // 60fpsに制限
  detectRetina: true, // Retinaディスプレイ対応
}

4. 不要な機能の無効化

使用しない機能は明示的に無効化しましょう。特にlinks(接続線)は多くのパーティクル間で計算が必要なため、パフォーマンスへの影響が大きいです。

TypeScript
particles: {
  links: {
    enable: false, // リンク線を使わない場合は無効化
  },
  opacity: {
    animation: {
      enable: false, // アニメーション不要なら無効化
    },
  },
}

実践的なユースケース

ここでは、実際のWebサイトでよく使われるパターンと、そのための設定例を紹介します。

ヒーローセクションの背景

ランディングページやポートフォリオサイトのファーストビューに最適な、シンプルで高パフォーマンスな設定です。背景を透明にすることで、既存のデザインに自然に溶け込みます。パフォーマンスを考慮して、パーティクル数を少なく、速度を遅くしています。

TypeScript
// シンプルで高パフォーマンスな設定
const heroBackground = {
  background: {
    color: { value: 'transparent' },
  },
  particles: {
    number: { value: 50 },
    color: { value: '#ffffff' },
    opacity: { value: 0.3 },
    size: { value: { min: 1, max: 3 } },
    move: {
      enable: true,
      speed: 0.5,
    },
  },
}

ボタンホバーエフェクト

CTAボタンにホバーした際にパーティクルが追従する、インタラクティブな演出です。trailモードを使用すると、マウスの軌跡に沿ってパーティクルが生成されます。ゲームサイトやクリエイティブなポートフォリオに効果的です。

TypeScript
const buttonHoverEffect = {
  particles: {
    number: { value: 0 },
    // ...
  },
  interactivity: {
    events: {
      onHover: {
        enable: true,
        mode: 'trail',
      },
    },
    modes: {
      trail: {
        delay: 0.005,
        quantity: 5,
      },
    },
  },
}

成功時のお祝いエフェクト

フォーム送信完了、購入完了、ゲームクリア、目標達成など、ユーザーの成功体験を祝福する演出です。複数回のconfetti呼び出しを組み合わせることで、より華やかなエフェクトを作成できます。

以下の例では、異なるパラメータで複数回発射することで、まるで本物のクラッカーのような演出を実現しています。

TypeScript
import { confetti } from '@tsparticles/confetti'
 
async function celebrateSuccess() {
  // 複数方向から発射して華やかに
  const count = 200
  const defaults = { origin: { y: 0.7 } }
 
  function fire(particleRatio: number, opts: object) {
    confetti({
      ...defaults,
      ...opts,
      particleCount: Math.floor(count * particleRatio),
    })
  }
 
  fire(0.25, { spread: 26, startVelocity: 55 })
  fire(0.2, { spread: 60 })
  fire(0.35, { spread: 100, decay: 0.91, scalar: 0.8 })
  fire(0.1, { spread: 120, startVelocity: 25, decay: 0.92, scalar: 1.2 })
  fire(0.1, { spread: 120, startVelocity: 45 })
}

まとめ

tsParticlesは、Webサイトに視覚的なインパクトを与える強力なツールです。シンプルな背景パーティクルから複雑な花火まで、様々なエフェクトを比較的少ないコードで実装できます。

tsParticlesの利点

特徴説明
多機能紙吹雪、雪、星空、花火など多彩なエフェクト
カスタマイズ性細かい設定で独自のエフェクトを作成可能
パフォーマンス軽量バンドルと最適化オプション
インタラクティブユーザー操作に反応するアニメーション
型安全TypeScript完全対応

使い分けガイド

  • シンプルな背景アニメーション: @tsparticles/slim
  • 紙吹雪のみ: @tsparticles/confetti
  • 花火、エミッター: tsparticles(full)

注意点

  • アクセシビリティ: 動きの多いアニメーションは、前庭障害のあるユーザーに不快感を与える可能性があります。prefers-reduced-motionメディアクエリに対応し、アニメーションを無効化するオプションを提供することを検討してください。
  • パフォーマンス: モバイルデバイスでは特にパフォーマンスに注意し、パーティクル数を抑えめに設定しましょう。
  • 適度な使用: パーティクルエフェクトは「スパイス」として使うのが効果的です。過度に使用するとユーザーの注意を散漫にし、本来のコンテンツから目をそらしてしまう可能性があります。

tsParticlesを活用して、ユーザーを魅了するリッチなWebエクスペリエンスを作成しましょう!

参考リンク