freshyo/apps/fallback-ui/src/components/3d/Scene.tsx
2026-02-01 13:56:03 +05:30

183 lines
5.1 KiB
TypeScript

import { useRef, useEffect } from 'react';
import { Canvas, useFrame, useThree } from '@react-three/fiber';
import { OrbitControls, Stars, Float } from '@react-three/drei';
import * as THREE from 'three';
import Characters from './Characters';
// Warm gradient background
function WarmBackground() {
const { scene } = useThree();
useEffect(() => {
// Create gradient texture
const canvas = document.createElement('canvas');
canvas.width = 512;
canvas.height = 512;
const ctx = canvas.getContext('2d')!;
const gradient = ctx.createLinearGradient(0, 0, 0, 512);
gradient.addColorStop(0, '#FFE5D4');
gradient.addColorStop(0.5, '#FFB4A2');
gradient.addColorStop(1, '#FF8E72');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 512, 512);
const texture = new THREE.TextureLoader().load(canvas.toDataURL());
scene.background = texture;
}, [scene]);
return null;
}
// Ground plane with warm color
function Ground() {
const meshRef = useRef<THREE.Mesh>(null);
useFrame((state) => {
if (meshRef.current) {
// Subtle ground animation
meshRef.current.rotation.x = -Math.PI / 2;
}
});
return (
<mesh ref={meshRef} position={[0, -0.1, 0]} receiveShadow>
<planeGeometry args={[20, 20, 32, 32]} />
<meshStandardMaterial
color="#F5FAFF"
roughness={0.8}
metalness={0.1}
/>
</mesh>
);
}
// Floating particles for atmosphere
function FloatingParticles({ isCelebrating }: { isCelebrating: boolean }) {
const points = useRef<THREE.Points>(null);
const particleCount = isCelebrating ? 200 : 50;
const positions = new Float32Array(particleCount * 3);
for (let i = 0; i < particleCount; i++) {
positions[i * 3] = (Math.random() - 0.5) * 15;
positions[i * 3 + 1] = Math.random() * 8;
positions[i * 3 + 2] = (Math.random() - 0.5) * 15;
}
useFrame((state) => {
if (points.current) {
points.current.rotation.y = state.clock.getElapsedTime() * 0.05;
if (isCelebrating) {
points.current.rotation.y = state.clock.getElapsedTime() * 0.2;
}
}
});
return (
<points ref={points}>
<bufferGeometry>
<bufferAttribute
attach="attributes-position"
args={[positions, 3]}
/>
</bufferGeometry>
<pointsMaterial
size={0.1}
color={isCelebrating ? "#53B1FD" : "#84CAFF"}
transparent
opacity={0.8}
sizeAttenuation
/>
</points>
);
}
// Blue lighting setup
function Lighting() {
return (
<>
<ambientLight intensity={0.6} color="#D1E9FF" />
<directionalLight
position={[5, 10, 5]}
intensity={1.2}
color="#53B1FD"
castShadow
shadow-mapSize={[2048, 2048]}
/>
<pointLight position={[-5, 5, -5]} intensity={0.8} color="#84CAFF" />
<pointLight position={[5, 3, 5]} intensity={0.6} color="#2E90FA" />
</>
);
}
// Camera animation
function CameraController({ isCelebrating }: { isCelebrating: boolean }) {
const { camera } = useThree();
useFrame((state) => {
const time = state.clock.getElapsedTime();
if (isCelebrating) {
// Dramatic camera movement during celebration
camera.position.x = Math.sin(time * 0.5) * 2;
camera.position.y = 3 + Math.sin(time * 0.3) * 0.5;
camera.position.z = 8 + Math.cos(time * 0.5) * 1;
} else {
// Gentle orbiting before celebration
camera.position.x = Math.sin(time * 0.2) * 4;
camera.position.z = 8 + Math.cos(time * 0.2) * 2;
camera.position.y = 3;
}
camera.lookAt(0, 1, 0);
});
return null;
}
interface SceneProps {
isCelebrating: boolean;
}
export default function Scene({ isCelebrating }: SceneProps) {
return (
<div className="w-full h-screen">
<Canvas
shadows
camera={{ position: [0, 3, 8], fov: 60 }}
gl={{ antialias: true, alpha: true }}
>
<WarmBackground />
<Lighting />
<CameraController isCelebrating={isCelebrating} />
<Ground />
<Characters isCelebrating={isCelebrating} />
<FloatingParticles isCelebrating={isCelebrating} />
{/* Floating decorative elements */}
<Float speed={2} rotationIntensity={0.5} floatIntensity={0.5}>
<mesh position={[-3, 4, -2]}>
<sphereGeometry args={[0.3, 16, 16]} />
<meshStandardMaterial color="#84CAFF" emissive="#53B1FD" emissiveIntensity={0.3} />
</mesh>
</Float>
<Float speed={1.5} rotationIntensity={0.3} floatIntensity={0.3}>
<mesh position={[3, 5, -3]}>
<sphereGeometry args={[0.2, 16, 16]} />
<meshStandardMaterial color="#53B1FD" emissive="#2E90FA" emissiveIntensity={0.3} />
</mesh>
</Float>
<Float speed={2.5} rotationIntensity={0.4} floatIntensity={0.4}>
<mesh position={[2, 3, 2]}>
<sphereGeometry args={[0.25, 16, 16]} />
<meshStandardMaterial color="#2E90FA" emissive="#1570EF" emissiveIntensity={0.2} />
</mesh>
</Float>
</Canvas>
</div>
);
}