Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Interactive Solar System</title> | |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/OrbitControls.min.js"></script> | |
| <style> | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| } | |
| body { | |
| overflow: hidden; | |
| background: #000; | |
| font-family: 'Arial', sans-serif; | |
| } | |
| #canvas-container { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| width: 100%; | |
| height: 100%; | |
| } | |
| .controls { | |
| position: absolute; | |
| bottom: 30px; | |
| left: 50%; | |
| transform: translateX(-50%); | |
| display: flex; | |
| gap: 20px; | |
| background: rgba(0, 0, 0, 0.7); | |
| padding: 15px 25px; | |
| border-radius: 50px; | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| } | |
| .control-btn { | |
| background: linear-gradient(45deg, #4a00e0, #8e2de2); | |
| border: none; | |
| color: white; | |
| width: 50px; | |
| height: 50px; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| font-size: 18px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| transition: all 0.3s ease; | |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); | |
| } | |
| .control-btn:hover { | |
| transform: scale(1.1); | |
| box-shadow: 0 8px 25px rgba(142, 45, 226, 0.4); | |
| } | |
| .speed-control { | |
| display: flex; | |
| align-items: center; | |
| gap: 15px; | |
| color: white; | |
| } | |
| .speed-slider { | |
| width: 200px; | |
| height: 6px; | |
| -webkit-appearance: none; | |
| background: linear-gradient(to right, #4a00e0, #8e2de2); | |
| border-radius: 3px; | |
| outline: none; | |
| } | |
| .speed-slider::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| width: 20px; | |
| height: 20px; | |
| border-radius: 50%; | |
| background: white; | |
| cursor: pointer; | |
| box-shadow: 0 0 10px rgba(142, 45, 226, 0.8); | |
| } | |
| .info-panel { | |
| position: absolute; | |
| top: 30px; | |
| right: 30px; | |
| width: 320px; | |
| background: rgba(0, 0, 0, 0.85); | |
| backdrop-filter: blur(20px); | |
| border-radius: 20px; | |
| padding: 25px; | |
| color: white; | |
| border: 1px solid rgba(255, 255, 255, 0.1); | |
| box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5); | |
| transform: translateX(120%); | |
| transition: transform 0.5s cubic-bezier(0.68, -0.55, 0.265, 1.55); | |
| z-index: 100; | |
| } | |
| .info-panel.visible { | |
| transform: translateX(0); | |
| } | |
| .info-header { | |
| display: flex; | |
| align-items: center; | |
| margin-bottom: 20px; | |
| } | |
| .planet-icon { | |
| width: 50px; | |
| height: 50px; | |
| border-radius: 50%; | |
| margin-right: 15px; | |
| background-size: cover; | |
| } | |
| .planet-name { | |
| font-size: 24px; | |
| font-weight: bold; | |
| background: linear-gradient(45deg, #4a00e0, #8e2de2); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| } | |
| .info-content { | |
| line-height: 1.6; | |
| } | |
| .info-item { | |
| margin-bottom: 15px; | |
| padding-bottom: 15px; | |
| border-bottom: 1px solid rgba(255, 255, 255, 0.1); | |
| } | |
| .info-label { | |
| color: #8e2de2; | |
| font-weight: bold; | |
| margin-bottom: 5px; | |
| } | |
| .info-value { | |
| color: white; | |
| font-size: 16px; | |
| } | |
| .info-description { | |
| color: #ccc; | |
| font-size: 14px; | |
| line-height: 1.5; | |
| } | |
| .close-btn { | |
| position: absolute; | |
| top: 15px; | |
| right: 15px; | |
| background: rgba(255, 255, 255, 0.1); | |
| border: none; | |
| color: white; | |
| width: 30px; | |
| height: 30px; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| font-size: 16px; | |
| } | |
| .title { | |
| position: absolute; | |
| top: 30px; | |
| left: 30px; | |
| color: white; | |
| font-size: 28px; | |
| font-weight: bold; | |
| text-shadow: 0 0 20px rgba(142, 45, 226, 0.8); | |
| } | |
| .title span { | |
| background: linear-gradient(45deg, #4a00e0, #8e2de2); | |
| -webkit-background-clip: text; | |
| -webkit-text-fill-color: transparent; | |
| } | |
| @media (max-width: 768px) { | |
| .controls { | |
| flex-direction: column; | |
| border-radius: 20px; | |
| padding: 15px; | |
| } | |
| .info-panel { | |
| width: calc(100% - 40px); | |
| right: 20px; | |
| top: 20px; | |
| } | |
| .title { | |
| font-size: 20px; | |
| top: 15px; | |
| left: 15px; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id="canvas-container"></div> | |
| <div class="title">Interactive <span>Solar System</span></div> | |
| <div class="controls"> | |
| <button id="playPauseBtn" class="control-btn">βΈοΈ</button> | |
| <div class="speed-control"> | |
| <span>π’</span> | |
| <input type="range" id="speedSlider" class="speed-slider" min="0" max="2" step="0.1" value="1"> | |
| <span>π°</span> | |
| </div> | |
| </div> | |
| <div id="infoPanel" class="info-panel"> | |
| <button class="close-btn">Γ</button> | |
| <div class="info-header"> | |
| <div class="planet-icon" id="planetIcon"></div> | |
| <div class="planet-name" id="planetName">Planet Name</div> | |
| </div> | |
| <div class="info-content"> | |
| <div class="info-item"> | |
| <div class="info-label">Distance from Sun</div> | |
| <div class="info-value" id="distance">0 million km</div> | |
| </div> | |
| <div class="info-item"> | |
| <div class="info-label">Orbital Period</div> | |
| <div class="info-value" id="period">0 Earth days</div> | |
| </div> | |
| <div class="info-item"> | |
| <div class="info-label">Description</div> | |
| <div class="info-description" id="description">Planet description...</div> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // Planet data with realistic information | |
| const planetData = [ | |
| { | |
| name: "Mercury", | |
| radius: 1.2, | |
| distance: 20, | |
| speed: 4.0, | |
| rotationSpeed: 0.017, | |
| color: 0x8a8a8a, | |
| description: "The smallest planet in our solar system and closest to the Sun. Mercury has no atmosphere and experiences extreme temperature variations.", | |
| distanceFromSun: 57.9, | |
| orbitalPeriod: 88 | |
| }, | |
| { | |
| name: "Venus", | |
| radius: 3.0, | |
| distance: 30, | |
| speed: 3.25, | |
| rotationSpeed: 0.004, | |
| color: 0xe39e1c, | |
| description: "The hottest planet in our solar system with a thick toxic atmosphere. Venus is often called Earth's sister planet due to its similar size.", | |
| distanceFromSun: 108.2, | |
| orbitalPeriod: 225 | |
| }, | |
| { | |
| name: "Earth", | |
| radius: 3.1, | |
| distance: 40, | |
| speed: 2.75, | |
| rotationSpeed: 0.01, | |
| color: 0x1f77b4, | |
| description: "Our home planet and the only known place in the universe with life. Earth has a diverse biosphere and a protective atmosphere.", | |
| distanceFromSun: 149.6, | |
| orbitalPeriod: 365 | |
| }, | |
| { | |
| name: "Mars", | |
| radius: 1.7, | |
| distance: 50, | |
| speed: 2.25, | |
| rotationSpeed: 0.0097, | |
| color: 0xff7f0e, | |
| description: "The Red Planet known for its iron oxide surface. Mars has the largest volcano and canyon in the solar system.", | |
| distanceFromSun: 227.9, | |
| orbitalPeriod: 687 | |
| }, | |
| { | |
| name: "Jupiter", | |
| radius: 10.0, | |
| distance: 70, | |
| speed: 1.25, | |
| rotationSpeed: 0.024, | |
| color: 0xd8ca9d, | |
| description: "The largest planet in our solar system, a gas giant with a prominent Great Red Spot storm. Jupiter has at least 79 moons.", | |
| distanceFromSun: 778.5, | |
| orbitalPeriod: 4333 | |
| }, | |
| { | |
| name: "Saturn", | |
| radius: 8.4, | |
| distance: 90, | |
| speed: 1.0, | |
| rotationSpeed: 0.019, | |
| color: 0xf0e0a0, | |
| description: "Famous for its spectacular ring system made of ice and rock particles. Saturn is the least dense planet in our solar system.", | |
| distanceFromSun: 1432.0, | |
| orbitalPeriod: 10759 | |
| }, | |
| { | |
| name: "Uranus", | |
| radius: 3.6, | |
| distance: 110, | |
| speed: 0.75, | |
| rotationSpeed: 0.015, | |
| color: 0xa0d0e0, | |
| description: "An ice giant that rotates on its side, possibly due to an ancient collision. Uranus has a blue-green color due to methane in its atmosphere.", | |
| distanceFromSun: 2867.0, | |
| orbitalPeriod: 30687 | |
| }, | |
| { | |
| name: "Neptune", | |
| radius: 3.5, | |
| distance: 130, | |
| speed: 0.6, | |
| rotationSpeed: 0.018, | |
| color: 0x4f79da, | |
| description: "The windiest planet with speeds up to 2,100 km/h. Neptune was the first planet discovered through mathematical predictions.", | |
| distanceFromSun: 4515.0, | |
| orbitalPeriod: 60190 | |
| } | |
| ]; | |
| // Initialize Three.js | |
| const scene = new THREE.Scene(); | |
| const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 3000); | |
| const renderer = new THREE.WebGLRenderer({ antialias: true }); | |
| renderer.setSize(window.innerWidth, window.innerHeight); | |
| renderer.setPixelRatio(window.devicePixelRatio); | |
| document.getElementById('canvas-container').appendChild(renderer.domElement); | |
| // Add orbit controls | |
| const controls = new THREE.OrbitControls(camera, renderer.domElement); | |
| controls.enableDamping = true; | |
| controls.dampingFactor = 0.05; | |
| // Create stars background | |
| const starsGeometry = new THREE.BufferGeometry(); | |
| const starsMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 1 }); | |
| const starsVertices = []; | |
| for (let i = 0; i < 10000; i++) { | |
| const x = (Math.random() - 0.5) * 2000; | |
| const y = (Math.random() - 0.5) * 2000; | |
| const z = (Math.random() - 0.5) * 2000; | |
| starsVertices.push(x, y, z); | |
| } | |
| starsGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starsVertices, 3)); | |
| const starField = new THREE.Points(starsGeometry, starsMaterial); | |
| scene.add(starField); | |
| // Create the Sun | |
| const sunGeometry = new THREE.SphereGeometry(10, 64, 64); | |
| const sunMaterial = new THREE.MeshBasicMaterial({ | |
| color: 0xffff00, | |
| emissive: 0xffff33, | |
| emissiveIntensity: 1 | |
| }); | |
| const sun = new THREE.Mesh(sunGeometry, sunMaterial); | |
| scene.add(sun); | |
| // Add sun glow effect | |
| const sunGlowGeometry = new THREE.SphereGeometry(12, 32, 32); | |
| const sunGlowMaterial = new THREE.MeshBasicMaterial({ | |
| color: 0xffff00, | |
| transparent: true, | |
| opacity: 0.3 | |
| }); | |
| const sunGlow = new THREE.Mesh(sunGlowGeometry, sunGlowMaterial); | |
| scene.add(sunGlow); | |
| // Create planets | |
| const planets = []; | |
| const orbits = []; | |
| planetData.forEach((planet, index) => { | |
| // Create planet | |
| const geometry = new THREE.SphereGeometry(planet.radius, 32, 32); | |
| const material = new THREE.MeshLambertMaterial({ color: planet.color }); | |
| const mesh = new THREE.Mesh(geometry, material); | |
| // Position planet | |
| const distance = planet.distance; // Scale down for visualization | |
| mesh.position.x = distance; | |
| // Create orbit path | |
| const orbitGeometry = new THREE.BufferGeometry(); | |
| const orbitPoints = []; | |
| const orbitSegments = 128; | |
| for (let i = 0; i <= orbitSegments; i++) { | |
| const theta = (i / orbitSegments) * Math.PI * 2; | |
| orbitPoints.push( | |
| Math.cos(theta) * distance, | |
| 0, | |
| Math.sin(theta) * distance | |
| ); | |
| } | |
| orbitGeometry.setAttribute('position', new THREE.Float32BufferAttribute(orbitPoints, 3)); | |
| const orbitMaterial = new THREE.LineBasicMaterial({ | |
| color: 0xffffff, | |
| transparent: true, | |
| opacity: 0.6 | |
| }); | |
| const orbit = new THREE.Line(orbitGeometry, orbitMaterial); | |
| scene.add(orbit); | |
| orbits.push(orbit); | |
| // Add to scene | |
| scene.add(mesh); | |
| // Store planet data | |
| planets.push({ | |
| mesh: mesh, | |
| data: planet, | |
| angle: Math.random() * Math.PI * 2, | |
| distance: distance, | |
| speed: planet.speed * 0.05, | |
| rotationSpeed: planet.rotationSpeed | |
| }); | |
| // Add rings to Saturn | |
| if (planet.name === "Saturn") { | |
| const ringGeometry = new THREE.RingGeometry(planet.radius * 1.5, planet.radius * 2.5, 64); | |
| const ringMaterial = new THREE.MeshBasicMaterial({ | |
| color: 0xf0e0a0, | |
| side: THREE.DoubleSide, | |
| transparent: true, | |
| opacity: 0.8 | |
| }); | |
| const ring = new THREE.Mesh(ringGeometry, ringMaterial); | |
| ring.rotation.x = Math.PI / 3; | |
| mesh.add(ring); | |
| } | |
| }); | |
| // Add ambient light | |
| const ambientLight = new THREE.AmbientLight(0x333333); | |
| scene.add(ambientLight); | |
| // Add directional light (sunlight) | |
| const sunLight = new THREE.PointLight(0xffffff, 1.5, 3000); | |
| sunLight.position.set(0, 0, 0); | |
| scene.add(sunLight); | |
| // Position camera | |
| camera.position.set(0, 100, 300); | |
| controls.update(); | |
| // UI Controls | |
| let isPlaying = true; | |
| let speed = 1; | |
| const playPauseBtn = document.getElementById('playPauseBtn'); | |
| const speedSlider = document.getElementById('speedSlider'); | |
| const infoPanel = document.getElementById('infoPanel'); | |
| const closeBtn = document.querySelector('.close-btn'); | |
| playPauseBtn.addEventListener('click', () => { | |
| isPlaying = !isPlaying; | |
| playPauseBtn.textContent = isPlaying ? 'βΈοΈ' : 'βΆοΈ'; | |
| }); | |
| speedSlider.addEventListener('input', (e) => { | |
| speed = parseFloat(e.target.value); | |
| }); | |
| closeBtn.addEventListener('click', () => { | |
| infoPanel.classList.remove('visible'); | |
| }); | |
| // Raycaster for planet selection | |
| const raycaster = new THREE.Raycaster(); | |
| const mouse = new THREE.Vector2(); | |
| function onMouseClick(event) { | |
| // Calculate mouse position in normalized device coordinates | |
| mouse.x = (event.clientX / window.innerWidth) * 2 - 1; | |
| mouse.y = - (event.clientY / window.innerHeight) * 2 + 1; | |
| // Update the picking ray with the camera and mouse position | |
| raycaster.setFromCamera(mouse, camera); | |
| // Calculate objects intersecting the picking ray | |
| const intersects = raycaster.intersectObjects(planets.map(p => p.mesh)); | |
| if (intersects.length > 0) { | |
| const planetMesh = intersects[0].object; | |
| const planet = planets.find(p => p.mesh === planetMesh); | |
| if (planet) { | |
| showPlanetInfo(planet.data); | |
| } | |
| } | |
| } | |
| function showPlanetInfo(planet) { | |
| document.getElementById('planetName').textContent = planet.name; | |
| document.getElementById('distance').textContent = `${planet.distanceFromSun} million km`; | |
| document.getElementById('period').textContent = `${planet.orbitalPeriod} Earth days`; | |
| document.getElementById('description').textContent = planet.description; | |
| // Set planet icon color | |
| const icon = document.getElementById('planetIcon'); | |
| icon.style.backgroundColor = `#${planet.color.toString(16).padStart(6, '0')}`; | |
| infoPanel.classList.add('visible'); | |
| } | |
| window.addEventListener('click', onMouseClick); | |
| // Handle window resize | |
| window.addEventListener('resize', () => { | |
| camera.aspect = window.innerWidth / window.innerHeight; | |
| camera.updateProjectionMatrix(); | |
| renderer.setSize(window.innerWidth, window.innerHeight); | |
| }); | |
| // Animation loop | |
| function animate() { | |
| requestAnimationFrame(animate); | |
| if (isPlaying) { | |
| // Rotate sun | |
| sun.rotation.y += 0.002 * speed; | |
| sunGlow.rotation.y += 0.002 * speed; | |
| // Update planets | |
| planets.forEach(planet => { | |
| // Orbit around sun | |
| planet.angle += planet.speed * speed; | |
| planet.mesh.position.x = Math.cos(planet.angle) * planet.distance; | |
| planet.mesh.position.z = Math.sin(planet.angle) * planet.distance; | |
| // Rotate on axis | |
| planet.mesh.rotation.y += planet.rotationSpeed * speed; | |
| }); | |
| } | |
| controls.update(); | |
| renderer.render(scene, camera); | |
| } | |
| animate(); | |
| </script> | |
| </body> | |
| </html> |