107 lines
3.3 KiB
TypeScript
107 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import { useRef, useState } from "react";
|
|
import { Canvas, useFrame } from "@react-three/fiber";
|
|
import {
|
|
Float,
|
|
MeshDistortMaterial,
|
|
Environment,
|
|
ContactShadows,
|
|
Lightformer,
|
|
PerspectiveCamera
|
|
} from "@react-three/drei";
|
|
import * as THREE from "three";
|
|
import { useTheme } from "next-themes";
|
|
|
|
function FloatingShape() {
|
|
const mesh = useRef<THREE.Mesh>(null);
|
|
const { theme, resolvedTheme } = useTheme();
|
|
const [hovered, setHovered] = useState(false);
|
|
|
|
const currentTheme = theme === "system" ? resolvedTheme : theme;
|
|
const isDark = currentTheme === "dark";
|
|
|
|
const color = isDark ? "#6366f1" : "#8b5cf6"; // primary or accent colors
|
|
const emissive = isDark ? "#3730a3" : "#4c1d95";
|
|
|
|
// Animate on interaction
|
|
useFrame((state) => {
|
|
if (mesh.current) {
|
|
mesh.current.rotation.x = THREE.MathUtils.lerp(mesh.current.rotation.x, hovered ? state.mouse.y * 0.5 : state.clock.getElapsedTime() * 0.2, 0.1);
|
|
mesh.current.rotation.y = THREE.MathUtils.lerp(mesh.current.rotation.y, hovered ? state.mouse.x * 0.5 : state.clock.getElapsedTime() * 0.3, 0.1);
|
|
}
|
|
});
|
|
|
|
return (
|
|
<Float
|
|
speed={4}
|
|
rotationIntensity={1}
|
|
floatIntensity={2}
|
|
>
|
|
<mesh
|
|
ref={mesh}
|
|
onPointerOver={() => setHovered(true)}
|
|
onPointerOut={() => setHovered(false)}
|
|
scale={hovered ? 1.1 : 1}
|
|
>
|
|
<torusKnotGeometry args={[1.2, 0.4, 256, 64]} />
|
|
<MeshDistortMaterial
|
|
color={color}
|
|
envMapIntensity={isDark ? 0.8 : 0.4}
|
|
clearcoat={0.9}
|
|
clearcoatRoughness={0.1}
|
|
metalness={0.9}
|
|
roughness={0.1}
|
|
distort={0.4}
|
|
speed={3}
|
|
emissive={emissive}
|
|
emissiveIntensity={0.2}
|
|
/>
|
|
</mesh>
|
|
</Float>
|
|
);
|
|
}
|
|
|
|
export default function Hero3D() {
|
|
const { theme, resolvedTheme } = useTheme();
|
|
const currentTheme = theme === "system" ? resolvedTheme : theme;
|
|
const isDark = currentTheme === "dark";
|
|
|
|
return (
|
|
<div className="absolute inset-0 w-full h-full -z-10 opacity-70">
|
|
<Canvas shadows camera={{ position: [0, 0, 5], fov: 45 }}>
|
|
<PerspectiveCamera makeDefault position={[0, 0, 5]} />
|
|
|
|
<ambientLight intensity={isDark ? 0.5 : 0.8} />
|
|
<spotLight
|
|
position={[10, 10, 10]}
|
|
angle={0.15}
|
|
penumbra={1}
|
|
intensity={isDark ? 1 : 1.5}
|
|
castShadow
|
|
/>
|
|
<pointLight position={[-10, -10, -10]} intensity={0.5} color="#8b5cf6" />
|
|
|
|
<FloatingShape />
|
|
|
|
<Environment resolution={256}>
|
|
<group rotation={[-Math.PI / 3, 0, 1]}>
|
|
<Lightformer form="circle" intensity={4} rotation-x={Math.PI / 2} position={[0, 5, -9]} scale={2} />
|
|
<Lightformer form="circle" intensity={2} rotation-y={Math.PI / 2} position={[-5, 1, -1]} scale={2} />
|
|
<Lightformer form="circle" intensity={2} rotation-y={Math.PI / 2} position={[5, 1, -1]} scale={2} />
|
|
<Lightformer form="circle" intensity={2} rotation-y={-Math.PI / 2} position={[10, 1, 0]} scale={8} />
|
|
</group>
|
|
</Environment>
|
|
|
|
<ContactShadows
|
|
position={[0, -2, 0]}
|
|
opacity={isDark ? 0.4 : 0.2}
|
|
scale={20}
|
|
blur={2}
|
|
far={4.5}
|
|
/>
|
|
</Canvas>
|
|
</div>
|
|
);
|
|
}
|