// Shared JavaScript across all pages document.addEventListener('DOMContentLoaded', function() { // Initialize Three.js scene for the hero background initNetworkBackground(); // Smooth scrolling for anchor links document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function(e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { window.scrollTo({ top: target.offsetTop, behavior: 'smooth' }); } }); }); }); function initNetworkBackground() { // Get the container element const container = document.getElementById('network-background'); // Set up Three.js scene const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setPixelRatio(window.devicePixelRatio); container.appendChild(renderer.domElement); // Create particle system for the network const particles = 2000; const geometry = new THREE.BufferGeometry(); const positions = new Float32Array(particles * 3); const colors = new Float32Array(particles * 3); // Create node positions for (let i = 0; i < particles * 3; i += 3) { positions[i] = (Math.random() - 0.5) * 200; positions[i + 1] = (Math.random() - 0.5) * 200; positions[i + 2] = (Math.random() - 0.5) * 200; } // Create node colors (purple spectrum) for (let i = 0; i < particles * 3; i += 3) { colors[i] = Math.random() * 0.5 + 0.5; // R colors[i + 1] = Math.random() * 0.3; // G colors[i + 2] = Math.random() * 0.8 + 0.2; // B } geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3)); geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3)); // Create material with custom shader for glow effect const material = new THREE.PointsMaterial({ size: 2, vertexColors: true, transparent: true, opacity: 0.8, blending: THREE.AdditiveBlending }); const points = new THREE.Points(geometry, material); scene.add(points); // Create connecting lines const lineGeometry = new THREE.BufferGeometry(); const linePositions = []; const lineColors = []; // Connect nearby nodes for (let i = 0; i < particles; i++) { for (let j = i + 1; j < particles; j++) { const dx = positions[i * 3] - positions[j * 3]; const dy = positions[i * 3 + 1] - positions[j * 3 + 1]; const dz = positions[i * 3 + 2] - positions[j * 3 + 2]; const distance = Math.sqrt(dx * dx + dy * dy + dz * dz); // Only connect relatively close nodes if (distance < 20) { linePositions.push( positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2], positions[j * 3], positions[j * 3 + 1], positions[j * 3 + 2] ); // Line color based on node colors lineColors.push( colors[i * 3], colors[i * 3 + 1], colors[i * 3 + 2], colors[j * 3], colors[j * 3 + 1], colors[j * 3 + 2] ); } } } lineGeometry.setAttribute('position', new THREE.Float32BufferAttribute(linePositions, 3)); lineGeometry.setAttribute('color', new THREE.Float32BufferAttribute(lineColors, 3)); const lineMaterial = new THREE.LineBasicMaterial({ vertexColors: true, transparent: true, opacity: 0.3, blending: THREE.AdditiveBlending }); const lines = new THREE.LineSegments(lineGeometry, lineMaterial); scene.add(lines); // Position camera camera.position.z = 50; // Add subtle ambient light const ambientLight = new THREE.AmbientLight(0x6a00b8, 0.2); scene.add(ambientLight); // Add directional light for highlights const directionalLight = new THREE.DirectionalLight(0xb366ff, 0.5); directionalLight.position.set(1, 1, 1); scene.add(directionalLight); // Handle window resize window.addEventListener('resize', () => { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); // Mouse movement effect let mouseX = 0; let mouseY = 0; document.addEventListener('mousemove', (event) => { mouseX = (event.clientX / window.innerWidth) * 2 - 1; mouseY = -(event.clientY / window.innerHeight) * 2 + 1; }); // Animation variables let time = 0; // Animation loop function animate() { requestAnimationFrame(animate); time += 0.01; // Rotate the entire scene slowly points.rotation.x = time * 0.05; points.rotation.y = time * 0.03; lines.rotation.x = time * 0.05; lines.rotation.y = time * 0.03; // Apply mouse parallax effect camera.position.x += (mouseX * 5 - camera.position.x) * 0.05; camera.position.y += (mouseY * 5 - camera.position.y) * 0.05; camera.lookAt(scene.position); // Pulsing effect for nodes const positions = points.geometry.attributes.position.array; for (let i = 0; i < positions.length; i += 3) { positions[i + 1] += Math.sin(time + i * 0.01) * 0.02; } points.geometry.attributes.position.needsUpdate = true; renderer.render(scene, camera); } animate(); }