Spaces:
Running
Running
| import * as THREE from 'three'; | |
| export class SceneManager { | |
| constructor(container) { | |
| this.container = container; | |
| this.scene = null; | |
| this.camera = null; | |
| this.renderer = null; | |
| this.animationId = null; | |
| } | |
| initialize() { | |
| // Check WebGL support | |
| if (!this.checkWebGLSupport()) { | |
| this.showWebGLError(); | |
| return false; | |
| } | |
| // Create scene | |
| this.scene = new THREE.Scene(); | |
| this.scene.background = new THREE.Color(0x1a1a2e); | |
| // Create camera | |
| const aspect = this.container.clientWidth / this.container.clientHeight; | |
| this.camera = new THREE.PerspectiveCamera(75, aspect, 0.1, 1000); | |
| this.camera.position.set(0, 0, 30); | |
| // Create renderer | |
| this.renderer = new THREE.WebGLRenderer({ antialias: true }); | |
| this.renderer.setSize(this.container.clientWidth, this.container.clientHeight); | |
| this.renderer.setPixelRatio(window.devicePixelRatio); | |
| this.container.appendChild(this.renderer.domElement); | |
| // Add lights | |
| const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); | |
| this.scene.add(ambientLight); | |
| const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); | |
| directionalLight.position.set(10, 10, 10); | |
| this.scene.add(directionalLight); | |
| // Handle window resize | |
| window.addEventListener('resize', () => this.onWindowResize()); | |
| return true; | |
| } | |
| checkWebGLSupport() { | |
| try { | |
| const canvas = document.createElement('canvas'); | |
| return !!(window.WebGLRenderingContext && | |
| (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'))); | |
| } catch (e) { | |
| return false; | |
| } | |
| } | |
| showWebGLError() { | |
| const errorDiv = document.createElement('div'); | |
| errorDiv.style.cssText = ` | |
| position: fixed; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background: rgba(0, 0, 0, 0.9); | |
| color: white; | |
| padding: 30px; | |
| border-radius: 10px; | |
| text-align: center; | |
| z-index: 10000; | |
| `; | |
| errorDiv.innerHTML = ` | |
| <h2>WebGL Not Available</h2> | |
| <p>WebGL is required but not available. Please use a modern browser with WebGL support.</p> | |
| <p><a href="https://get.webgl.org/" target="_blank" style="color: #4fc3f7;">Learn more</a></p> | |
| `; | |
| document.body.appendChild(errorDiv); | |
| } | |
| start() { | |
| if (!this.renderer) return; | |
| const animate = () => { | |
| this.animationId = requestAnimationFrame(animate); | |
| this.renderer.render(this.scene, this.camera); | |
| }; | |
| animate(); | |
| } | |
| stop() { | |
| if (this.animationId) { | |
| cancelAnimationFrame(this.animationId); | |
| this.animationId = null; | |
| } | |
| } | |
| onWindowResize() { | |
| if (!this.camera || !this.renderer) return; | |
| this.camera.aspect = this.container.clientWidth / this.container.clientHeight; | |
| this.camera.updateProjectionMatrix(); | |
| this.renderer.setSize(this.container.clientWidth, this.container.clientHeight); | |
| } | |
| getScene() { | |
| return this.scene; | |
| } | |
| getCamera() { | |
| return this.camera; | |
| } | |
| getRenderer() { | |
| return this.renderer; | |
| } | |
| } | |