ashish rajwani

3d animated stars background

Component 3

About

a beautiful mouse react background.

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds 3d animated stars background to your project and fits it to your theme.

Code

How 3d animated stars background is used: the demo's code. The component's own source comes with a free account.

Usage.tsx


import React, { useRef, useMemo, useEffect } from 'react';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import * as THREE from 'three';
import { Bloom, EffectComposer, Noise, Vignette } from '@react-three/postprocessing';

/**
 * CrystallineParticle System
 * Features:
 * - Interactive magnetic fluid dynamics
 * - Hair-thin filaments (connections)
 * - Kinetic ripple pulses on click
 * - Bioluminescent styling (Cyan/Indigo)
 */

const PARTICLE_COUNT = 800;
const MAX_DISTANCE = 1.2;

const NeuralLattice: React.FC = () => {
  const meshRef = useRef<THREE.Points>(null!);
  const lineRef = useRef<THREE.LineSegments>(null!);
  const mouse = useRef(new THREE.Vector2(0, 0));
  const ripple = useRef({ active: false, radius: 0, origin: new THREE.Vector3() });

  const { viewport } = useThree();

  // Create initial nodes
  const nodes = useMemo(() => {
    return Array.from({ length: PARTICLE_COUNT }).map(() => ({
      position: new THREE.Vector3(
        (Math.random() - 0.5) * 10,
        (Math.random() - 0.5) * 10,
        (Math.random() - 0.5) * 10
      ),
      velocity: new THREE.Vector3(
        (Math.random() - 0.5) * 0.005,
        (Math.random() - 0.5) * 0.005,
        (Math.random() - 0.5) * 0.005
      ),
      basePos: new THREE.Vector3(),
    }));
  }, []);

  // Buffer setups
  const [particlePositions, particleColors] = useMemo(() => {
    const pos = new Float32Array(PARTICLE_COUNT * 3);
    const col = new Float32Array(PARTICLE_COUNT * 3);
    const colorA = new THREE.Color('#00f2ff');
    const colorB = new THREE.Color('#7000ff');

    for (let i = 0; i < PARTICLE_COUNT; i++) {
      const mixed = colorA.clone().lerp(colorB, Math.random());
      col[i * 3] = mixed.r;
      col[i * 3 + 1] = mixed.g;
      col[i * 3 + 2] = mixed.b;
    }
    return [pos, col];
  }, []);

  useFrame((state) => {
    const time = state.clock.getElapsedTime();
    const positions = meshRef.current.geometry.attributes.position.array as Float32Array;
    const linePositions: number[] = [];
    const lineColors: number[] = [];
    
    // Smooth mouse follow
    mouse.current.lerp(new THREE.Vector2(state.mouse.x * viewport.width / 2, state.mouse.y * viewport.height / 2), 0.1);

    // Update ripple
    if (ripple.current.active) {
      ripple.current.radius += 0.15;
      if (ripple.current.radius > 15) ripple.current.active = false;
    }

    nodes.forEach((node, i) => {
      // 1. Ambient Movement (Harmonic drift)
      node.position.x += node.velocity.x + Math.sin(time + i) * 0.001;
      node.position.y += node.velocity.y + Math.cos(time + i) * 0.001;
      node.position.z += node.velocity.z;

      // 2. Magnetic Mouse Interaction
      const dx = node.position.x - mouse.current.x;
      const dy = node.position.y - mouse.current.y;
      const dist = Math.sqrt(dx * dx + dy * dy);
      if (dist < 2.5) {
        const force = (1 - dist / 2.5) * 0.02;
        node.position.x += dx * force;
        node.position.y += dy * force;
      }

      // 3. Pulse interaction
      if (ripple.current.active) {
        const rDist = node.position.distanceTo(ripple.current.origin);
        const rDiff = Math.abs(rDist - ripple.current.radius);
        if (rDiff < 0.5) {
          const force = (1 - rDiff / 0.5) * 0.1;
          node.position.z += force;
        }
      }

      // 4. Boundary Logic
      if (Math.abs(node.position.x) > 6) node.velocity.x *= -1;
      if (Math.abs(node.position.y) > 6) node.velocity.y *= -1;
      if (Math.abs(node.position.z) > 6) node.velocity.z *= -1;

      positions[i * 3] = node.position.x;
      positions[i * 3 + 1] = node.position.y;
      positions[i * 3 + 2] = node.position.z;

      // 5. Build Filaments (Lines)
      // We skip most comparisons for performance, only check next N neighbors
      for (let j = i + 1; j < i + 15; j++) {
        const other = nodes[j % PARTICLE_COUNT];
        const d = node.position.distanceTo(other.position);
        if (d < MAX_DISTANCE) {
          linePositions.push(node.position.x, node.position.y, node.position.z);
          linePositions.push(other.position.x, other.position.y, other.position.z);
          
          const alpha = (1 - d / MAX_DISTANCE) * 0.4;
          const r = 0.2 + alpha;
          const g = 0.5 + alpha;
          const b = 0.9 + alpha;
          lineColors.push(r, g, b, r, g, b);
        }
      }
    });

    meshRef.current.geometry.attributes.position.needsUpdate = true;
    lineRef.current.geometry.setAttribute('position', new THREE.Float32BufferAttribute(linePositions, 3));
    lineRef.current.geometry.setAttribute('color', new THREE.Float32BufferAttribute(lineColors, 3));
    
    // Slow rotation
    meshRef.current.rotation.y = time * 0.05;
    lineRef.current.rotation.y = time * 0.05;
  });

  const handlePointerDown = (e: any) => {
    ripple.current.active = true;
    ripple.current.radius = 0;
    ripple.current.origin.set(
      (e.clientX / window.innerWidth) * 2 - 1,
      -(e.clientY / window.innerHeight) * 2 + 1,
      0.5
    ).unproject(e.camera);
  };

  return (
    <group onPointerDown={handlePointerDown}>
      <points ref={meshRef}>
        <bufferGeometry>
          <bufferAttribute
            attach="attributes-position"
            count={PARTICLE_COUNT}
            array={particlePositions}
            itemSize={3}
          />
          <bufferAttribute
            attach="attributes-color"
            count={PARTICLE_COUNT}
            array={particleColors}
            itemSize={3}
          />
        </bufferGeometry>
        <pointsMaterial
          size={0.015}
          vertexColors
          transparent
          opacity={0.8}
          blending={THREE.AdditiveBlending}
          sizeAttenuation={true}
        />
      </points>

      <lineSegments ref={lineRef}>
        <bufferGeometry />
        <lineBasicMaterial 
          vertexColors 
          transparent 
          opacity={0.3} 
          blending={THREE.AdditiveBlending} 
          linewidth={1}
        />
      </lineSegments>
    </group>
  );
};

export default function CrystallineNeuralBackground() {
  return (
    <div className="fixed inset-0 w-full h-full bg-[#020205] overflow-hidden">
      {/* Cinematic Grain Overlay */}
      <div 
        className="absolute inset-0 pointer-events-none opacity-[0.03] z-20"
        style={{
          backgroundImage: `url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E")`
        }}
      />
      
      {/* Glassmorphism Vignette */}
      <div className="absolute inset-0 z-10 pointer-events-none bg-[radial-gradient(circle_at_center,transparent_0%,rgba(2,2,5,0.6)_100%)]" />

      <Canvas
        camera={{ position: [0, 0, 5], fov: 60 }}
        dpr={[1, 2]}
      >
        <color attach="background" args={['#020205']} />
        
        <NeuralLattice />

        <EffectComposer disableNormalPass>
          <Bloom 
            luminanceThreshold={0.2} 
            mipmapBlur 
            intensity={1.5} 
            radius={0.4} 
          />
          <Noise opacity={0.05} />
          <Vignette eskil={false} offset={0.1} darkness={1.1} />
        </EffectComposer>
      </Canvas>

      {/* Foreground Example */}
      <div className="absolute inset-0 flex flex-col items-center justify-center pointer-events-none z-30 px-6">
        <div className="max-w-xl text-center">
          <h1 className="text-white/20 text-5xl md:text-7xl font-thin tracking-[1em] uppercase mb-8 select-none">
            Void
          </h1>
          <div className="h-[1px] w-32 bg-gradient-to-r from-transparent via-cyan-500/30 to-transparent mx-auto mb-8" />
          <p className="text-cyan-100/30 font-mono text-xs tracking-[0.3em] uppercase leading-loose select-none">
            Generative Neural Architecture<br/>
            Crystalline Dynamics v.04
          </p>
        </div>
      </div>
    </div>
  );
}

More by ashish rajwani

View all
  • ASMR background

    ASMR background

    684
  • animated pattern cloud

    animated pattern cloud

    616
  • Balloons Pop background

    Balloons Pop background

    362
  • realistic fog background

    realistic fog background

    309
  • Matrix background

    Matrix background

    1
  • tab pages

    tab pages

    1
  • sleek text input

    sleek text input

  • Botanical background

    Botanical background