Spaces:
Sleeping
Sleeping
// 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); | |
} |