From a4070e864465d64c1ad78dc686d37c9abd6af877 Mon Sep 17 00:00:00 2001 From: anshk Date: Wed, 1 Apr 2026 20:13:40 +0530 Subject: [PATCH] feat: add scene for task2 in r3f --- Week-2/Task-2/r3f/sceene/src/App.jsx | 142 ++++++++++++++++++++++++- Week-2/Task-2/r3f/sceene/src/index.css | 66 ++++++++++++ 2 files changed, 207 insertions(+), 1 deletion(-) diff --git a/Week-2/Task-2/r3f/sceene/src/App.jsx b/Week-2/Task-2/r3f/sceene/src/App.jsx index 194eb0b..717f1ba 100644 --- a/Week-2/Task-2/r3f/sceene/src/App.jsx +++ b/Week-2/Task-2/r3f/sceene/src/App.jsx @@ -1,7 +1,147 @@ +import { useEffect, useMemo, useRef, useState } from 'react' +import { Canvas, useFrame } from '@react-three/fiber' +import * as THREE from 'three' + +const SCENE_STATES = { + state1: { + center: { position: [0, 0, 0], rotation: [0, 0, 0], visible: true }, + left: { position: [0, 0, 0], rotation: [0, 0, 0], visible: false }, + right: { position: [0, 0, 0], rotation: [0, 0, 0], visible: false }, + }, + state2: { + center: { position: [0, 0, 0], rotation: [0.25, 0.4, 0], visible: true }, + left: { position: [-2.1, 0, 0.2], rotation: [0, 0.2, 0], visible: true }, + right: { position: [2.1, 0, -0.2], rotation: [0, -0.2, 0], visible: true }, + }, + state3: { + center: { position: [0, 1.3, 0], rotation: [0.6, 0.9, 0], visible: true }, + left: { position: [-1.2, -1, 1.2], rotation: [0.3, 0.3, 0.1], visible: true }, + right: { position: [0, 0, 0], rotation: [0, 0, 0], visible: false }, + }, +} + +function SceneObjects({ stateKey }) { + const centerRef = useRef() + const leftRef = useRef() + const rightRef = useRef() + + const targets = useMemo( + () => ({ + center: { position: new THREE.Vector3(), rotation: new THREE.Euler() }, + left: { position: new THREE.Vector3(), rotation: new THREE.Euler() }, + right: { position: new THREE.Vector3(), rotation: new THREE.Euler() }, + }), + [] + ) + + useEffect(() => { + const state = SCENE_STATES[stateKey] + const refs = { + center: centerRef.current, + left: leftRef.current, + right: rightRef.current, + } + + Object.keys(refs).forEach((name) => { + const object = refs[name] + if (!object) return + + const config = state[name] + targets[name].position.set(...config.position) + targets[name].rotation.set(...config.rotation) + object.visible = config.visible + }) + }, [stateKey, targets]) + + useFrame(() => { + const refs = { + center: centerRef.current, + left: leftRef.current, + right: rightRef.current, + } + + Object.keys(refs).forEach((name) => { + const object = refs[name] + if (!object) return + + const target = targets[name] + object.position.lerp(target.position, 0.1) + object.rotation.x += (target.rotation.x - object.rotation.x) * 0.1 + object.rotation.y += (target.rotation.y - object.rotation.y) * 0.1 + object.rotation.z += (target.rotation.z - object.rotation.z) * 0.1 + }) + }) + + return ( + <> + + + + + + + + + + + + + + + + + + + ) +} + function App() { + const [stateKey, setStateKey] = useState('state1') + + useEffect(() => { + function onKeyDown(event) { + if (event.key === '1') setStateKey('state1') + if (event.key === '2') setStateKey('state2') + if (event.key === '3') setStateKey('state3') + } + + window.addEventListener('keydown', onKeyDown) + return () => window.removeEventListener('keydown', onKeyDown) + }, []) + return ( - <> +
+
+

Scene States

+
+ + + +
+

Press 1, 2, or 3 to switch state.

+
+ + + + + +
) } diff --git a/Week-2/Task-2/r3f/sceene/src/index.css b/Week-2/Task-2/r3f/sceene/src/index.css index 57aaa4b..e820423 100644 --- a/Week-2/Task-2/r3f/sceene/src/index.css +++ b/Week-2/Task-2/r3f/sceene/src/index.css @@ -8,8 +8,74 @@ body, body { overflow: hidden; + font-family: "Avenir Next", "Segoe UI", sans-serif; + background: #f3f5f8; } canvas { display: block; } + +.app-shell { + position: relative; + width: 100%; + height: 100%; +} + +#state-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); +} + +#state-panel h2 { + margin: 0; + font-size: 14px; + letter-spacing: 0.03em; + color: #1b2530; + font-weight: 700; +} + +.state-buttons { + display: flex; + gap: 8px; + flex-wrap: wrap; +} + +.state-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; +} + +.state-btn:hover { + border-color: #8ea2b8; + transform: translateY(-1px); +} + +.state-btn.active { + background: #203448; + border-color: #203448; + color: #f4f8fb; +} + +#hint { + margin: 0; + font-size: 12px; + color: #4f647a; +}