neural-glow / script.js
dodey917's picture
Imagine the network not as a flat animation, but as a floating 3D digital environment — a luminous purple nebula where energy threads weave through a living data cloud.
2541ddd verified
// 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();
}