Donmill commited on
Commit
d586eda
·
verified ·
1 Parent(s): 97f1f9e

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +281 -0
index.html ADDED
@@ -0,0 +1,281 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Enhanced 3D Solar System</title>
6
+ <style>
7
+ body { margin: 0; overflow: hidden; }
8
+ #info { position: absolute; top: 10px; left: 10px; color: white; background: rgba(0,0,0,0.5); padding: 10px; font-family: Arial, sans-serif; border-radius: 5px; z-index: 100; }
9
+ #panel { position: absolute; top: 10px; right: 10px; background: rgba(0,0,0,0.8); color: #fff; padding: 15px; border-radius: 10px; min-width: 220px; z-index: 200; display: none; }
10
+ #panel h2 { margin-top: 0; }
11
+ #closePanel { float: right; cursor: pointer; color: #fff; font-size: 18px; }
12
+ #ai-chat { position: absolute; bottom: 10px; right: 10px; color: white; background: rgba(0,0,0,0.7); padding: 10px; font-family: Arial, sans-serif; border-radius: 5px; max-width: 300px; z-index: 100; }
13
+ #loading { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); color: white; background: rgba(0,0,0,0.7); padding: 20px; border-radius: 10px; font-family: Arial, sans-serif; display: none; z-index: 1000; }
14
+ button { background: #444; color: white; border: none; padding: 5px 10px; margin: 5px 0; cursor: pointer; border-radius: 3px; }
15
+ button:hover { background: #666; }
16
+ input { padding: 5px; margin: 5px 0; width: 100%; }
17
+ #ai-response { margin-top: 10px; max-height: 200px; overflow-y: auto; }
18
+ </style>
19
+ </head>
20
+ <body>
21
+ <div id="info">Click a planet to learn more!</div>
22
+ <div id="panel"><span id="closePanel">&times;</span><h2 id="panel-title"></h2><div id="panel-content"></div></div>
23
+ <div id="ai-chat">
24
+ <h3>Ask the AI about the Solar System</h3>
25
+ <input id="ai-question" type="text" placeholder="Your question...">
26
+ <button id="ai-submit">Ask</button>
27
+ <div id="ai-response"></div>
28
+ </div>
29
+ <div id="loading">Loading...</div>
30
+ <script src="https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.min.js"></script>
31
+ <script src="https://cdn.jsdelivr.net/npm/three@0.152.2/examples/js/controls/OrbitControls.js"></script>
32
+ <script src="https://cdn.jsdelivr.net/npm/three@0.152.2/examples/js/renderers/CSS2DRenderer.js"></script>
33
+ <script>
34
+ // --- Three.js Solar System with enhancements ---
35
+ const scene = new THREE.Scene();
36
+ scene.background = new THREE.Color(0x000010);
37
+
38
+ const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
39
+ camera.position.set(0, 30, 70);
40
+
41
+ const renderer = new THREE.WebGLRenderer({ antialias: true });
42
+ renderer.setSize(window.innerWidth, window.innerHeight);
43
+ document.body.appendChild(renderer.domElement);
44
+
45
+ // CSS2DRenderer for labels
46
+ const labelRenderer = new THREE.CSS2DRenderer();
47
+ labelRenderer.setSize(window.innerWidth, window.innerHeight);
48
+ labelRenderer.domElement.style.position = 'absolute';
49
+ labelRenderer.domElement.style.top = '0px';
50
+ labelRenderer.domElement.style.pointerEvents = 'none';
51
+ document.body.appendChild(labelRenderer.domElement);
52
+
53
+ // Controls
54
+ const controls = new THREE.OrbitControls(camera, renderer.domElement);
55
+
56
+ // Lighting
57
+ scene.add(new THREE.AmbientLight(0x404040));
58
+ const sunLight = new THREE.PointLight(0xffffaa, 2, 200);
59
+ scene.add(sunLight);
60
+
61
+ // Textures (remote URLs)
62
+ const textures = {
63
+ "Sun": "https://www.solarsystemscope.com/textures/download/2k_sun.jpg",
64
+ "Mercury": "https://www.solarsystemscope.com/textures/download/2k_mercury.jpg",
65
+ "Venus": "https://www.solarsystemscope.com/textures/download/2k_venus_surface.jpg",
66
+ "Earth": "https://www.solarsystemscope.com/textures/download/2k_earth_daymap.jpg",
67
+ "Moon": "https://www.solarsystemscope.com/textures/download/2k_moon.jpg",
68
+ "Mars": "https://www.solarsystemscope.com/textures/download/2k_mars.jpg",
69
+ "Jupiter": "https://www.solarsystemscope.com/textures/download/2k_jupiter.jpg",
70
+ "Saturn": "https://www.solarsystemscope.com/textures/download/2k_saturn.jpg",
71
+ "Uranus": "https://www.solarsystemscope.com/textures/download/2k_uranus.jpg",
72
+ "Neptune": "https://www.solarsystemscope.com/textures/download/2k_neptune.jpg"
73
+ };
74
+
75
+ // Planets and moons
76
+ const planets = [
77
+ { name: "Mercury", radius: 0.8, distance: 10, speed: 0.04, moons: [] },
78
+ { name: "Venus", radius: 1.2, distance: 15, speed: 0.03, moons: [] },
79
+ {
80
+ name: "Earth", radius: 1.2, distance: 20, speed: 0.02,
81
+ moons: [{ name: "Moon", radius: 0.3, distance: 2, speed: 0.05 }]
82
+ },
83
+ { name: "Mars", radius: 0.9, distance: 25, speed: 0.015, moons: [] },
84
+ {
85
+ name: "Jupiter", radius: 2.5, distance: 35, speed: 0.01,
86
+ moons: [{ name: "Europa", radius: 0.2, distance: 4, speed: 0.04 }]
87
+ },
88
+ {
89
+ name: "Saturn", radius: 2.2, distance: 45, speed: 0.008, rings: true, moons: []
90
+ },
91
+ { name: "Uranus", radius: 1.8, distance: 55, speed: 0.005, moons: [] },
92
+ { name: "Neptune", radius: 1.8, distance: 65, speed: 0.003, moons: [] }
93
+ ];
94
+
95
+ // Asteroid belt
96
+ for (let i = 0; i < 200; i++) {
97
+ const beltGeometry = new THREE.SphereGeometry(0.1, 8, 8);
98
+ const beltMaterial = new THREE.MeshPhongMaterial({ color: 0x888888 });
99
+ const beltMesh = new THREE.Mesh(beltGeometry, beltMaterial);
100
+ const angle = Math.random() * Math.PI * 2;
101
+ const distance = 28 + Math.random() * 4;
102
+ beltMesh.position.x = Math.cos(angle) * distance;
103
+ beltMesh.position.z = Math.sin(angle) * distance;
104
+ beltMesh.position.y = (Math.random() - 0.5) * 0.5;
105
+ scene.add(beltMesh);
106
+ }
107
+
108
+ // Sun
109
+ const sunTexture = new THREE.TextureLoader().load(textures["Sun"]);
110
+ const sunGeometry = new THREE.SphereGeometry(4, 64, 64);
111
+ const sunMaterial = new THREE.MeshBasicMaterial({ map: sunTexture });
112
+ const sun = new THREE.Mesh(sunGeometry, sunMaterial);
113
+ scene.add(sun);
114
+ sunLight.position.copy(sun.position);
115
+ addLabel(sun, "Sun");
116
+
117
+ // Create planets, moons, rings, orbits
118
+ const planetObjects = [];
119
+ const clickableObjects = [];
120
+ planets.forEach((planet) => {
121
+ const texture = textures[planet.name] ? new THREE.TextureLoader().load(textures[planet.name]) : null;
122
+ const geometry = new THREE.SphereGeometry(planet.radius, 32, 32);
123
+ const material = texture ? new THREE.MeshPhongMaterial({ map: texture }) : new THREE.MeshPhongMaterial({ color: 0xffffff });
124
+ const mesh = new THREE.Mesh(geometry, material);
125
+ mesh.position.x = planet.distance;
126
+ mesh.userData = { type: 'planet', name: planet.name };
127
+ scene.add(mesh);
128
+ clickableObjects.push(mesh);
129
+ addLabel(mesh, planet.name);
130
+
131
+ // Saturn's rings
132
+ if (planet.rings) {
133
+ const ringGeometry = new THREE.RingGeometry(planet.radius * 1.5, planet.radius * 2.2, 64);
134
+ const ringMaterial = new THREE.MeshPhongMaterial({ color: 0xe9e5c6, side: THREE.DoubleSide, transparent: true, opacity: 0.7 });
135
+ const ring = new THREE.Mesh(ringGeometry, ringMaterial);
136
+ ring.rotation.x = Math.PI / 2;
137
+ mesh.add(ring);
138
+ }
139
+
140
+ // Moons
141
+ const planetMoons = [];
142
+ if (planet.moons && planet.moons.length > 0) {
143
+ planet.moons.forEach(moon => {
144
+ const moonGeometry = new THREE.SphereGeometry(moon.radius, 16, 16);
145
+ const moonMaterial = new THREE.MeshPhongMaterial({ color: 0xcccccc });
146
+ const moonMesh = new THREE.Mesh(moonGeometry, moonMaterial);
147
+ moonMesh.position.x = moon.distance;
148
+ moonMesh.userData = { type: 'moon', name: moon.name, parent: planet.name };
149
+ mesh.add(moonMesh);
150
+ planetMoons.push({ mesh: moonMesh, ...moon });
151
+ addLabel(moonMesh, moon.name);
152
+ clickableObjects.push(moonMesh);
153
+ });
154
+ }
155
+
156
+ // Orbit path
157
+ const orbitGeometry = new THREE.BufferGeometry();
158
+ const points = [];
159
+ const segments = 64;
160
+ for (let i = 0; i <= segments; i++) {
161
+ const theta = (i / segments) * Math.PI * 2;
162
+ points.push(new THREE.Vector3(
163
+ Math.cos(theta) * planet.distance,
164
+ 0,
165
+ Math.sin(theta) * planet.distance
166
+ ));
167
+ }
168
+ orbitGeometry.setFromPoints(points);
169
+ const orbitMaterial = new THREE.LineBasicMaterial({ color: 0xaaaaaa, transparent: true, opacity: 0.4 });
170
+ const orbit = new THREE.Line(orbitGeometry, orbitMaterial);
171
+ scene.add(orbit);
172
+
173
+ planetObjects.push({ mesh, ...planet, moons: planetMoons });
174
+ });
175
+
176
+ // Add labels
177
+ function addLabel(object, name) {
178
+ const div = document.createElement('div');
179
+ div.className = 'label';
180
+ div.textContent = name;
181
+ div.style.color = '#fff';
182
+ div.style.fontSize = '14px';
183
+ div.style.textShadow = '0 0 5px #000';
184
+ const label = new THREE.CSS2DObject(div);
185
+ label.position.set(0, object.geometry.parameters.radius + 0.6, 0);
186
+ object.add(label);
187
+ }
188
+
189
+ // Raycaster for click events
190
+ const raycaster = new THREE.Raycaster();
191
+ const mouse = new THREE.Vector2();
192
+
193
+ window.addEventListener('click', (event) => {
194
+ mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
195
+ mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
196
+ raycaster.setFromCamera(mouse, camera);
197
+ const intersects = raycaster.intersectObjects(clickableObjects, true);
198
+ if (intersects.length > 0) {
199
+ const obj = intersects[0].object;
200
+ showPanel(obj.userData);
201
+ }
202
+ });
203
+
204
+ // Info panel logic
205
+ function showPanel(data) {
206
+ const panel = document.getElementById('panel');
207
+ const title = document.getElementById('panel-title');
208
+ const content = document.getElementById('panel-content');
209
+ panel.style.display = 'block';
210
+ title.textContent = data.name;
211
+ content.innerHTML = "Loading info...";
212
+ // Example: fetch Wikipedia summary (or use your AI backend)
213
+ fetch(`https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(data.name)}`)
214
+ .then(res => res.json())
215
+ .then(info => {
216
+ content.innerHTML = info.extract_html || "No info found.";
217
+ })
218
+ .catch(() => {
219
+ content.innerHTML = "No info found.";
220
+ });
221
+ }
222
+ document.getElementById('closePanel').onclick = () => {
223
+ document.getElementById('panel').style.display = 'none';
224
+ };
225
+
226
+ // Animation loop
227
+ let angle = 0;
228
+ function animate() {
229
+ requestAnimationFrame(animate);
230
+ controls.update();
231
+ angle += 0.005;
232
+ planetObjects.forEach((planet) => {
233
+ planet.mesh.position.x = Math.cos(angle * planet.speed) * planet.distance;
234
+ planet.mesh.position.z = Math.sin(angle * planet.speed) * planet.distance;
235
+ if (planet.moons) {
236
+ planet.moons.forEach((moon) => {
237
+ moon.mesh.position.x = Math.cos(angle * moon.speed) * moon.distance;
238
+ moon.mesh.position.z = Math.sin(angle * moon.speed) * moon.distance;
239
+ });
240
+ }
241
+ });
242
+ renderer.render(scene, camera);
243
+ labelRenderer.render(scene, camera);
244
+ }
245
+ animate();
246
+
247
+ // Responsive resize
248
+ window.addEventListener('resize', () => {
249
+ camera.aspect = window.innerWidth / window.innerHeight;
250
+ camera.updateProjectionMatrix();
251
+ renderer.setSize(window.innerWidth, window.innerHeight);
252
+ labelRenderer.setSize(window.innerWidth, window.innerHeight);
253
+ });
254
+
255
+ // --- AI Chat Integration ---
256
+ document.getElementById('ai-submit').addEventListener('click', async () => {
257
+ const question = document.getElementById('ai-question').value;
258
+ const responseDiv = document.getElementById('ai-response');
259
+ const loadingDiv = document.getElementById('loading');
260
+ responseDiv.textContent = "";
261
+ loadingDiv.style.display = "block";
262
+ try {
263
+ const resp = await fetch("/api/ask", {
264
+ method: "POST",
265
+ headers: { "Content-Type": "application/json" },
266
+ body: JSON.stringify({ question })
267
+ });
268
+ const data = await resp.json();
269
+ if (data.answer) {
270
+ responseDiv.textContent = "AI: " + data.answer;
271
+ } else {
272
+ responseDiv.textContent = "Error: " + (data.error || "Unknown error.");
273
+ }
274
+ } catch (error) {
275
+ responseDiv.textContent = "Error: Could not connect to AI.";
276
+ }
277
+ loadingDiv.style.display = "none";
278
+ });
279
+ </script>
280
+ </body>
281
+ </html>