import * as THREE from 'three' const scene = new THREE.Scene() scene.background = new THREE.Color(0xf3f5f8) const camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 0.1, 100 ) camera.position.set(0, 2, 7) camera.lookAt(0, 0, 0) const renderer = new THREE.WebGLRenderer({ antialias: true }) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) renderer.setSize(window.innerWidth, window.innerHeight) document.body.appendChild(renderer.domElement) scene.add(new THREE.AmbientLight(0xffffff, 0.9)) const keyLight = new THREE.DirectionalLight(0xffffff, 1) keyLight.position.set(3, 4, 5) scene.add(keyLight) const objects = { center: new THREE.Mesh( new THREE.BoxGeometry(1.2, 1.2, 1.2), new THREE.MeshStandardMaterial({ color: 0x2a9d8f }) ), left: new THREE.Mesh( new THREE.BoxGeometry(0.9, 0.9, 0.9), new THREE.MeshStandardMaterial({ color: 0xe76f51 }) ), right: new THREE.Mesh( new THREE.BoxGeometry(0.9, 0.9, 0.9), new THREE.MeshStandardMaterial({ color: 0x457b9d }) ), } scene.add(objects.center, objects.left, objects.right) const 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 }, }, } const targets = { 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() }, } const buttons = Array.from(document.querySelectorAll('.state-btn')) let activeState = 'state1' function updateButtonState(stateName) { buttons.forEach((button) => { button.classList.toggle('active', button.dataset.state === stateName) }) } function applyState(stateName) { const nextState = states[stateName] if (!nextState) { return } activeState = stateName Object.keys(objects).forEach((name) => { const object = objects[name] const config = nextState[name] targets[name].position.set(...config.position) targets[name].rotation.set(...config.rotation) object.visible = config.visible }) updateButtonState(stateName) } buttons.forEach((button) => { button.addEventListener('click', () => { applyState(button.dataset.state) }) }) window.addEventListener('keydown', (event) => { if (event.key === '1') applyState('state1') if (event.key === '2') applyState('state2') if (event.key === '3') applyState('state3') }) applyState(activeState) function animate() { Object.keys(objects).forEach((name) => { const object = objects[name] 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 }) renderer.render(scene, camera) } renderer.setAnimationLoop(animate) window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight camera.updateProjectionMatrix() renderer.setSize(window.innerWidth, window.innerHeight) })