Spaces:
Sleeping
Sleeping
Create script.js
Browse files- static/script.js +200 -0
static/script.js
ADDED
@@ -0,0 +1,200 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
// static/script.js
|
2 |
+
let scene, camera, renderer, controls;
|
3 |
+
let spheres = [];
|
4 |
+
let fluidParticles = [];
|
5 |
+
let simulationRunning = false;
|
6 |
+
|
7 |
+
const PARTICLE_COUNT = 5000;
|
8 |
+
const SPACE_SIZE = 20;
|
9 |
+
const FLUID_SPEED = 0.1;
|
10 |
+
const FRICTION_FACTOR = 0.9;
|
11 |
+
const GRAVITY_CONSTANT = 0.1;
|
12 |
+
|
13 |
+
init();
|
14 |
+
animate();
|
15 |
+
|
16 |
+
function init() {
|
17 |
+
// Scene setup
|
18 |
+
scene = new THREE.Scene();
|
19 |
+
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
|
20 |
+
camera.position.set(0, 10, 20);
|
21 |
+
|
22 |
+
renderer = new THREE.WebGLRenderer({ antialias: true });
|
23 |
+
renderer.setSize(window.innerWidth - 300, window.innerHeight);
|
24 |
+
document.getElementById('scene-container').appendChild(renderer.domElement);
|
25 |
+
|
26 |
+
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
27 |
+
controls.enableDamping = true;
|
28 |
+
controls.dampingFactor = 0.05;
|
29 |
+
|
30 |
+
// Add spheres
|
31 |
+
const brownGeometry = new THREE.SphereGeometry(0.5, 32, 32);
|
32 |
+
const brownMaterial = new THREE.MeshBasicMaterial({ color: 0x8B4513 });
|
33 |
+
const brownSphere = new THREE.Mesh(brownGeometry, brownMaterial);
|
34 |
+
brownSphere.position.set(0, 0, 0);
|
35 |
+
brownSphere.userData = { mass: 92 };
|
36 |
+
scene.add(brownSphere);
|
37 |
+
spheres.push(brownSphere);
|
38 |
+
|
39 |
+
const greenGeometry = new THREE.SphereGeometry(0.4, 32, 32);
|
40 |
+
const greenMaterial = new THREE.MeshBasicMaterial({ color: 0x00FF00 });
|
41 |
+
const greenSphere = new THREE.Mesh(greenGeometry, greenMaterial);
|
42 |
+
greenSphere.position.set(5, 0, 5);
|
43 |
+
greenSphere.userData = { mass: 29 };
|
44 |
+
scene.add(greenSphere);
|
45 |
+
spheres.push(greenSphere);
|
46 |
+
|
47 |
+
const redGeometry = new THREE.SphereGeometry(0.3, 32, 32);
|
48 |
+
const redMaterial = new THREE.MeshBasicMaterial({ color: 0xFF0000 });
|
49 |
+
const redSphere = new THREE.Mesh(redGeometry, redMaterial);
|
50 |
+
redSphere.position.set(-5, 0, -5);
|
51 |
+
redSphere.userData = { mass: 10 };
|
52 |
+
scene.add(redSphere);
|
53 |
+
spheres.push(redSphere);
|
54 |
+
|
55 |
+
// Add fluid particles
|
56 |
+
const particleGeometry = new THREE.SphereGeometry(0.05, 8, 8);
|
57 |
+
const particleMaterial = new THREE.MeshBasicMaterial({ color: 0x00BFFF, transparent: true, opacity: 0.5 });
|
58 |
+
for (let i = 0; i < PARTICLE_COUNT; i++) {
|
59 |
+
const particle = new THREE.Mesh(particleGeometry, particleMaterial);
|
60 |
+
particle.position.set(
|
61 |
+
(Math.random() - 0.5) * SPACE_SIZE,
|
62 |
+
(Math.random() - 0.5) * SPACE_SIZE,
|
63 |
+
(Math.random() - 0.5) * SPACE_SIZE
|
64 |
+
);
|
65 |
+
particle.userData = {
|
66 |
+
velocity: new THREE.Vector3(
|
67 |
+
(Math.random() - 0.5) * FLUID_SPEED,
|
68 |
+
(Math.random() - 0.5) * FLUID_SPEED,
|
69 |
+
(Math.random() - 0.5) * FLUID_SPEED
|
70 |
+
)
|
71 |
+
};
|
72 |
+
scene.add(particle);
|
73 |
+
fluidParticles.push(particle);
|
74 |
+
}
|
75 |
+
|
76 |
+
// Add grid helper for reference
|
77 |
+
const gridHelper = new THREE.GridHelper(SPACE_SIZE, 20);
|
78 |
+
gridHelper.position.y = -SPACE_SIZE / 2;
|
79 |
+
scene.add(gridHelper);
|
80 |
+
|
81 |
+
// Event listeners for controls
|
82 |
+
document.getElementById('start-btn').addEventListener('click', () => {
|
83 |
+
simulationRunning = true;
|
84 |
+
updateParams();
|
85 |
+
});
|
86 |
+
|
87 |
+
document.getElementById('reset-btn').addEventListener('click', () => {
|
88 |
+
simulationRunning = false;
|
89 |
+
resetSimulation();
|
90 |
+
});
|
91 |
+
|
92 |
+
// Update sphere positions and masses from sliders
|
93 |
+
['brown', 'green', 'red'].forEach(color => {
|
94 |
+
document.getElementById(`${color}-mass`).addEventListener('input', updateParams);
|
95 |
+
document.getElementById(`${color}-x`).addEventListener('input', updateParams);
|
96 |
+
document.getElementById(`${color}-y`).addEventListener('input', updateParams);
|
97 |
+
document.getElementById(`${color}-z`).addEventListener('input', updateParams);
|
98 |
+
});
|
99 |
+
|
100 |
+
// Handle window resize
|
101 |
+
window.addEventListener('resize', () => {
|
102 |
+
camera.aspect = (window.innerWidth - 300) / window.innerHeight;
|
103 |
+
camera.updateProjectionMatrix();
|
104 |
+
renderer.setSize(window.innerWidth - 300, window.innerHeight);
|
105 |
+
});
|
106 |
+
}
|
107 |
+
|
108 |
+
function updateParams() {
|
109 |
+
spheres[0].userData.mass = parseFloat(document.getElementById('brown-mass').value);
|
110 |
+
spheres[0].position.set(
|
111 |
+
parseFloat(document.getElementById('brown-x').value),
|
112 |
+
parseFloat(document.getElementById('brown-y').value),
|
113 |
+
parseFloat(document.getElementById('brown-z').value)
|
114 |
+
);
|
115 |
+
|
116 |
+
spheres[1].userData.mass = parseFloat(document.getElementById('green-mass').value);
|
117 |
+
spheres[1].position.set(
|
118 |
+
parseFloat(document.getElementById('green-x').value),
|
119 |
+
parseFloat(document.getElementById('green-y').value),
|
120 |
+
parseFloat(document.getElementById('green-z').value)
|
121 |
+
);
|
122 |
+
|
123 |
+
spheres[2].userData.mass = parseFloat(document.getElementById('red-mass').value);
|
124 |
+
spheres[2].position.set(
|
125 |
+
parseFloat(document.getElementById('red-x').value),
|
126 |
+
parseFloat(document.getElementById('red-y').value),
|
127 |
+
parseFloat(document.getElementById('red-z').value)
|
128 |
+
);
|
129 |
+
}
|
130 |
+
|
131 |
+
function resetSimulation() {
|
132 |
+
fluidParticles.forEach(particle => {
|
133 |
+
particle.position.set(
|
134 |
+
(Math.random() - 0.5) * SPACE_SIZE,
|
135 |
+
(Math.random() - 0.5) * SPACE_SIZE,
|
136 |
+
(Math.random() - 0.5) * SPACE_SIZE
|
137 |
+
);
|
138 |
+
particle.userData.velocity.set(
|
139 |
+
(Math.random() - 0.5) * FLUID_SPEED,
|
140 |
+
(Math.random() - 0.5) * FLUID_SPEED,
|
141 |
+
(Math.random() - 0.5) * FLUID_SPEED
|
142 |
+
);
|
143 |
+
});
|
144 |
+
}
|
145 |
+
|
146 |
+
function animate() {
|
147 |
+
requestAnimationFrame(animate);
|
148 |
+
|
149 |
+
if (simulationRunning) {
|
150 |
+
// Update fluid particles
|
151 |
+
fluidParticles.forEach(particle => {
|
152 |
+
let position = particle.position;
|
153 |
+
let velocity = particle.userData.velocity;
|
154 |
+
|
155 |
+
// Check for interactions with spheres
|
156 |
+
spheres.forEach(sphere => {
|
157 |
+
let distance = position.distanceTo(sphere.position);
|
158 |
+
let sphereRadius = sphere.geometry.parameters.radius + 0.5; // Interaction radius
|
159 |
+
|
160 |
+
if (distance < sphereRadius) {
|
161 |
+
// Apply friction
|
162 |
+
velocity.multiplyScalar(FRICTION_FACTOR);
|
163 |
+
|
164 |
+
// Apply gravitational deflection
|
165 |
+
let direction = sphere.position.clone().sub(position).normalize();
|
166 |
+
let forceMagnitude = (GRAVITY_CONSTANT * sphere.userData.mass) / (distance * distance);
|
167 |
+
let force = direction.multiplyScalar(forceMagnitude);
|
168 |
+
velocity.add(force);
|
169 |
+
}
|
170 |
+
});
|
171 |
+
|
172 |
+
// Update position
|
173 |
+
position.add(velocity);
|
174 |
+
|
175 |
+
// Boundary conditions (wrap around)
|
176 |
+
if (Math.abs(position.x) > SPACE_SIZE / 2) position.x = -Math.sign(position.x) * SPACE_SIZE / 2;
|
177 |
+
if (Math.abs(position.y) > SPACE_SIZE / 2) position.y = -Math.sign(position.y) * SPACE_SIZE / 2;
|
178 |
+
if (Math.abs(position.z) > SPACE_SIZE / 2) position.z = -Math.sign(position.z) * SPACE_SIZE / 2;
|
179 |
+
});
|
180 |
+
|
181 |
+
// Update sphere positions (gravitational interaction between spheres)
|
182 |
+
spheres.forEach((sphere, i) => {
|
183 |
+
let acceleration = new THREE.Vector3();
|
184 |
+
spheres.forEach((otherSphere, j) => {
|
185 |
+
if (i !== j) {
|
186 |
+
let distance = sphere.position.distanceTo(otherSphere.position);
|
187 |
+
if (distance > 0.1) { // Avoid division by zero
|
188 |
+
let direction = otherSphere.position.clone().sub(sphere.position).normalize();
|
189 |
+
let force = (GRAVITY_CONSTANT * otherSphere.userData.mass) / (distance * distance);
|
190 |
+
acceleration.add(direction.multiplyScalar(force));
|
191 |
+
}
|
192 |
+
}
|
193 |
+
});
|
194 |
+
sphere.position.add(acceleration);
|
195 |
+
});
|
196 |
+
}
|
197 |
+
|
198 |
+
controls.update();
|
199 |
+
renderer.render(scene, camera);
|
200 |
+
}
|