periodic_table / SceneManager.js
AK51's picture
Upload 18 files
ab59545 verified
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;
}
}