luxury-snake / index.html
engerl's picture
Add 1 files
b92c118 verified
<!DOCTYPE html>
<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>