3dsolarsystem / static /static.html
Donmill's picture
Rename static.html to static/static.html
0169989 verified
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Enhanced 3D Solar System</title>
<style>
body { margin: 0; overflow: hidden; }
#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; }
#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; }
#panel h2 { margin-top: 0; }
#closePanel { float: right; cursor: pointer; color: #fff; font-size: 18px; }
#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; }
#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; }
button { background: #444; color: white; border: none; padding: 5px 10px; margin: 5px 0; cursor: pointer; border-radius: 3px; }
button:hover { background: #666; }
input { padding: 5px; margin: 5px 0; width: 100%; }
#ai-response { margin-top: 10px; max-height: 200px; overflow-y: auto; }
</style>
</head>
<body>
<div id="info">Click a planet to learn more!</div>
<div id="panel"><span id="closePanel">&times;</span><h2 id="panel-title"></h2><div id="panel-content"></div></div>
<div id="ai-chat">
<h3>Ask the AI about the Solar System</h3>
<input id="ai-question" type="text" placeholder="Your question...">
<button id="ai-submit">Ask</button>
<div id="ai-response"></div>
</div>
<div id="loading">Loading...</div>
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/examples/js/controls/OrbitControls.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.152.2/examples/js/renderers/CSS2DRenderer.js"></script>
<script>
// --- Three.js Solar System with enhancements ---
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000010);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 30, 70);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// CSS2DRenderer for labels
const labelRenderer = new THREE.CSS2DRenderer();
labelRenderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.domElement.style.position = 'absolute';
labelRenderer.domElement.style.top = '0px';
labelRenderer.domElement.style.pointerEvents = 'none';
document.body.appendChild(labelRenderer.domElement);
// Controls
const controls = new THREE.OrbitControls(camera, renderer.domElement);
// Lighting
scene.add(new THREE.AmbientLight(0x404040));
const sunLight = new THREE.PointLight(0xffffaa, 2, 200);
scene.add(sunLight);
// Textures (remote URLs)
const textures = {
"Sun": "https://www.solarsystemscope.com/textures/download/2k_sun.jpg",
"Mercury": "https://www.solarsystemscope.com/textures/download/2k_mercury.jpg",
"Venus": "https://www.solarsystemscope.com/textures/download/2k_venus_surface.jpg",
"Earth": "https://www.solarsystemscope.com/textures/download/2k_earth_daymap.jpg",
"Moon": "https://www.solarsystemscope.com/textures/download/2k_moon.jpg",
"Mars": "https://www.solarsystemscope.com/textures/download/2k_mars.jpg",
"Jupiter": "https://www.solarsystemscope.com/textures/download/2k_jupiter.jpg",
"Saturn": "https://www.solarsystemscope.com/textures/download/2k_saturn.jpg",
"Uranus": "https://www.solarsystemscope.com/textures/download/2k_uranus.jpg",
"Neptune": "https://www.solarsystemscope.com/textures/download/2k_neptune.jpg"
};
// Planets and moons
const planets = [
{ name: "Mercury", radius: 0.8, distance: 10, speed: 0.04, moons: [] },
{ name: "Venus", radius: 1.2, distance: 15, speed: 0.03, moons: [] },
{
name: "Earth", radius: 1.2, distance: 20, speed: 0.02,
moons: [{ name: "Moon", radius: 0.3, distance: 2, speed: 0.05 }]
},
{ name: "Mars", radius: 0.9, distance: 25, speed: 0.015, moons: [] },
{
name: "Jupiter", radius: 2.5, distance: 35, speed: 0.01,
moons: [{ name: "Europa", radius: 0.2, distance: 4, speed: 0.04 }]
},
{
name: "Saturn", radius: 2.2, distance: 45, speed: 0.008, rings: true, moons: []
},
{ name: "Uranus", radius: 1.8, distance: 55, speed: 0.005, moons: [] },
{ name: "Neptune", radius: 1.8, distance: 65, speed: 0.003, moons: [] }
];
// Asteroid belt
for (let i = 0; i < 200; i++) {
const beltGeometry = new THREE.SphereGeometry(0.1, 8, 8);
const beltMaterial = new THREE.MeshPhongMaterial({ color: 0x888888 });
const beltMesh = new THREE.Mesh(beltGeometry, beltMaterial);
const angle = Math.random() * Math.PI * 2;
const distance = 28 + Math.random() * 4;
beltMesh.position.x = Math.cos(angle) * distance;
beltMesh.position.z = Math.sin(angle) * distance;
beltMesh.position.y = (Math.random() - 0.5) * 0.5;
scene.add(beltMesh);
}
// Sun
const sunTexture = new THREE.TextureLoader().load(textures["Sun"]);
const sunGeometry = new THREE.SphereGeometry(4, 64, 64);
const sunMaterial = new THREE.MeshBasicMaterial({ map: sunTexture });
const sun = new THREE.Mesh(sunGeometry, sunMaterial);
scene.add(sun);
sunLight.position.copy(sun.position);
addLabel(sun, "Sun");
// Create planets, moons, rings, orbits
const planetObjects = [];
const clickableObjects = [];
planets.forEach((planet) => {
const texture = textures[planet.name] ? new THREE.TextureLoader().load(textures[planet.name]) : null;
const geometry = new THREE.SphereGeometry(planet.radius, 32, 32);
const material = texture ? new THREE.MeshPhongMaterial({ map: texture }) : new THREE.MeshPhongMaterial({ color: 0xffffff });
const mesh = new THREE.Mesh(geometry, material);
mesh.position.x = planet.distance;
mesh.userData = { type: 'planet', name: planet.name };
scene.add(mesh);
clickableObjects.push(mesh);
addLabel(mesh, planet.name);
// Saturn's rings
if (planet.rings) {
const ringGeometry = new THREE.RingGeometry(planet.radius * 1.5, planet.radius * 2.2, 64);
const ringMaterial = new THREE.MeshPhongMaterial({ color: 0xe9e5c6, side: THREE.DoubleSide, transparent: true, opacity: 0.7 });
const ring = new THREE.Mesh(ringGeometry, ringMaterial);
ring.rotation.x = Math.PI / 2;
mesh.add(ring);
}
// Moons
const planetMoons = [];
if (planet.moons && planet.moons.length > 0) {
planet.moons.forEach(moon => {
const moonGeometry = new THREE.SphereGeometry(moon.radius, 16, 16);
const moonMaterial = new THREE.MeshPhongMaterial({ color: 0xcccccc });
const moonMesh = new THREE.Mesh(moonGeometry, moonMaterial);
moonMesh.position.x = moon.distance;
moonMesh.userData = { type: 'moon', name: moon.name, parent: planet.name };
mesh.add(moonMesh);
planetMoons.push({ mesh: moonMesh, ...moon });
addLabel(moonMesh, moon.name);
clickableObjects.push(moonMesh);
});
}
// Orbit path
const orbitGeometry = new THREE.BufferGeometry();
const points = [];
const segments = 64;
for (let i = 0; i <= segments; i++) {
const theta = (i / segments) * Math.PI * 2;
points.push(new THREE.Vector3(
Math.cos(theta) * planet.distance,
0,
Math.sin(theta) * planet.distance
));
}
orbitGeometry.setFromPoints(points);
const orbitMaterial = new THREE.LineBasicMaterial({ color: 0xaaaaaa, transparent: true, opacity: 0.4 });
const orbit = new THREE.Line(orbitGeometry, orbitMaterial);
scene.add(orbit);
planetObjects.push({ mesh, ...planet, moons: planetMoons });
});
// Add labels
function addLabel(object, name) {
const div = document.createElement('div');
div.className = 'label';
div.textContent = name;
div.style.color = '#fff';
div.style.fontSize = '14px';
div.style.textShadow = '0 0 5px #000';
const label = new THREE.CSS2DObject(div);
label.position.set(0, object.geometry.parameters.radius + 0.6, 0);
object.add(label);
}
// Raycaster for click events
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
window.addEventListener('click', (event) => {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(clickableObjects, true);
if (intersects.length > 0) {
const obj = intersects[0].object;
showPanel(obj.userData);
}
});
// Info panel logic
function showPanel(data) {
const panel = document.getElementById('panel');
const title = document.getElementById('panel-title');
const content = document.getElementById('panel-content');
panel.style.display = 'block';
title.textContent = data.name;
content.innerHTML = "Loading info...";
// Example: fetch Wikipedia summary (or use your AI backend)
fetch(`https://en.wikipedia.org/api/rest_v1/page/summary/${encodeURIComponent(data.name)}`)
.then(res => res.json())
.then(info => {
content.innerHTML = info.extract_html || "No info found.";
})
.catch(() => {
content.innerHTML = "No info found.";
});
}
document.getElementById('closePanel').onclick = () => {
document.getElementById('panel').style.display = 'none';
};
// Animation loop
let angle = 0;
function animate() {
requestAnimationFrame(animate);
controls.update();
angle += 0.005;
planetObjects.forEach((planet) => {
planet.mesh.position.x = Math.cos(angle * planet.speed) * planet.distance;
planet.mesh.position.z = Math.sin(angle * planet.speed) * planet.distance;
if (planet.moons) {
planet.moons.forEach((moon) => {
moon.mesh.position.x = Math.cos(angle * moon.speed) * moon.distance;
moon.mesh.position.z = Math.sin(angle * moon.speed) * moon.distance;
});
}
});
renderer.render(scene, camera);
labelRenderer.render(scene, camera);
}
animate();
// Responsive resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
labelRenderer.setSize(window.innerWidth, window.innerHeight);
});
// --- AI Chat Integration ---
document.getElementById('ai-submit').addEventListener('click', async () => {
const question = document.getElementById('ai-question').value;
const responseDiv = document.getElementById('ai-response');
const loadingDiv = document.getElementById('loading');
responseDiv.textContent = "";
loadingDiv.style.display = "block";
try {
const resp = await fetch("/api/ask", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ question })
});
const data = await resp.json();
if (data.answer) {
responseDiv.textContent = "AI: " + data.answer;
} else {
responseDiv.textContent = "Error: " + (data.error || "Unknown error.");
}
} catch (error) {
responseDiv.textContent = "Error: Could not connect to AI.";
}
loadingDiv.style.display = "none";
});
</script>
</body>
</html>