diff --git a/Week-2/Task-1/r3f/Cammera/src/App.jsx b/Week-2/Task-1/r3f/Cammera/src/App.jsx index 7ed0c18..1a51815 100644 --- a/Week-2/Task-1/r3f/Cammera/src/App.jsx +++ b/Week-2/Task-1/r3f/Cammera/src/App.jsx @@ -1,9 +1,95 @@ -function App() { +import { useEffect, useMemo, useState } from 'react' +import { Canvas, useFrame, useThree } from '@react-three/fiber' +import * as THREE from 'three' + +const PRESETS = { + front: [0, 1.2, 6.5], + side: [6.5, 1.4, 0], + topAngled: [3.8, 5.4, 4.2], +} + +function CameraController({ preset }) { + const { camera } = useThree() + const target = useMemo(() => new THREE.Vector3(0, 0, 0), []) + const targetPosition = useMemo(() => new THREE.Vector3(), []) + + useEffect(() => { + const [x, y, z] = PRESETS[preset] + targetPosition.set(x, y, z) + }, [preset, targetPosition]) + + useFrame(() => { + camera.position.lerp(targetPosition, 0.08) + camera.lookAt(target) + }) + + return null +} + +function Scene({ preset }) { return ( <> + + + + + + + + + ) } +function App() { + const [preset, setPreset] = useState('front') + + useEffect(() => { + function onKeyDown(event) { + if (event.key === '1') setPreset('front') + if (event.key === '2') setPreset('side') + if (event.key === '3') setPreset('topAngled') + } + + window.addEventListener('keydown', onKeyDown) + return () => window.removeEventListener('keydown', onKeyDown) + }, []) + + return ( +
+
+

Camera Presets

+
+ + + +
+

Press 1, 2, or 3 to switch view.

+
+ + + + + +
+ ) +} + export default App diff --git a/Week-2/Task-1/r3f/Cammera/src/index.css b/Week-2/Task-1/r3f/Cammera/src/index.css index 220d0b3..8eb2c4c 100644 --- a/Week-2/Task-1/r3f/Cammera/src/index.css +++ b/Week-2/Task-1/r3f/Cammera/src/index.css @@ -12,4 +12,70 @@ body, body { overflow: hidden; + font-family: "Avenir Next", "Segoe UI", sans-serif; + background: #f3f5f8; +} + +.app-shell { + position: relative; + width: 100%; + height: 100%; +} + +#preset-panel { + position: fixed; + top: 16px; + left: 16px; + z-index: 10; + background: rgba(255, 255, 255, 0.82); + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 12px; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); + padding: 12px; + display: flex; + flex-direction: column; + gap: 8px; + backdrop-filter: blur(6px); +} + +#preset-panel h2 { + margin: 0; + font-size: 14px; + letter-spacing: 0.03em; + color: #1b2530; + font-weight: 700; +} + +.preset-buttons { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + +.preset-btn { + border: 1px solid #cfd8e3; + background: #ffffff; + color: #203448; + border-radius: 8px; + padding: 8px 10px; + font-size: 13px; + cursor: pointer; + transition: all 0.2s ease; +} + +.preset-btn:hover { + border-color: #8ea2b8; + transform: translateY(-1px); +} + +.preset-btn.active { + background: #203448; + border-color: #203448; + color: #f4f8fb; +} + +#hint { + margin: 0; + font-size: 12px; + color: #4f647a; }