VeloxUI
3d·free

Hero Orb

Cursor-reactive floating distorted orb — a drop-in 3D hero backdrop.

Installation

terminal
pnpm add three @react-three/fiber @react-three/drei

Then copy the component below into src/components/three/hero-orb.tsx. It expects @/lib/gsap (plugin registration) and @/lib/utils (cn).

Source

src/components/three/hero-orb.tsx
"use client";

import { Suspense, useRef } from "react";
import { Canvas, useFrame } from "@react-three/fiber";
import { Float, MeshDistortMaterial, Environment, ContactShadows, Lightformer } from "@react-three/drei";
import type { Mesh } from "three";
import { cn } from "@/lib/utils";

export interface HeroOrbProps {
  className?: string;
  color?: string;
  /** Surface distortion amount (0–1). */
  distort?: number;
  speed?: number;
  wireframe?: boolean;
}

function Orb({ color, distort, speed, wireframe }: Required<Omit<HeroOrbProps, "className">>) {
  const mesh = useRef<Mesh>(null);
  useFrame((state) => {
    if (!mesh.current) return;
    const { x, y } = state.pointer;
    mesh.current.rotation.x += (y * 0.4 - mesh.current.rotation.x) * 0.05;
    mesh.current.rotation.y += (x * 0.6 - mesh.current.rotation.y) * 0.05;
  });
  return (
    <Float speed={speed * 2} rotationIntensity={0.6} floatIntensity={1.2}>
      <mesh ref={mesh} castShadow>
        <icosahedronGeometry args={[1.6, 64]} />
        <MeshDistortMaterial
          color={color}
          distort={distort}
          speed={speed * 2}
          roughness={0.15}
          metalness={0.6}
          wireframe={wireframe}
        />
      </mesh>
    </Float>
  );
}

/** A floating, cursor-reactive distorted orb — drop-in 3D hero backdrop. */
export function HeroOrb({
  className,
  color = "#7c5cff",
  distort = 0.45,
  speed = 1,
  wireframe = false,
}: HeroOrbProps) {
  return (
    <div className={cn("relative h-[480px] w-full", className)}>
      <Canvas camera={{ position: [0, 0, 6], fov: 40 }} dpr={[1, 1.75]} gl={{ antialias: true, alpha: true }}>
        <Suspense fallback={null}>
          <ambientLight intensity={0.4} />
          <directionalLight position={[4, 6, 4]} intensity={1.4} />
          <Orb color={color} distort={distort} speed={speed} wireframe={wireframe} />
          <ContactShadows position={[0, -2.2, 0]} opacity={0.5} blur={2.5} far={4} />
          <Environment resolution={256}>
            <Lightformer intensity={2} position={[0, 5, -6]} scale={[10, 4, 1]} />
            <Lightformer intensity={1.5} color="#22d3ee" position={[-6, 2, 2]} rotation-y={Math.PI / 2} scale={[6, 3, 1]} />
            <Lightformer intensity={1.5} color="#7c5cff" position={[6, -1, 2]} rotation-y={-Math.PI / 2} scale={[6, 3, 1]} />
          </Environment>
        </Suspense>
      </Canvas>
    </div>
  );
}