Motiva
Мои коллекции
← каталог

Particle Field

Медленно дрейфующее 3D-поле из ~1800 частиц — фон на настоящем WebGL (React Three Fiber).

threeautoparallaxintermediate~160 КБreduced-motion ✓

Установка

npx shadcn@latest add https://motiva.pages.dev/r/particle-field.json

зависимости: three@^0.185.1 · @react-three/fiber@^9.6.1

Что нужно в проекте до установки
  1. components.json в корне — с алиасами в форме"components": "@/components". Нет файла — CLI не поймёт, куда класть.
  2. Алиас @ объявлен дважды: "paths": {"@/*": ["./src/*"]} в корневом tsconfig.json (в Vite он часто содержит только references — тогда CLI создаёт папку@) и resolve.alias в конфиге сборщика.
  3. Токены подключены один раз на приложение:import "@/styles/motiva-tokens.css" — они приезжают вместе с записью. Без них секция потеряет цвета, ритм и тему.
  4. Своя типографика не должна спорить: если у вас на обёрткеtext-align: center, он протечёт внутрь блоков.
  5. Проект без TypeScript? Всё равно нужен минимальныйtsconfig.json с pathsи "tsx": true в components.json: CLI грузит tsconfig безусловно, а с "tsx": false идёт за jsconfig.json и падает так же. Приехавший рядом.tsx можно не трогать — вам нужен.vanilla.js.

Экспорт

↓ Скачать .zip

Код

"use client";

import { Canvas, useFrame } from "@react-three/fiber";
import { useMemo, useRef } from "react";
import * as THREE from "three";

function Particles({ count = 1800 }: { count?: number }) {
  const ref = useRef<THREE.Points>(null);
  const positions = useMemo(() => {
    const a = new Float32Array(count * 3);
    for (let i = 0; i < count * 3; i++) a[i] = (Math.random() - 0.5) * 11;
    return a;
  }, [count]);

  useFrame((s) => {
    if (!ref.current) return;
    ref.current.rotation.y = s.clock.elapsedTime * 0.04;
    ref.current.rotation.x = s.clock.elapsedTime * 0.02;
  });

  return (
    <points ref={ref}>
      <bufferGeometry>
        <bufferAttribute attach="attributes-position" args={[positions, 3]} />
      </bufferGeometry>
      <pointsMaterial size={0.03} color="#38bdf8" transparent opacity={0.85} sizeAttenuation depthWrite={false} />
    </points>
  );
}

/** Дрейфующее 3D-поле частиц (React Three Fiber). `?noanim`/data-shot → стоп-кадр. */
export function ParticleField() {
  const frozen =
    typeof document !== "undefined" && document.documentElement.hasAttribute("data-shot");

  return (
    <div style={{ position: "absolute", inset: 0 }}>
      <Canvas camera={{ position: [0, 0, 6], fov: 60 }} frameloop={frozen ? "demand" : "always"} dpr={[1, 2]}>
        <Particles />
      </Canvas>
    </div>
  );
}
лицензия: MITавтор: Motivaисточник: оригинал (Motiva)v1.0.0