| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>3D Earth Simulation</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <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> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| body { |
| overflow: hidden; |
| background: linear-gradient(135deg, #1a2a6c, #2c3e50); |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
| } |
| #earth-container { |
| width: 100vw; |
| height: 100vh; |
| } |
| .control-panel { |
| position: absolute; |
| top: 20px; |
| left: 20px; |
| background: rgba(0, 0, 0, 0.7); |
| border-radius: 15px; |
| padding: 20px; |
| color: white; |
| max-width: 300px; |
| backdrop-filter: blur(10px); |
| border: 1px solid rgba(255, 255, 255, 0.1); |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); |
| } |
| .control-group { |
| margin-bottom: 15px; |
| } |
| .control-label { |
| display: block; |
| margin-bottom: 5px; |
| font-weight: 500; |
| } |
| .btn { |
| background: linear-gradient(to right, #3498db, #2980b9); |
| border: none; |
| padding: 10px 15px; |
| border-radius: 8px; |
| color: white; |
| cursor: pointer; |
| transition: all 0.3s ease; |
| font-weight: 600; |
| display: flex; |
| align-items: center; |
| justify-content: center; |
| width: 100%; |
| margin-top: 5px; |
| } |
| .btn:hover { |
| transform: translateY(-2px); |
| box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); |
| } |
| .btn i { |
| margin-right: 8px; |
| } |
| .info-card { |
| position: absolute; |
| bottom: 20px; |
| left: 20px; |
| background: rgba(0, 0, 0, 0.7); |
| border-radius: 15px; |
| padding: 20px; |
| color: white; |
| max-width: 300px; |
| backdrop-filter: blur(10px); |
| border: 1px solid rgba(255, 255, 255, 0.1); |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); |
| } |
| .loading { |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| background: rgba(0, 0, 0, 0.9); |
| display: flex; |
| flex-direction: column; |
| justify-content: center; |
| align-items: center; |
| color: white; |
| z-index: 100; |
| transition: opacity 0.5s; |
| } |
| .spinner { |
| width: 50px; |
| height: 50px; |
| border: 5px solid rgba(255, 255, 255, 0.3); |
| border-radius: 50%; |
| border-top-color: #3498db; |
| animation: spin 1s ease-in-out infinite; |
| margin-bottom: 20px; |
| } |
| @keyframes spin { |
| to { transform: rotate(360deg); } |
| } |
| .instructions { |
| position: absolute; |
| bottom: 20px; |
| right: 20px; |
| background: rgba(0, 0, 0, 0.7); |
| border-radius: 15px; |
| padding: 20px; |
| color: white; |
| max-width: 300px; |
| backdrop-filter: blur(10px); |
| border: 1px solid rgba(255, 255, 255, 0.1); |
| box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3); |
| } |
| .instructions ul { |
| padding-left: 20px; |
| margin-top: 10px; |
| } |
| .instructions li { |
| margin-bottom: 8px; |
| } |
| .highlight { |
| color: #3498db; |
| font-weight: 600; |
| } |
| .title { |
| font-size: 1.8rem; |
| font-weight: 700; |
| margin-bottom: 5px; |
| background: linear-gradient(to right, #3498db, #2ecc71); |
| -webkit-background-clip: text; |
| -webkit-text-fill-color: transparent; |
| } |
| .subtitle { |
| font-size: 1rem; |
| color: #bbb; |
| margin-bottom: 20px; |
| } |
| .clouds { |
| position: absolute; |
| top: 0; |
| left: 0; |
| width: 100%; |
| height: 100%; |
| pointer-events: none; |
| opacity: 0.3; |
| } |
| .cloud { |
| position: absolute; |
| background: rgba(255, 255, 255, 0.8); |
| border-radius: 50%; |
| filter: blur(20px); |
| } |
| </style> |
| </head> |
| <body> |
| <div id="earth-container"></div> |
| |
| <div class="loading" id="loading"> |
| <div class="spinner"></div> |
| <h2>Loading Earth Simulation</h2> |
| <p>Please wait while we render the planet...</p> |
| </div> |
| |
| <div class="control-panel"> |
| <h2 class="title">Earth Controls</h2> |
| <p class="subtitle">Navigate around our beautiful planet</p> |
| |
| <div class="control-group"> |
| <label class="control-label">Rotation Speed</label> |
| <input type="range" id="rotation-speed" min="0" max="2" step="0.1" value="0.5" class="w-full"> |
| </div> |
| |
| <div class="control-group"> |
| <label class="control-label">Cloud Opacity</label> |
| <input type="range" id="cloud-opacity" min="0" max="1" step="0.1" value="0.5" class="w-full"> |
| </div> |
| |
| <div class="control-group"> |
| <label class="control-label">Satellite Speed</label> |
| <input type="range" id="satellite-speed" min="0" max="2" step="0.1" value="1" class="w-full"> |
| </div> |
| |
| <div class="control-group"> |
| <label class="control-label">Orbit Diameter</label> |
| <input type="range" id="orbit-diameter" min="1" max="3" step="0.1" value="1.8" class="w-full"> |
| </div> |
| |
| <div class="control-group"> |
| <label class="control-label">Satellite Rotation</label> |
| <input type="range" id="satellite-rotation" min="0" max="2" step="0.1" value="1" class="w-full"> |
| </div> |
| |
| <button id="reset-view" class="btn"><i class="fas fa-sync-alt"></i> Reset View</button> |
| <button id="toggle-rotation" class="btn"><i class="fas fa-play"></i> Pause Rotation</button> |
| </div> |
| |
| <div class="info-card"> |
| <h3 class="title">Planet Earth</h3> |
| <p>Our home planet is the only place we know of so far that's inhabited by living things.</p> |
| <div class="mt-3"> |
| <p><span class="highlight">Diameter:</span> 12,742 km</p> |
| <p><span class="highlight">Age:</span> 4.54 billion years</p> |
| <p><span class="highlight">Population:</span> 7.9 billion</p> |
| </div> |
| </div> |
| |
| <div class="instructions"> |
| <h3 class="title">Navigation Guide</h3> |
| <ul> |
| <li><span class="highlight">Left Click + Drag</span> to rotate</li> |
| <li><span class="highlight">Scroll Wheel</span> to zoom in/out</li> |
| <li><span class="highlight">Right Click + Drag</span> to pan</li> |
| <li>Use controls to adjust parameters</li> |
| </ul> |
| </div> |
| |
| <div class="clouds" id="clouds"></div> |
|
|
| <script> |
| |
| function createClouds() { |
| const cloudsContainer = document.getElementById('clouds'); |
| for (let i = 0; i < 15; i++) { |
| const cloud = document.createElement('div'); |
| cloud.classList.add('cloud'); |
| |
| |
| const size = Math.random() * 200 + 50; |
| const posX = Math.random() * 100; |
| const posY = Math.random() * 100; |
| |
| cloud.style.width = `${size}px`; |
| cloud.style.height = `${size * 0.6}px`; |
| cloud.style.left = `${posX}%`; |
| cloud.style.top = `${posY}%`; |
| |
| |
| const duration = Math.random() * 30 + 20; |
| cloud.style.animation = `float ${duration}s linear infinite`; |
| |
| cloudsContainer.appendChild(cloud); |
| } |
| } |
| |
| |
| const style = document.createElement('style'); |
| style.innerHTML = ` |
| @keyframes float { |
| 0% { transform: translateX(-100px); } |
| 100% { transform: translateX(calc(100vw + 100px)); } |
| } |
| `; |
| document.head.appendChild(style); |
| |
| |
| function initEarth() { |
| |
| const scene = new THREE.Scene(); |
| scene.background = new THREE.Color(0x000814); |
| |
| |
| const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000); |
| camera.position.z = 3; |
| |
| |
| const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); |
| renderer.setSize(window.innerWidth, window.innerHeight); |
| renderer.setPixelRatio(window.devicePixelRatio); |
| document.getElementById('earth-container').appendChild(renderer.domElement); |
| |
| |
| const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); |
| scene.add(ambientLight); |
| |
| |
| const directionalLight = new THREE.DirectionalLight(0xffffff, 1); |
| directionalLight.position.set(5, 3, 5); |
| scene.add(directionalLight); |
| |
| |
| const earthGeometry = new THREE.SphereGeometry(1, 64, 64); |
| |
| |
| const textureLoader = new THREE.TextureLoader(); |
| const earthTexture = textureLoader.load('https://threejs.org/examples/textures/planets/earth_atmos_2048.jpg'); |
| const earthBumpMap = textureLoader.load('https://threejs.org/examples/textures/planets/earth_normal_2048.jpg'); |
| const earthSpecularMap = textureLoader.load('https://threejs.org/examples/textures/planets/earth_specular_2048.jpg'); |
| |
| const earthMaterial = new THREE.MeshPhongMaterial({ |
| map: earthTexture, |
| bumpMap: earthBumpMap, |
| bumpScale: 0.05, |
| specularMap: earthSpecularMap, |
| specular: new THREE.Color(0x333333), |
| shininess: 5 |
| }); |
| |
| const earth = new THREE.Mesh(earthGeometry, earthMaterial); |
| scene.add(earth); |
| |
| |
| const cloudsGeometry = new THREE.SphereGeometry(1.01, 64, 64); |
| const cloudsTexture = textureLoader.load('https://threejs.org/examples/textures/planets/earth_clouds_1024.png'); |
| const cloudsMaterial = new THREE.MeshPhongMaterial({ |
| map: cloudsTexture, |
| transparent: true, |
| opacity: 0.5 |
| }); |
| |
| const clouds = new THREE.Mesh(cloudsGeometry, cloudsMaterial); |
| scene.add(clouds); |
| |
| |
| const starGeometry = new THREE.BufferGeometry(); |
| const starMaterial = new THREE.PointsMaterial({ |
| color: 0xffffff, |
| size: 0.02, |
| }); |
| |
| const starVertices = []; |
| 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; |
| starVertices.push(x, y, z); |
| } |
| |
| starGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starVertices, 3)); |
| const stars = new THREE.Points(starGeometry, starMaterial); |
| scene.add(stars); |
| |
| |
| const satelliteGroup = new THREE.Group(); |
| scene.add(satelliteGroup); |
| |
| |
| const satelliteGeometry = new THREE.SphereGeometry(0.05, 16, 16); |
| const satelliteMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00 }); |
| const satellite = new THREE.Mesh(satelliteGeometry, satelliteMaterial); |
| |
| |
| let satelliteOrbitRadius = 1.8; |
| const satelliteOrbit = new THREE.EllipseCurve( |
| 0, 0, |
| satelliteOrbitRadius, satelliteOrbitRadius, |
| 0, 2 * Math.PI, |
| false, |
| 0 |
| ); |
| |
| const satellitePathPoints = satelliteOrbit.getPoints(100); |
| const satellitePathGeometry = new THREE.BufferGeometry().setFromPoints(satellitePathPoints); |
| const satellitePathMaterial = new THREE.LineBasicMaterial({ |
| color: 0x00ffff, |
| transparent: true, |
| opacity: 0.3 |
| }); |
| |
| const satellitePath = new THREE.Line(satellitePathGeometry, satellitePathMaterial); |
| satellitePath.rotation.x = Math.PI / 2; |
| scene.add(satellitePath); |
| |
| |
| satellite.position.set(satelliteOrbitRadius, 0, 0); |
| satelliteGroup.add(satellite); |
| |
| |
| const controls = new THREE.OrbitControls(camera, renderer.domElement); |
| controls.enableDamping = true; |
| controls.dampingFactor = 0.05; |
| controls.rotateSpeed = 0.5; |
| |
| |
| window.addEventListener('resize', () => { |
| camera.aspect = window.innerWidth / window.innerHeight; |
| camera.updateProjectionMatrix(); |
| renderer.setSize(window.innerWidth, window.innerHeight); |
| }); |
| |
| |
| const rotationSpeedSlider = document.getElementById('rotation-speed'); |
| const cloudOpacitySlider = document.getElementById('cloud-opacity'); |
| const satelliteSpeedSlider = document.getElementById('satellite-speed'); |
| const orbitDiameterSlider = document.getElementById('orbit-diameter'); |
| const satelliteRotationSlider = document.getElementById('satellite-rotation'); |
| const resetViewBtn = document.getElementById('reset-view'); |
| const toggleRotationBtn = document.getElementById('toggle-rotation'); |
| const loadingScreen = document.getElementById('loading'); |
| |
| |
| let autoRotate = true; |
| let rotationSpeed = 0.5; |
| let satelliteSpeed = 1; |
| let satelliteRotationSpeed = 1; |
| |
| |
| rotationSpeedSlider.addEventListener('input', (e) => { |
| rotationSpeed = parseFloat(e.target.value); |
| }); |
| |
| cloudOpacitySlider.addEventListener('input', (e) => { |
| cloudsMaterial.opacity = parseFloat(e.target.value); |
| }); |
| |
| satelliteSpeedSlider.addEventListener('input', (e) => { |
| satelliteSpeed = parseFloat(e.target.value); |
| }); |
| |
| orbitDiameterSlider.addEventListener('input', (e) => { |
| satelliteOrbitRadius = parseFloat(e.target.value); |
| |
| const newOrbit = new THREE.EllipseCurve( |
| 0, 0, |
| satelliteOrbitRadius, satelliteOrbitRadius, |
| 0, 2 * Math.PI, |
| false, |
| 0 |
| ); |
| const newPathPoints = newOrbit.getPoints(100); |
| satellitePath.geometry.setFromPoints(newPathPoints); |
| }); |
| |
| satelliteRotationSlider.addEventListener('input', (e) => { |
| satelliteRotationSpeed = parseFloat(e.target.value); |
| }); |
| |
| resetViewBtn.addEventListener('click', () => { |
| controls.reset(); |
| camera.position.z = 3; |
| }); |
| |
| toggleRotationBtn.addEventListener('click', () => { |
| autoRotate = !autoRotate; |
| toggleRotationBtn.innerHTML = autoRotate ? |
| '<i class="fas fa-pause"></i> Pause Rotation' : |
| '<i class="fas fa-play"></i> Resume Rotation'; |
| }); |
| |
| |
| setTimeout(() => { |
| loadingScreen.style.opacity = '0'; |
| setTimeout(() => { |
| loadingScreen.style.display = 'none'; |
| }, 500); |
| }, 2000); |
| |
| |
| function animate() { |
| requestAnimationFrame(animate); |
| |
| if (autoRotate) { |
| earth.rotation.y += 0.001 * rotationSpeed; |
| clouds.rotation.y += 0.001 * rotationSpeed * 1.1; |
| } |
| |
| |
| const baseSatelliteSpeed = 0.005; |
| const time = Date.now() * baseSatelliteSpeed * satelliteSpeed; |
| satelliteGroup.position.x = satelliteOrbitRadius * Math.cos(time); |
| satelliteGroup.position.z = satelliteOrbitRadius * Math.sin(time); |
| |
| |
| satellite.rotation.y += 0.01 * satelliteRotationSpeed; |
| |
| controls.update(); |
| renderer.render(scene, camera); |
| } |
| |
| animate(); |
| } |
| |
| |
| window.addEventListener('load', () => { |
| createClouds(); |
| initEarth(); |
| }); |
| </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=Jebari/earth" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |