Spaces:
Sleeping
Sleeping
File size: 2,715 Bytes
5008b66 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
import { useRef, useState } from 'react';
import { Canvas, useFrame, ThreeEvent } from '@react-three/fiber';
import { Sphere, MeshDistortMaterial, Float } from '@react-three/drei';
import * as THREE from 'three';
interface OrbProps {
position?: [number, number, number];
onInteraction?: (type: 'hover' | 'click') => void;
}
function Orb({ position = [0, 0, 0], onInteraction }: OrbProps) {
const meshRef = useRef<THREE.Mesh>(null);
const [hovered, setHovered] = useState(false);
const [clicked, setClicked] = useState(false);
useFrame((state) => {
if (meshRef.current) {
// Continuous rotation
meshRef.current.rotation.x = Math.sin(state.clock.elapsedTime * 0.5) * 0.3;
meshRef.current.rotation.y = state.clock.elapsedTime * 0.3;
// Scale based on interaction
const targetScale = clicked ? 1.3 : hovered ? 1.1 : 1;
meshRef.current.scale.lerp(new THREE.Vector3(targetScale, targetScale, targetScale), 0.1);
}
});
const handlePointerOver = (event: ThreeEvent<PointerEvent>) => {
event.stopPropagation();
setHovered(true);
onInteraction?.('hover');
};
const handlePointerOut = () => {
setHovered(false);
};
const handleClick = (event: ThreeEvent<MouseEvent>) => {
event.stopPropagation();
setClicked(true);
setTimeout(() => setClicked(false), 200);
onInteraction?.('click');
};
return (
<Float speed={1.5} rotationIntensity={0.3} floatIntensity={0.5}>
<Sphere
ref={meshRef}
args={[1]}
position={position}
onPointerOver={handlePointerOver}
onPointerOut={handlePointerOut}
onClick={handleClick}
>
<MeshDistortMaterial
color={clicked ? "#ec4899" : hovered ? "#06b6d4" : "#a855f7"}
transparent
opacity={0.8}
distort={hovered ? 0.6 : 0.3}
speed={clicked ? 5 : hovered ? 3 : 1}
emissive={clicked ? "#db2777" : hovered ? "#0891b2" : "#8b5cf6"}
emissiveIntensity={clicked ? 0.8 : hovered ? 0.5 : 0.2}
/>
</Sphere>
</Float>
);
}
interface InteractiveOrbProps {
onInteraction?: (type: 'hover' | 'click') => void;
className?: string;
}
export default function InteractiveOrb({ onInteraction, className = "" }: InteractiveOrbProps) {
return (
<div className={`w-full h-full cursor-pointer ${className}`}>
<Canvas camera={{ position: [0, 0, 5], fov: 45 }}>
<ambientLight intensity={0.4} />
<directionalLight position={[10, 10, 5]} intensity={1} />
<pointLight position={[-10, -10, -5]} intensity={0.5} color="#a855f7" />
<Orb onInteraction={onInteraction} />
</Canvas>
</div>
);
} |