import { useRef, useState, Suspense, useEffect } from 'react'; import { Canvas, useFrame } from '@react-three/fiber'; import { OrbitControls, Environment, Stars, Effects } from '@react-three/drei'; import { Box, Disc, Hexagon, Octagon, Pentagon, Star, Palette, Zap, Maximize } from 'lucide-react'; import * as THREE from 'three'; import { EffectComposer, Bloom, ChromaticAberration } from '@react-three/postprocessing'; interface ShapeProps { geometry: 'box' | 'sphere' | 'torus' | 'icosahedron' | 'octahedron' | 'dodecahedron'; color: string; textured: boolean; speed: number; scale: number; effects: boolean; } function createVoronoiTexture() { const size = 512; const data = new Uint8Array(size * size * 4); const points = Array(16).fill(0).map(() => ({ x: Math.random() * size, y: Math.random() * size, color: Math.random() * 255 })); for (let y = 0; y < size; y++) { for (let x = 0; x < size; x++) { let minDist = Infinity; let cellColor = 0; // Find nearest point for voronoi cell points.forEach(point => { const dx = x - point.x; const dy = y - point.y; const dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; cellColor = point.color; } }); // Add some noise to break up the pattern const noise = Math.random() * 30 - 15; const finalColor = Math.max(0, Math.min(255, cellColor + noise)); const i = (y * size + x) * 4; data[i] = finalColor; // r data[i + 1] = finalColor; // g data[i + 2] = finalColor; // b data[i + 3] = 255; // a } } const texture = new THREE.DataTexture(data, size, size, THREE.RGBAFormat); texture.wrapS = THREE.RepeatWrapping; texture.wrapT = THREE.RepeatWrapping; texture.needsUpdate = true; return texture; } function Shape({ geometry, color, textured, speed, scale, effects }: ShapeProps) { const meshRef = useRef(null); const matRef = useRef(null); const [normalMap] = useState(() => createVoronoiTexture()); useFrame((state, delta) => { if (meshRef.current) { meshRef.current.rotation.x += delta * speed; meshRef.current.rotation.y += delta * speed * 0.5; } if (matRef.current && effects) { matRef.current.roughness = Math.sin(state.clock.elapsedTime) * 0.3 + 0.5; } }); const getGeometry = () => { switch (geometry) { case 'box': return ; case 'sphere': return ; case 'torus': return ; case 'icosahedron': return ; case 'octahedron': return ; case 'dodecahedron': return ; default: return ; } }; return ( {getGeometry()} ); } function SceneContent(props: ShapeProps) { return ( <> {props.effects && ( )} ); } export function Scene() { const [settings, setSettings] = useState({ geometry: 'box' as const, color: '#ff6b6b', textured: false, speed: 1, scale: 1, effects: true, }); const geometryOptions = [ { value: 'box', label: 'Cube', icon: Box }, { value: 'sphere', label: 'Sphere', icon: Disc }, { value: 'torus', label: 'Torus', icon: Hexagon }, { value: 'icosahedron', label: 'Icosahedron', icon: Pentagon }, { value: 'octahedron', label: 'Octahedron', icon: Octagon }, { value: 'dodecahedron', label: 'Dodecahedron', icon: Star }, ]; return (

Scene Settings

{geometryOptions.map((option) => { const Icon = option.icon; return ( ); })}
setSettings({ ...settings, color: e.target.value })} className="w-full h-12 rounded-lg cursor-pointer bg-gray-800 border-2 border-gray-700" />
setSettings({ ...settings, speed: parseFloat(e.target.value) })} className="w-full accent-blue-600 bg-gray-700 h-2 rounded-lg appearance-none cursor-pointer" />
setSettings({ ...settings, scale: parseFloat(e.target.value) })} className="w-full accent-blue-600 bg-gray-700 h-2 rounded-lg appearance-none cursor-pointer" />
); }