96 lines
2.4 KiB
JavaScript

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 (
<>
<ambientLight intensity={0.85} />
<directionalLight intensity={1} position={[3, 4, 5]} />
<mesh>
<boxGeometry args={[1.6, 1.6, 1.6]} />
<meshStandardMaterial color="#2a9d8f" roughness={0.45} metalness={0.1} />
</mesh>
<CameraController preset={preset} />
</>
)
}
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 (
<div className="app-shell">
<div id="preset-panel">
<h2>Camera Presets</h2>
<div className="preset-buttons">
<button
className={`preset-btn ${preset === 'front' ? 'active' : ''}`}
onClick={() => setPreset('front')}
>
Front (1)
</button>
<button
className={`preset-btn ${preset === 'side' ? 'active' : ''}`}
onClick={() => setPreset('side')}
>
Side (2)
</button>
<button
className={`preset-btn ${preset === 'topAngled' ? 'active' : ''}`}
onClick={() => setPreset('topAngled')}
>
Top Angled (3)
</button>
</div>
<p id="hint">Press 1, 2, or 3 to switch view.</p>
</div>
<Canvas camera={{ fov: 55, near: 0.1, far: 100, position: PRESETS.front }}>
<color attach="background" args={["#f3f5f8"]} />
<Scene preset={preset} />
</Canvas>
</div>
)
}
export default App