Download SceneManager.js from richardhcli/simple_neural_network_visualizer: direct link, hf CLI and curl.
- Browser
- Download file 7.26 kB
-
https://huggingface.co/spaces/richardhcli/simple_neural_network_visualizer/resolve/main/SceneManager.js
- Command line
-
hf download hf://spaces/richardhcli/simple_neural_network_visualizer/SceneManager.js
-
curl -L -o SceneManager.js https://huggingface.co/spaces/richardhcli/simple_neural_network_visualizer/resolve/main/SceneManager.js
7.26 kB
| class SceneManager { | |
| constructor(config = {}) { | |
| // Scene setup | |
| this.scene = new THREE.Scene(); | |
| this.scene.background = new THREE.Color(config.backgroundColor || 0x0a0e27); | |
| this.scene.fog = new THREE.Fog(config.backgroundColor || 0x0a0e27, 100, 1000); | |
| // Camera setup | |
| this.camera = new THREE.PerspectiveCamera( | |
| 75, | |
| window.innerWidth / window.innerHeight, | |
| 0.1, | |
| 1000 | |
| ); | |
| this.camera.position.set(0, 0, config.cameraDistance || 15); | |
| // Renderer setup | |
| this.renderer = new THREE.WebGLRenderer({ | |
| canvas: document.getElementById('canvas'), | |
| antialias: true, | |
| alpha: true | |
| }); | |
| this.renderer.setSize(window.innerWidth, window.innerHeight); | |
| this.renderer.setPixelRatio(window.devicePixelRatio); | |
| this.renderer.shadowMap.enabled = true; | |
| // Lighting | |
| this.setupLighting(); | |
| // Managers | |
| this.sphereManager = new SphereManager(this.scene); | |
| this.connectionManager = new ConnectionManager(this.scene); | |
| // Controls | |
| this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement); | |
| this.controls.enableDamping = true; | |
| this.controls.dampingFactor = 0.05; | |
| this.controls.screenSpacePanning = false; | |
| this.controls.minDistance = 5; | |
| this.controls.maxDistance = 500; | |
| this.controls.maxPolarAngle = Math.PI; | |
| // Store initial camera state for reset | |
| this.initialCameraPosition = this.camera.position.clone(); | |
| this.initialControlsTarget = new THREE.Vector3(0, 0, 0); | |
| // Window resize listener | |
| window.addEventListener('resize', () => this.onWindowResize()); | |
| // reset camera view button | |
| const resetCameraButton = document.getElementById('resetCameraButton'); | |
| if (resetCameraButton) { | |
| resetCameraButton.addEventListener('click', () => { | |
| this.resetCameraView(); | |
| }); | |
| } | |
| // Start animation loop | |
| this.animate(); | |
| console.log('✓ Scene3D initialized'); | |
| } | |
| /** | |
| * Setup lighting for the scene | |
| */ | |
| setupLighting() { | |
| const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); | |
| this.scene.add(ambientLight); | |
| // Directional light | |
| const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8); | |
| directionalLight.position.set(10, 10, 10); | |
| directionalLight.castShadow = true; | |
| directionalLight.shadow.mapSize.width = 2048; | |
| directionalLight.shadow.mapSize.height = 2048; | |
| this.scene.add(directionalLight); | |
| // Point lights for atmosphere | |
| const pointLight1 = new THREE.PointLight(0xff0080, 0.3, 100); | |
| pointLight1.position.set(-10, 10, 10); | |
| this.scene.add(pointLight1); | |
| const pointLight2 = new THREE.PointLight(0x0080ff, 0.3, 100); | |
| pointLight2.position.set(10, -10, 10); | |
| this.scene.add(pointLight2); | |
| } | |
| /** | |
| * Initialize scene from JSON configuration | |
| * @param {Object} jsonConfig - Configuration with spheres and connections arrays | |
| * | |
| * Example: | |
| * { | |
| * spheres: [ | |
| * { name: 'A', radius: 1, color: '#ff0000', position: { x: 0, y: 0, z: 0 } }, | |
| * { name: 'B', radius: 1, color: '#00ff00', position: { x: 5, y: 0, z: 0 } } | |
| * ], | |
| * connections: [ | |
| * { id: 'AB', from: 'A', to: 'B', color: '#ffff00', lineWidth: 2 } | |
| * ] | |
| * } | |
| */ | |
| loadFromJSON(jsonConfig) { | |
| // Clear existing scene | |
| this.sphereManager.clearAll(); | |
| this.connectionManager.clearAll(); | |
| // Add spheres | |
| if (jsonConfig.spheres && Array.isArray(jsonConfig.spheres)) { | |
| jsonConfig.spheres.forEach(sphereConfig => { | |
| const position = new THREE.Vector3( | |
| sphereConfig.position?.x || 0, | |
| sphereConfig.position?.y || 0, | |
| sphereConfig.position?.z || 0 | |
| ); | |
| this.sphereManager.addSphere(sphereConfig.name, { | |
| radius: sphereConfig.radius || 1, | |
| color: sphereConfig.color || '#ff0000', | |
| position: position, | |
| opacity: sphereConfig.opacity || 1 | |
| }); | |
| }); | |
| } | |
| // Add connections | |
| if (jsonConfig.connections && Array.isArray(jsonConfig.connections)) { | |
| jsonConfig.connections.forEach(connConfig => { | |
| const fromSphere = this.sphereManager.getSphere(connConfig.from); | |
| const toSphere = this.sphereManager.getSphere(connConfig.to); | |
| if (fromSphere && toSphere) { | |
| this.connectionManager.addConnection( | |
| connConfig.id || `conn_${connConfig.from}_${connConfig.to}`, | |
| fromSphere.position, | |
| toSphere.position, | |
| { | |
| color: connConfig.color || '#00ff00', | |
| lineWidth: connConfig.lineWidth || 2, | |
| fromSphere: connConfig.from, | |
| toSphere: connConfig.to | |
| } | |
| ); | |
| } else { | |
| console.warn(`Connection ${connConfig.id}: sphere(s) not found`); | |
| } | |
| }); | |
| } | |
| console.log('✓ Scene loaded from JSON'); | |
| } | |
| /** | |
| * Handle window resize | |
| */ | |
| onWindowResize() { | |
| this.camera.aspect = window.innerWidth / window.innerHeight; | |
| this.camera.updateProjectionMatrix(); | |
| this.renderer.setSize(window.innerWidth, window.innerHeight); | |
| } | |
| resetCameraView() { | |
| // Disable damping temporarily to stop momentum | |
| const wasDamping = this.controls.enableDamping; | |
| this.controls.enableDamping = false; | |
| // Reset to initial positions | |
| this.camera.position.copy(this.initialCameraPosition); | |
| this.controls.target.copy(this.initialControlsTarget); | |
| // Reset OrbitControls internal state (removes any stored rotations/pans) | |
| this.controls.reset(); | |
| // Force immediate update without damping | |
| this.controls.update(); | |
| // Re-enable damping | |
| this.controls.enableDamping = wasDamping; | |
| console.log('✓ Camera view reset'); | |
| } | |
| /** | |
| * Main animation loop | |
| */ | |
| animate() { | |
| requestAnimationFrame(() => this.animate()); | |
| // Update controls | |
| this.controls.update(); | |
| // Update connection positions dynamically | |
| this.connectionManager.getAllConnections().forEach(conn => { | |
| const fromSphere = this.sphereManager.getSphere(conn.fromSphere); | |
| const toSphere = this.sphereManager.getSphere(conn.toSphere); | |
| if (fromSphere && toSphere) { | |
| this.connectionManager.updateConnectionPositions( | |
| conn.id, | |
| fromSphere.position, | |
| toSphere.position | |
| ); | |
| } | |
| }); | |
| this.renderer.render(this.scene, this.camera); | |
| } | |
| } |