import React, { useRef, useMemo, Suspense } from 'react'; import { Canvas, useFrame } from '@react-three/fiber'; import { createNoise3D } from 'simplex-noise'; import * as THREE from 'three'; const Terrain = () => { const mesh = useRef(); const materialRef = useRef(); const noise3D = useMemo(() => createNoise3D(), []); // Detect mobile device and reduce polygon count accordingly const isMobile = useMemo(() => { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || (window.innerWidth <= 768); }, []); // Create geometry with reduced segment count for mobile devices const segments = isMobile ? 28 : 100; // Reduce from 100x100 to 28x28 on mobile (50% polygon reduction) const geometry = useMemo(() => new THREE.PlaneGeometry(20, 20, segments, segments), [segments]); useFrame((state) => { if (mesh.current) { const time = state.clock.getElapsedTime(); const positions = mesh.current.geometry.attributes.position; for (let i = 0; i < positions.count; i++) { const x = positions.getX(i); const y = positions.getY(i); // Smoother noise settings const z = noise3D(x * 0.15, y * 0.15, time * 0.15) * 2; positions.setZ(i, z); } positions.needsUpdate = true; // Slight rotation mesh.current.rotation.x = -Math.PI / 2.5; mesh.current.rotation.z += 0.0005; // Entrance animation logic (simple lerp for opacity) // We start opacity at 0 in the material and lerp to 0.15 // Ideally use a spring or GSAP, but lerp is cheap and easy here if (materialRef.current) { materialRef.current.opacity = THREE.MathUtils.lerp(materialRef.current.opacity, 0.15, 0.02); } } }); return ( ); }; const HeroModel = () => { // Detect dark mode for fog color const fogColor = useMemo(() => { const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; return prefersDark ? '#0a0a0a' : '#e4e4e4'; }, []); return (
{/* Fog to fade edges into background color */}
); }; export default HeroModel;