// static/script.js let scene, camera, renderer, controls; let spheres = []; let fluidParticles = []; let simulationRunning = false; const PARTICLE_COUNT = 5000; const SPACE_SIZE = 40; // Increased space size for solar system scale const FLUID_SPEED = 0.1; let FLUID_FRICTION = 0.9; // Adjustable friction let FLUID_DEFLECTION = 0.1; // Adjustable deflection const GRAVITY_CONSTANT = 0.1; // Scaled gravitational constant init(); animate(); function init() { // Scene setup scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); camera.position.set(0, 20, 40); renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth - 300, window.innerHeight); document.getElementById('scene-container').appendChild(renderer.domElement); controls = new THREE.OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.dampingFactor = 0.05; // Add Sun const sunGeometry = new THREE.SphereGeometry(1, 32, 32); const sunMaterial = new THREE.MeshBasicMaterial({ color: 0xFFFF00 }); const sun = new THREE.Mesh(sunGeometry, sunMaterial); sun.position.set(0, 0, 0); sun.userData = { mass: 1.989e4, velocity: new THREE.Vector3(0, 0, 0) }; scene.add(sun); spheres.push(sun); // Add Earth const earthGeometry = new THREE.SphereGeometry(0.3, 32, 32); const earthMaterial = new THREE.MeshBasicMaterial({ color: 0x0000FF }); const earth = new THREE.Mesh(earthGeometry, earthMaterial); earth.position.set(10, 0, 0); earth.userData = { mass: 5.972e-2, velocity: new THREE.Vector3(0, 0, 0.0298), // Initial orbital velocity in Z direction centripetalScale: 1 }; scene.add(earth); spheres.push(earth); // Add Mars const marsGeometry = new THREE.SphereGeometry(0.25, 32, 32); const marsMaterial = new THREE.MeshBasicMaterial({ color: 0xFF4500 }); const mars = new THREE.Mesh(marsGeometry, marsMaterial); mars.position.set(15, 0, 0); mars.userData = { mass: 6.417e-3, velocity: new THREE.Vector3(0, 0, 0.0241), // Initial orbital velocity in Z direction centripetalScale: 1 }; scene.add(mars); spheres.push(mars); // Add fluid particles const particleGeometry = new THREE.SphereGeometry(0.05, 8, 8); const particleMaterial = new THREE.MeshBasicMaterial({ color: 0x00BFFF, transparent: true, opacity: 0.5 }); for (let i = 0; i < PARTICLE_COUNT; i++) { const particle = new THREE.Mesh(particleGeometry, particleMaterial); particle.position.set( (Math.random() - 0.5) * SPACE_SIZE, (Math.random() - 0.5) * SPACE_SIZE, (Math.random() - 0.5) * SPACE_SIZE ); particle.userData = { velocity: new THREE.Vector3( (Math.random() - 0.5) * FLUID_SPEED, (Math.random() - 0.5) * FLUID_SPEED, (Math.random() - 0.5) * FLUID_SPEED ) }; scene.add(particle); fluidParticles.push(particle); } // Add grid helper for reference const gridHelper = new THREE.GridHelper(SPACE_SIZE, 20); gridHelper.position.y = -SPACE_SIZE / 2; scene.add(gridHelper); // Event listeners for controls document.getElementById('start-btn').addEventListener('click', () => { simulationRunning = true; updateParams(); }); document.getElementById('reset-btn').addEventListener('click', () => { simulationRunning = false; resetSimulation(); }); // Update sphere positions, masses, orbital velocities, centripetal force, and fluid interactions ['sun', 'earth', 'mars'].forEach(body => { document.getElementById(`${body}-mass`).addEventListener('input', updateParams); document.getElementById(`${body}-x`).addEventListener('input', updateParams); document.getElementById(`${body}-y`).addEventListener('input', updateParams); document.getElementById(`${body}-z`).addEventListener('input', updateParams); if (body !== 'sun') { document.getElementById(`${body}-orbital-velocity`).addEventListener('input', updateParams); document.getElementById(`${body}-centripetal`).addEventListener('input', updateParams); } }); document.getElementById('fluid-friction').addEventListener('input', updateParams); document.getElementById('fluid-deflection').addEventListener('input', updateParams); // Handle window resize window.addEventListener('resize', () => { camera.aspect = (window.innerWidth - 300) / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth - 300, window.innerHeight); }); } function updateParams() { // Update Sun spheres[0].userData.mass = parseFloat(document.getElementById('sun-mass').value) * 1e4; spheres[0].position.set( parseFloat(document.getElementById('sun-x').value), parseFloat(document.getElementById('sun-y').value), parseFloat(document.getElementById('sun-z').value) ); // Update Earth spheres[1].userData.mass = parseFloat(document.getElementById('earth-mass').value) * 1e4; spheres[1].position.set( parseFloat(document.getElementById('earth-x').value), parseFloat(document.getElementById('earth-y').value), parseFloat(document.getElementById('earth-z').value) ); const earthVelocity = parseFloat(document.getElementById('earth-orbital-velocity').value); spheres[1].userData.velocity.set(0, 0, earthVelocity); // Update velocity in Z direction for orbit spheres[1].userData.centripetalScale = parseFloat(document.getElementById('earth-centripetal').value); // Update Mars spheres[2].userData.mass = parseFloat(document.getElementById('mars-mass').value) * 1e4; spheres[2].position.set( parseFloat(document.getElementById('mars-x').value), parseFloat(document.getElementById('mars-y').value), parseFloat(document.getElementById('mars-z').value) ); const marsVelocity = parseFloat(document.getElementById('mars-orbital-velocity').value); spheres[2].userData.velocity.set(0, 0, marsVelocity); // Update velocity in Z direction for orbit spheres[2].userData.centripetalScale = parseFloat(document.getElementById('mars-centripetal').value); // Update fluid interaction parameters FLUID_FRICTION = parseFloat(document.getElementById('fluid-friction').value); FLUID_DEFLECTION = parseFloat(document.getElementById('fluid-deflection').value); } function resetSimulation() { fluidParticles.forEach(particle => { particle.position.set( (Math.random() - 0.5) * SPACE_SIZE, (Math.random() - 0.5) * SPACE_SIZE, (Math.random() - 0.5) * SPACE_SIZE ); particle.userData.velocity.set( (Math.random() - 0.5) * FLUID_SPEED, (Math.random() - 0.5) * FLUID_SPEED, (Math.random() - 0.5) * FLUID_SPEED ); }); // Reset positions and velocities for Earth and Mars spheres[1].position.set(10, 0, 0); spheres[1].userData.velocity.set(0, 0, 0.0298); spheres[2].position.set(15, 0, 0); spheres[2].userData.velocity.set(0, 0, 0.0241); } function animate() { requestAnimationFrame(animate); if (simulationRunning) { // Update fluid particles fluidParticles.forEach(particle => { let position = particle.position; let velocity = particle.userData.velocity; // Check for interactions with spheres spheres.forEach(sphere => { let distance = position.distanceTo(sphere.position); let sphereRadius = sphere.geometry.parameters.radius + 0.5; // Interaction radius if (distance < sphereRadius) { // Apply friction velocity.multiplyScalar(FLUID_FRICTION); // Apply gravitational deflection let direction = sphere.position.clone().sub(position).normalize(); let forceMagnitude = (FLUID_DEFLECTION * sphere.userData.mass) / (distance * distance); let force = direction.multiplyScalar(forceMagnitude); velocity.add(force); } }); // Update position position.add(velocity); // Boundary conditions (wrap around) if (Math.abs(position.x) > SPACE_SIZE / 2) position.x = -Math.sign(position.x) * SPACE_SIZE / 2; if (Math.abs(position.y) > SPACE_SIZE / 2) position.y = -Math.sign(position.y) * SPACE_SIZE / 2; if (Math.abs(position.z) > SPACE_SIZE / 2) position.z = -Math.sign(position.z) * SPACE_SIZE / 2; }); // Update sphere positions (gravitational interaction and orbital dynamics) spheres.forEach((sphere, i) => { if (i === 0) return; // Sun is stationary let acceleration = new THREE.Vector3(); spheres.forEach((otherSphere, j) => { if (i !== j) { let distance = sphere.position.distanceTo(otherSphere.position); if (distance > 0.1) { // Avoid division by zero let direction = otherSphere.position.clone().sub(sphere.position).normalize(); let force = (GRAVITY_CONSTANT * otherSphere.userData.mass) / (distance * distance); acceleration.add(direction.multiplyScalar(force * sphere.userData.centripetalScale)); } } }); // Update velocity and position sphere.userData.velocity.add(acceleration); sphere.position.add(sphere.userData.velocity); }); } controls.update(); renderer.render(scene, camera); }