Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Interactive 3D Solar System</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<script src="https://kit.fontawesome.com/a076d05399.js" crossorigin="anonymous"></script> | |
<style> | |
body { | |
overflow: hidden; | |
background: radial-gradient(ellipse at bottom, #1B2735 0%, #090A0F 100%); | |
height: 100vh; | |
margin: 0; | |
font-family: 'Arial', sans-serif; | |
cursor: grab; | |
user-select: none; | |
} | |
body.grabbing { | |
cursor: grabbing; | |
} | |
#stars { | |
position: absolute; | |
width: 300%; | |
height: 300%; | |
z-index: 0; | |
transform-origin: center; | |
} | |
.star { | |
position: absolute; | |
background-color: white; | |
border-radius: 50%; | |
animation: twinkle var(--duration) infinite ease-in-out; | |
} | |
@keyframes twinkle { | |
0%, 100% { opacity: 0.2; } | |
50% { opacity: 1; } | |
} | |
.orbit { | |
position: absolute; | |
border: 1px dashed rgba(255, 255, 255, 0.1); | |
border-radius: 50%; | |
transform-origin: center; | |
} | |
.planet { | |
position: absolute; | |
border-radius: 50%; | |
transform-origin: center; | |
cursor: pointer; | |
transition: transform 0.3s, box-shadow 0.3s; | |
z-index: 5; | |
} | |
.planet:hover { | |
transform: scale(1.5); | |
box-shadow: 0 0 15px currentColor; | |
z-index: 10; | |
} | |
.planet-info { | |
position: absolute; | |
background: rgba(0, 0, 0, 0.8); | |
border: 1px solid #444; | |
border-radius: 8px; | |
padding: 15px; | |
color: white; | |
max-width: 250px; | |
display: none; | |
z-index: 100; | |
backdrop-filter: blur(5px); | |
pointer-events: none; | |
} | |
.sun { | |
position: absolute; | |
border-radius: 50%; | |
background: radial-gradient(circle at center, #ffde00, #ff8c00, #ff3d00); | |
box-shadow: 0 0 60px #ff8c00, 0 0 98px #ff4500; | |
z-index: 2; | |
} | |
.controls { | |
position: fixed; | |
bottom: 20px; | |
left: 50%; | |
transform: translateX(-50%); | |
background: rgba(0, 0, 0, 0.7); | |
padding: 15px; | |
border-radius: 10px; | |
display: flex; | |
gap: 15px; | |
align-items: center; | |
z-index: 100; | |
backdrop-filter: blur(5px); | |
} | |
.speed-display { | |
color: white; | |
min-width: 80px; | |
text-align: center; | |
} | |
.title { | |
position: fixed; | |
top: 20px; | |
left: 50%; | |
transform: translateX(-50%); | |
color: white; | |
font-size: 2.5rem; | |
text-align: center; | |
z-index: 100; | |
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5); | |
background: rgba(0, 0, 0, 0.5); | |
padding: 10px 20px; | |
border-radius: 10px; | |
pointer-events: none; | |
} | |
.ring { | |
position: absolute; | |
border-radius: 50%; | |
opacity: 0.7; | |
transform-origin: center; | |
pointer-events: none; | |
} | |
.solar-system-container { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
transform-origin: center; | |
transition: transform 0.1s ease-out; | |
} | |
.tooltip { | |
position: absolute; | |
background: rgba(0, 0, 0, 0.7); | |
color: white; | |
padding: 5px 10px; | |
border-radius: 5px; | |
font-size: 12px; | |
pointer-events: none; | |
opacity: 0; | |
transition: opacity 0.3s; | |
z-index: 20; | |
} | |
.asteroid { | |
position: absolute; | |
background-color: #888; | |
border-radius: 50%; | |
pointer-events: none; | |
} | |
.comet { | |
position: absolute; | |
width: 10px; | |
height: 3px; | |
background: linear-gradient(to right, rgba(200,200,255,1), transparent); | |
transform-origin: center; | |
pointer-events: none; | |
} | |
.drag-indicator { | |
position: fixed; | |
bottom: 20px; | |
left: 20px; | |
background: rgba(0, 0, 0, 0.7); | |
color: white; | |
padding: 10px; | |
border-radius: 8px; | |
z-index: 100; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="solar-system-container" id="solarSystem"> | |
<div id="stars"></div> | |
<div class="sun" id="sun"></div> | |
</div> | |
<div class="title">Interactive 3D Solar System</div> | |
<div id="positionIndicator" class="fixed bottom-20 right-4 bg-black bg-opacity-50 text-white p-2 rounded-md z-50"> | |
X: 0 | Y: 0 | Zoom: 1x | |
</div> | |
<div class="drag-indicator"> | |
<i class="fas fa-arrows-alt"></i> Hold left mouse button to drag view | |
</div> | |
<div class="controls"> | |
<button id="slowDown" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition-colors"> | |
<i class="fas fa-minus"></i> Slower | |
</button> | |
<div class="speed-display" id="speedDisplay">1x</div> | |
<button id="speedUp" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition-colors"> | |
<i class="fas fa-plus"></i> Faster | |
</button> | |
<button id="pauseBtn" class="bg-red-600 hover:bg-red-700 text-white font-bold py-2 px-4 rounded transition-colors"> | |
<i class="fas fa-pause"></i> Pause | |
</button> | |
<button id="resetBtn" class="bg-gray-600 hover:bg-gray-700 text-white font-bold py-2 px-4 rounded transition-colors"> | |
<i class="fas fa-sync-alt"></i> Reset | |
</button> | |
<button id="zoomIn" class="bg-purple-600 hover:bg-purple-700 text-white font-bold py-2 px-4 rounded transition-colors"> | |
<i class="fas fa-search-plus"></i> | |
</button> | |
<button id="zoomOut" class="bg-purple-600 hover:bg-purple-700 text-white font-bold py-2 px-4 rounded transition-colors"> | |
<i class="fas fa-search-minus"></i> | |
</button> | |
</div> | |
<div id="tooltip" class="tooltip"></div> | |
<script> | |
// Configuration | |
const config = { | |
scale: 0.5, // Initial scale factor for distances | |
speed: 1, // Initial speed multiplier | |
paused: false, | |
zoom: 1, | |
offsetX: 0, | |
offsetY: 0, | |
isDragging: false, | |
lastX: 0, | |
lastY: 0 | |
}; | |
// Planet data (relative sizes and distances) | |
const planets = [ | |
{ name: "Mercury", color: "#B8B8B8", size: 4, distance: 58, orbitTime: 88, info: "The smallest planet in our solar system and closest to the Sun." }, | |
{ name: "Venus", color: "#E6C229", size: 9.5, distance: 108, orbitTime: 225, info: "Similar in size to Earth but with a toxic atmosphere of carbon dioxide." }, | |
{ name: "Earth", color: "#6B93D6", size: 10, distance: 150, orbitTime: 365, hasMoon: true, info: "Our home planet, the only known place in the universe confirmed to host life." }, | |
{ name: "Mars", color: "#C1440E", size: 5.3, distance: 228, orbitTime: 687, info: "Known as the Red Planet due to iron oxide on its surface." }, | |
{ name: "Jupiter", color: "#D39C7E", size: 112, distance: 778, orbitTime: 4333, info: "The largest planet in our solar system, a gas giant with a Great Red Spot." }, | |
{ name: "Saturn", color: "#E4D191", size: 94, distance: 1427, orbitTime: 10759, hasRings: true, info: "Famous for its beautiful ring system made of ice and rock." }, | |
{ name: "Uranus", color: "#D1E7E7", size: 40, distance: 2871, orbitTime: 30687, info: "An ice giant that rotates on its side, with a blue-green color." }, | |
{ name: "Neptune", color: "#5B5DDF", size: 38, distance: 4498, orbitTime: 60190, info: "The windiest planet with the strongest winds in the solar system." }, | |
{ name: "Pluto", color: "#D1B7A3", size: 1.8, distance: 5906, orbitTime: 90560, info: "A dwarf planet in the Kuiper belt, smaller than Earth's moon." } | |
]; | |
// Create stars | |
function createStars() { | |
const starsContainer = document.getElementById('stars'); | |
const starCount = 1000; | |
for (let i = 0; i < starCount; i++) { | |
const star = document.createElement('div'); | |
star.className = 'star'; | |
// Random position | |
const x = Math.random() * 300; | |
const y = Math.random() * 300; | |
// Random size (0.5px to 2px) | |
const size = Math.random() * 1.5 + 0.5; | |
// Random twinkle duration (3s to 10s) | |
const duration = Math.random() * 7 + 3; | |
star.style.left = `${x - 50}%`; | |
star.style.top = `${y - 50}%`; | |
star.style.width = `${size}px`; | |
star.style.height = `${size}px`; | |
star.style.setProperty('--duration', `${duration}s`); | |
starsContainer.appendChild(star); | |
} | |
} | |
// Create asteroid belt | |
function createAsteroidBelt() { | |
const container = document.getElementById('solarSystem'); | |
const centerX = window.innerWidth / 2; | |
const centerY = window.innerHeight / 2; | |
const asteroidCount = 100; | |
for (let i = 0; i < asteroidCount; i++) { | |
const asteroid = document.createElement('div'); | |
asteroid.className = 'asteroid'; | |
// Random position in asteroid belt area (between Mars and Jupiter) | |
const distance = Math.random() * 230 + 350; | |
const angle = Math.random() * Math.PI * 2; | |
const x = centerX + Math.cos(angle) * distance * config.scale; | |
const y = centerY + Math.sin(angle) * distance * config.scale; | |
// Random size (0.5px to 3px) | |
const size = Math.random() * 2.5 + 0.5; | |
asteroid.style.left = `${x}px`; | |
asteroid.style.top = `${y}px`; | |
asteroid.style.width = `${size}px`; | |
asteroid.style.height = `${size}px`; | |
container.appendChild(asteroid); | |
} | |
// Create a comet | |
const comet = document.createElement('div'); | |
comet.className = 'comet'; | |
comet.id = 'comet'; | |
comet.style.left = `${centerX - 500}px`; | |
comet.style.top = `${centerY - 300}px`; | |
container.appendChild(comet); | |
} | |
// Create solar system | |
function createSolarSystem() { | |
const container = document.getElementById('solarSystem'); | |
const centerX = window.innerWidth / 2; | |
const centerY = window.innerHeight / 2; | |
// Create Sun | |
const sun = document.getElementById('sun'); | |
sun.style.width = '50px'; | |
sun.style.height = '50px'; | |
sun.style.left = `${centerX - 25}px`; | |
sun.style.top = `${centerY - 25}px`; | |
// Create planets and orbits | |
planets.forEach((planet, index) => { | |
// Create orbit path | |
const orbit = document.createElement('div'); | |
orbit.className = 'orbit'; | |
const orbitRadius = planet.distance * config.scale; | |
orbit.style.width = `${orbitRadius * 2}px`; | |
orbit.style.height = `${orbitRadius * 2}px`; | |
orbit.style.left = `${centerX - orbitRadius}px`; | |
orbit.style.top = `${centerY - orbitRadius}px`; | |
container.appendChild(orbit); | |
// Create planet | |
const planetElement = document.createElement('div'); | |
planetElement.className = 'planet'; | |
planetElement.id = `planet-${index}`; | |
planetElement.style.backgroundColor = planet.color; | |
planetElement.style.boxShadow = `0 0 10px ${planet.color}`; | |
planetElement.style.color = planet.color; // For glow effect | |
const planetSize = planet.size * 0.5; | |
planetElement.style.width = `${planetSize}px`; | |
planetElement.style.height = `${planetSize}px`; | |
// Initial position | |
const angle = Math.random() * Math.PI * 2; | |
const x = centerX + Math.cos(angle) * orbitRadius - planetSize / 2; | |
const y = centerY + Math.sin(angle) * orbitRadius - planetSize / 2; | |
planetElement.style.left = `${x}px`; | |
planetElement.style.top = `${y}px`; | |
container.appendChild(planetElement); | |
// Create moon for Earth | |
if (planet.hasMoon) { | |
const moon = document.createElement('div'); | |
moon.className = 'planet'; | |
moon.style.backgroundColor = '#ddd'; | |
moon.style.width = '3px'; | |
moon.style.height = '3px'; | |
moon.style.left = `${x + planetSize/2 + 8}px`; | |
moon.style.top = `${y + planetSize/2 - 3}px`; | |
container.appendChild(moon); | |
planet.moon = moon; | |
} | |
// Create rings for Saturn | |
if (planet.hasRings) { | |
const ring = document.createElement('div'); | |
ring.className = 'ring'; | |
ring.style.border = `15px solid #C0C0C0`; | |
ring.style.width = `${planetSize * 2.5}px`; | |
ring.style.height = `${planetSize * 0.5}px`; | |
ring.style.left = `${x - planetSize * 0.75}px`; | |
ring.style.top = `${y + planetSize * 0.25}px`; | |
container.appendChild(ring); | |
planet.ringElement = ring; | |
} | |
// Create info panel | |
const infoPanel = document.createElement('div'); | |
infoPanel.className = 'planet-info'; | |
infoPanel.id = `info-${index}`; | |
infoPanel.innerHTML = ` | |
<h3 class="font-bold text-lg mb-2">${planet.name}</h3> | |
<p class="text-sm mb-1">Distance from Sun: ${planet.distance} million km</p> | |
<p class="text-sm mb-1">Orbit Period: ${planet.orbitTime} Earth days</p> | |
<p class="text-sm">${planet.info}</p> | |
`; | |
container.appendChild(infoPanel); | |
// Add hover event for tooltip | |
planetElement.addEventListener('mousemove', (e) => { | |
const tooltip = document.getElementById('tooltip'); | |
tooltip.textContent = planet.name; | |
tooltip.style.left = `${e.pageX + 15}px`; | |
tooltip.style.top = `${e.pageY + 15}px`; | |
tooltip.style.opacity = '1'; | |
}); | |
planetElement.addEventListener('mouseleave', () => { | |
document.getElementById('tooltip').style.opacity = '0'; | |
}); | |
// Add click event to show info | |
planetElement.addEventListener('click', (e) => { | |
e.stopPropagation(); | |
hideAllInfoPanels(); | |
infoPanel.style.display = 'block'; | |
// Position the info panel | |
const rect = planetElement.getBoundingClientRect(); | |
infoPanel.style.left = `${rect.right + 10}px`; | |
infoPanel.style.top = `${rect.top}px`; | |
// Adjust if it goes off screen | |
if (parseInt(infoPanel.style.left) + infoPanel.offsetWidth > window.innerWidth) { | |
infoPanel.style.left = `${rect.left - infoPanel.offsetWidth - 10}px`; | |
} | |
}); | |
// Store planet data for animation | |
planet.element = planetElement; | |
planet.angle = angle; | |
planet.orbitRadius = orbitRadius; | |
}); | |
// Hide info panels when clicking anywhere else | |
document.addEventListener('click', hideAllInfoPanels); | |
} | |
function hideAllInfoPanels() { | |
document.querySelectorAll('.planet-info').forEach(panel => { | |
panel.style.display = 'none'; | |
}); | |
} | |
// Animate planets | |
function animatePlanets() { | |
if (config.paused) { | |
requestAnimationFrame(animatePlanets); | |
return; | |
} | |
const container = document.getElementById('solarSystem'); | |
const centerX = window.innerWidth / 2; | |
const centerY = window.innerHeight / 2; | |
planets.forEach((planet) => { | |
// Update angle based on orbit time and speed | |
planet.angle += (0.01 / planet.orbitTime) * config.speed; | |
// Calculate new position (accounting for offset and zoom) | |
const effectiveOrbitRadius = planet.orbitRadius * config.zoom; | |
const x = centerX + config.offsetX + Math.cos(planet.angle) * effectiveOrbitRadius - planet.element.offsetWidth / 2; | |
const y = centerY + config.offsetY + Math.sin(planet.angle) * effectiveOrbitRadius - planet.element.offsetHeight / 2; | |
// Update planet position | |
planet.element.style.left = `${x}px`; | |
planet.element.style.top = `${y}px`; | |
// Update moon position for Earth | |
if (planet.hasMoon) { | |
planet.moon.style.left = `${x + planet.size * 0.5 / 2 + 8}px`; | |
planet.moon.style.top = `${y + planet.size * 0.5 / 2 - 3}px`; | |
} | |
// Update ring position for Saturn | |
if (planet.hasRings) { | |
planet.ringElement.style.left = `${x - planet.size * 0.75 * 0.5}px`; | |
planet.ringElement.style.top = `${y + planet.size * 0.25 * 0.5}px`; | |
planet.ringElement.style.transform = `rotate(${planet.angle * 2}rad)`; | |
} | |
}); | |
// Animate comet | |
const comet = document.getElementById('comet'); | |
if (comet) { | |
const cometAngle = performance.now() * 0.0001; | |
const cometDistance = 1000; | |
const cometX = centerX + config.offsetX + Math.cos(cometAngle) * cometDistance * config.scale; | |
const cometY = centerY + config.offsetY + Math.sin(cometAngle * 1.5) * cometDistance * config.scale; | |
comet.style.left = `${cometX}px`; | |
comet.style.top = `${cometY}px`; | |
comet.style.transform = `rotate(${cometAngle}rad)`; | |
} | |
// Update solar system container transform | |
container.style.transform = `translate(${config.offsetX}px, ${config.offsetY}px) scale(${config.zoom})`; | |
requestAnimationFrame(animatePlanets); | |
} | |
// Handle mouse drag for panning | |
function setupDragControls() { | |
const container = document.body; | |
container.addEventListener('mousedown', (e) => { | |
// Only respond to left mouse button | |
if (e.button !== 0) return; | |
if (e.target.closest('button') || e.target.closest('.planet-info')) return; | |
config.isDragging = true; | |
config.lastX = e.clientX; | |
config.lastY = e.clientY; | |
container.classList.add('grabbing'); | |
e.preventDefault(); | |
}); | |
container.addEventListener('mousemove', (e) => { | |
if (!config.isDragging) return; | |
const dx = e.clientX - config.lastX; | |
const dy = e.clientY - config.lastY; | |
config.offsetX += dx; | |
config.offsetY += dy; | |
config.lastX = e.clientX; | |
config.lastY = e.clientY; | |
updatePositionIndicator(); | |
e.preventDefault(); | |
}); | |
container.addEventListener('mouseup', (e) => { | |
if (e.button !== 0) return; | |
config.isDragging = false; | |
container.classList.remove('grabbing'); | |
e.preventDefault(); | |
}); | |
container.addEventListener('mouseleave', () => { | |
config.isDragging = false; | |
container.classList.remove('grabbing'); | |
}); | |
// Touch support | |
container.addEventListener('touchstart', (e) => { | |
if (e.target.closest('button') || e.target.closest('.planet-info')) return; | |
config.isDragging = true; | |
config.lastX = e.touches[0].clientX; | |
config.lastY = e.touches[0].clientY; | |
e.preventDefault(); | |
}); | |
container.addEventListener('touchmove', (e) => { | |
if (!config.isDragging) return; | |
const dx = e.touches[0].clientX - config.lastX; | |
const dy = e.touches[0].clientY - config.lastY; | |
config.offsetX += dx; | |
config.offsetY += dy; | |
config.lastX = e.touches[0].clientX; | |
config.lastY = e.touches[0].clientY; | |
updatePositionIndicator(); | |
e.preventDefault(); | |
}); | |
container.addEventListener('touchend', () => { | |
config.isDragging = false; | |
}); | |
} | |
function updatePositionIndicator() { | |
const indicator = document.getElementById('positionIndicator'); | |
indicator.textContent = `X: ${Math.round(config.offsetX)} | Y: ${Math.round(config.offsetY)} | Zoom: ${config.zoom.toFixed(1)}x`; | |
} | |
// Handle window resize | |
function handleResize() { | |
const centerX = window.innerWidth / 2; | |
const centerY = window.innerHeight / 2; | |
// Update Sun position | |
const sun = document.getElementById('sun'); | |
sun.style.left = `${centerX - 25}px`; | |
sun.style.top = `${centerY - 25}px`; | |
} | |
// Initialize | |
window.addEventListener('load', () => { | |
createStars(); | |
createSolarSystem(); | |
createAsteroidBelt(); | |
setupDragControls(); | |
animatePlanets(); | |
updatePositionIndicator(); | |
// Set up controls | |
document.getElementById('speedUp').addEventListener('click', () => { | |
config.speed *= 1.5; | |
updateControls(); | |
}); | |
document.getElementById('slowDown').addEventListener('click', () => { | |
config.speed /= 1.5; | |
if (config.speed < 0.01) config.speed = 0.01; | |
updateControls(); | |
}); | |
document.getElementById('pauseBtn').addEventListener('click', () => { | |
config.paused = !config.paused; | |
updateControls(); | |
if (!config.paused) animatePlanets(); | |
}); | |
document.getElementById('resetBtn').addEventListener('click', () => { | |
config.speed = 1; | |
config.paused = false; | |
config.zoom = 1; | |
config.offsetX = 0; | |
config.offsetY = 0; | |
updateControls(); | |
// Reset planet positions to random angles | |
planets.forEach(planet => { | |
planet.angle = Math.random() * Math.PI * 2; | |
}); | |
animatePlanets(); | |
}); | |
document.getElementById('zoomIn').addEventListener('click', () => { | |
config.zoom *= 1.2; | |
if (config.zoom > 5) config.zoom = 5; | |
updatePositionIndicator(); | |
}); | |
document.getElementById('zoomOut').addEventListener('click', () => { | |
config.zoom /= 1.2; | |
if (config.zoom < 0.5) config.zoom = 0.5; | |
updatePositionIndicator(); | |
}); | |
// Mouse wheel zoom | |
document.addEventListener('wheel', (e) => { | |
e.preventDefault(); | |
const delta = e.deltaY < 0 ? 1.2 : 1/1.2; | |
// Zoom toward mouse position | |
const mouseX = e.clientX; | |
const mouseY = e.clientY; | |
const newZoom = config.zoom * delta; | |
if (newZoom > 5) return; | |
if (newZoom < 0.5) return; | |
// Calculate the offset needed to zoom toward mouse position | |
const containerX = window.innerWidth / 2; | |
const containerY = window.innerHeight / 2; | |
const offsetX = mouseX - containerX; | |
const offsetY = mouseY - containerY; | |
config.offsetX = offsetX + (config.offsetX - offsetX) * delta; | |
config.offsetY = offsetY + (config.offsetY - offsetY) * delta; | |
config.zoom = newZoom; | |
updatePositionIndicator(); | |
}, { passive: false }); | |
window.addEventListener('resize', handleResize); | |
}); | |
function updateControls() { | |
document.getElementById('speedDisplay').textContent = | |
config.speed.toFixed(2) + 'x'; | |
const btn = document.getElementById('pauseBtn'); | |
if (config.paused) { | |
btn.innerHTML = '<i class="fas fa-play"></i> Play'; | |
btn.classList.remove('bg-red-600'); | |
btn.classList.add('bg-green-600'); | |
} else { | |
btn.innerHTML = '<i class="fas fa-pause"></i> Pause'; | |
btn.classList.remove('bg-green-600'); | |
btn.classList.add('bg-red-600'); | |
} | |
} | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=engerl/luxury-snake" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body> | |
</html> |