diff --git a/assets/css/custom.css b/assets/css/custom.css index 5961183..5073798 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -3,6 +3,21 @@ body { overflow: hidden; background-color: #000; } + +#date-container { + position: absolute; + top: 20px; + left: 50%; + transform: translateX(-50%); + color: white; + background-color: rgba(0, 0, 0, 0.5); + padding: 10px 20px; + border-radius: 5px; + font-family: sans-serif; + font-size: 1.2em; + z-index: 10; +} + canvas { display: block; } @@ -42,40 +57,78 @@ canvas { border-color: #007bff; } -#controls-container { +#time-controls { position: absolute; bottom: 20px; - left: 50%; - transform: translateX(-50%); - background-color: rgba(0, 0, 0, 0.5); + left: 20px; + background-color: rgba(0,0,0,0.5); padding: 10px; border-radius: 5px; z-index: 10; + color: white; + font-family: sans-serif; } -#controls-container button { +#time-controls button { background-color: #333; color: white; border: 1px solid #555; - padding: 10px 20px; + padding: 5px 10px; cursor: pointer; border-radius: 3px; + margin: 0 5px; } -#controls-container button:hover { +#time-controls button:hover { background-color: #555; } -#time-container { +#time-controls span { + margin-left: 10px; + font-size: 0.9em; + vertical-align: middle; +} + +.planet-label { + position: absolute; + color: white; + font-family: sans-serif; + font-size: 12px; + text-shadow: 1px 1px 2px black; + pointer-events: none; /* So they don't interfere with mouse controls */ + z-index: 11; +} + +#controls-top-left { position: absolute; top: 20px; - left: 50%; - transform: translateX(-50%); + right: 20px; + display: flex; + flex-direction: column; + gap: 10px; + z-index: 10; +} + +#scale-container, #focus-container { color: white; background-color: rgba(0, 0, 0, 0.5); - padding: 10px 20px; + padding: 10px; border-radius: 5px; - font-family: monospace; - font-size: 1.2em; - z-index: 10; + font-family: sans-serif; +} + +#scale-container label { + margin-right: 5px; +} + +#focus-container label { + margin-right: 5px; +} + +#focus-container select { + background-color: #333; + color: white; + border: 1px solid #555; + border-radius: 3px; + padding: 5px; } \ No newline at end of file diff --git a/assets/js/main.js b/assets/js/main.js index e5eb124..fb7210c 100644 --- a/assets/js/main.js +++ b/assets/js/main.js @@ -1,383 +1,328 @@ import * as THREE from 'three'; import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; -// Scene +// --- SCENE, CAMERA, RENDERER, CONTROLS --- const scene = new THREE.Scene(); - -// Camera -const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); +const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 50000); camera.position.set(0, 25, 45); camera.lookAt(scene.position); -// Renderer -const renderer = new THREE.WebGLRenderer(); +const renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); -// Controls const controls = new OrbitControls(camera, renderer.domElement); -controls.enableDamping = true; // an animation loop is required when either damping or auto-rotation are enabled +controls.enableDamping = true; controls.dampingFactor = 0.05; controls.screenSpacePanning = false; -controls.minDistance = 10; -controls.maxDistance = 500; +controls.minDistance = 1; +controls.maxDistance = 20000; -// Lighting -const pointLight = new THREE.PointLight(0xffffff, 5, 3000); // Increased intensity and distance +// --- LIGHTING --- +const pointLight = new THREE.PointLight(0xffffff, 5, 60000); scene.add(pointLight); -const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); // Increased ambient light +const ambientLight = new THREE.AmbientLight(0xffffff, 0.6); scene.add(ambientLight); - -// Texture Loader +// --- TEXTURES & ASSETS --- const textureLoader = new THREE.TextureLoader(); -// Stars +// --- STARS BACKGROUND --- 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; +for (let i = 0; i < 15000; i++) { + const x = (Math.random() - 0.5) * 25000; + const y = (Math.random() - 0.5) * 25000; + const z = (Math.random() - 0.5) * 25000; starVertices.push(x, y, z); } - const starGeometry = new THREE.BufferGeometry(); starGeometry.setAttribute('position', new THREE.Float32BufferAttribute(starVertices, 3)); - -const starMaterial = new THREE.PointsMaterial({ - color: 0xffffff, - size: 0.7 -}); - +const starMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 1.5 }); const stars = new THREE.Points(starGeometry, starMaterial); scene.add(stars); -// --- Sun --- +// --- SCALE CONSTANTS --- +const SCALES = { + artistic: { + sunSize: 5, + planetScale: 1, + orbitScale: 1, + moonOrbitScale: 1, + }, + realistic: { + sunSize: 0.5, + planetScale: 0.01, + orbitScale: 100, + moonOrbitScale: 0.1, + } +}; +let currentScale = 'artistic'; + +// --- CELESTIAL BODY DATA & CREATION --- +const celestialBodies = []; + +// --- SUN --- const sunTexture = textureLoader.load('assets/textures/sun.jpg'); const sunMaterial = new THREE.MeshBasicMaterial({ map: sunTexture }); -const sun = new THREE.Mesh(new THREE.SphereGeometry(5, 32, 32), sunMaterial); +const sun = new THREE.Mesh(new THREE.SphereGeometry(1, 32, 32), sunMaterial); +sun.name = 'Sun'; scene.add(sun); +celestialBodies.push({ name: 'Sun', object: sun, data: { radius: 696340 } }); // Real radius in km -// --- Planets & Orbits --- -const segments = 128; -const orbitMaterial = new THREE.LineBasicMaterial({ color: 0xffffff, opacity: 0.5, transparent: true }); - -function createPlanet(radius, textureFile, distance, orbitalPeriodDays) { +function createPlanet(name, textureFile, data) { const texture = textureLoader.load(`assets/textures/${textureFile}?v=${Date.now()}`); - const geometry = new THREE.SphereGeometry(radius, 32, 32); - const material = new THREE.MeshBasicMaterial({ map: texture }); // Reverted + const geometry = new THREE.SphereGeometry(data.radius, 32, 32); + const material = new THREE.MeshBasicMaterial({ map: texture }); const planet = new THREE.Mesh(geometry, material); - + planet.name = name; + const pivot = new THREE.Object3D(); sun.add(pivot); pivot.add(planet); - planet.position.x = distance; - // Trail setup - const trailPoints = []; - const trailGeometry = new THREE.BufferGeometry(); - const trailMaterial = new THREE.LineBasicMaterial({ color: 0xffffff, opacity: 0.5, transparent: true }); - const trail = new THREE.Line(trailGeometry, trailMaterial); - scene.add(trail); - - return { planet, pivot, orbitalPeriodDays, trail, trailPoints }; + const planetObj = { + name, + object: planet, + pivot, + data, + }; + celestialBodies.push(planetObj); + return planetObj; } -const mercuryData = createPlanet(0.4, 'mercury.jpg', 7, 88); -const venusData = createPlanet(0.9, 'venus.jpg', 11, 225); -const earthData = createPlanet(1, 'earth.jpg', 15, 365); -const marsData = createPlanet(0.7, 'mars.jpg', 20, 687); -const jupiterData = createPlanet(3, 'jupiter.jpg', 30, 4333); -const saturnData = createPlanet(2.5, 'saturn.jpg', 40, 10759); -const uranusData = createPlanet(2, 'uranus.jpg', 50, 30687); -const neptuneData = createPlanet(1.9, 'neptune.jpg', 60, 60190); +function createMoon(name, color, data, parentPlanetObject) { + const geometry = new THREE.SphereGeometry(data.radius, 32, 32); + const material = new THREE.MeshBasicMaterial({ color }); + const moon = new THREE.Mesh(geometry, material); + moon.name = name; -// --- Saturn's Rings --- -const ringGeometry = new THREE.RingGeometry(3.5, 5, 64); -const ringMaterial = new THREE.MeshBasicMaterial({ - color: 0xffffff, - side: THREE.DoubleSide, - transparent: true, - opacity: 0.6 -}); -const ring = new THREE.Mesh(ringGeometry, ringMaterial); -ring.rotation.x = -Math.PI / 2.5; // Tilt the rings -saturnData.planet.add(ring); + const pivot = new THREE.Object3D(); + parentPlanetObject.add(pivot); + pivot.add(moon); -// --- Moon --- -const moonGeometry = new THREE.SphereGeometry(0.25, 32, 32); -const moonMaterial = new THREE.MeshBasicMaterial({ color: 0x888888 }); -const moon = new THREE.Mesh(moonGeometry, moonMaterial); - -const moonPivot = new THREE.Object3D(); -earthData.planet.add(moonPivot); -moonPivot.add(moon); -moon.position.x = 2; - -// --- Asteroid Belt --- -const asteroidCount = 1500; -const asteroidGeometry = new THREE.SphereGeometry(0.05, 8, 8); // A small sphere for asteroids -const asteroidMaterial = new THREE.MeshStandardMaterial({ color: 0x999999, roughness: 0.9 }); -const asteroidMesh = new THREE.InstancedMesh(asteroidGeometry, asteroidMaterial, asteroidCount); - -const beltMinRadius = 23; -const beltMaxRadius = 28; -const beltHeight = 1.5; // Vertical thickness - -const dummy = new THREE.Object3D(); -const asteroidData = []; - -for (let i = 0; i < asteroidCount; i++) { - const radius = Math.random() * (beltMaxRadius - beltMinRadius) + beltMinRadius; - const angle = Math.random() * Math.PI * 2; - const y = (Math.random() - 0.5) * beltHeight; - const orbitSpeed = (Math.random() * 0.002 + 0.0005); // Slower than Mars, faster than Jupiter - const rotationSpeed = Math.random() * 0.05; - - asteroidData.push({ radius, angle, y, orbitSpeed, rotationSpeed }); - - dummy.position.set( - Math.cos(angle) * radius, - y, - Math.sin(angle) * radius - ); - dummy.updateMatrix(); - asteroidMesh.setMatrixAt(i, dummy.matrix); + const moonObj = { + name, + object: moon, + pivot, + data, + parent: parentPlanetObject + }; + celestialBodies.push(moonObj); + return moonObj; } -scene.add(asteroidMesh); +function createRings(innerRadius, outerRadius, color, opacity, tilt) { + const ringGeometry = new THREE.RingGeometry(innerRadius, outerRadius, 64); + const ringMaterial = new THREE.MeshBasicMaterial({ + color: color, + side: THREE.DoubleSide, + transparent: true, + opacity: opacity + }); + const ring = new THREE.Mesh(ringGeometry, ringMaterial); + ring.rotation.x = tilt; + return ring; +} - -const planets = [mercuryData, venusData, earthData, marsData, jupiterData, saturnData, uranusData, neptuneData]; - -// Planet Data -const planetData = { - [earthData.planet.uuid]: { - name: 'Earth', - mass: '5.97 × 10^24 kg', - radius: '6,371 km', - orbital_speed: '29.78 km/s', - }, - [mercuryData.planet.uuid]: { - name: 'Mercury', - mass: '3.285 × 10^23 kg', - radius: '2,439.7 km', - orbital_speed: '47.36 km/s', - }, - [venusData.planet.uuid]: { - name: 'Venus', - mass: '4.867 × 10^24 kg', - radius: '6,051.8 km', - orbital_speed: '35.02 km/s', - }, - [marsData.planet.uuid]: { - name: 'Mars', - mass: '6.39 × 10^23 kg', - radius: '3,389.5 km', - orbital_speed: '24.07 km/s', - }, - [jupiterData.planet.uuid]: { - name: 'Jupiter', - mass: '1.898 × 10^27 kg', - radius: '69,911 km', - orbital_speed: '13.07 km/s', - }, - [saturnData.planet.uuid]: { - name: 'Saturn', - mass: '5.683 × 10^26 kg', - radius: '58,232 km', - orbital_speed: '9.69 km/s', - }, - [uranusData.planet.uuid]: { - name: 'Uranus', - mass: '8.681 × 10^25 kg', - radius: '25,362 km', - orbital_speed: '6.81 km/s', - }, - [neptuneData.planet.uuid]: { - name: 'Neptune', - mass: '1.024 × 10^26 kg', - radius: '24,622 km', - orbital_speed: '5.43 km/s', - } +const celestialData = { + mercury: { radius: 0.4, distance: 7, period: 88 }, + venus: { radius: 0.9, distance: 11, period: 225 }, + earth: { radius: 1, distance: 15, period: 365 }, + mars: { radius: 0.7, distance: 20, period: 687 }, + jupiter: { radius: 3, distance: 30, period: 4333 }, + saturn: { radius: 2.5, distance: 40, period: 10759 }, + uranus: { radius: 2, distance: 50, period: 30687 }, + neptune: { radius: 1.9, distance: 60, period: 60190 }, + moon: { radius: 0.25, distance: 2, period: 27.3 }, + io: { radius: 0.2, distance: 3.5, period: 1.769 }, + europa: { radius: 0.2, distance: 4.0, period: 3.551 }, + ganymede: { radius: 0.3, distance: 4.5, period: 7.155 }, + callisto: { radius: 0.3, distance: 5.0, period: 16.689 }, + titan: { radius: 0.4, distance: 6.0, period: 15.95 }, + triton: { radius: 0.35, distance: 4.0, period: 5.88 }, }; -// --- Selection Outline --- -let outlineMesh; -const outlineMaterial = new THREE.MeshBasicMaterial({ color: 0xffff00, side: THREE.BackSide }); -const outlineScale = 1.15; +// --- INSTANTIATE BODIES --- +const mercury = createPlanet('Mercury', 'mercury.jpg', celestialData.mercury); +const venus = createPlanet('Venus', 'venus.jpg', celestialData.venus); +const earth = createPlanet('Earth', 'earth.jpg', celestialData.earth); +const mars = createPlanet('Mars', 'mars.jpg', celestialData.mars); +const jupiter = createPlanet('Jupiter', 'jupiter.jpg', celestialData.jupiter); +const saturn = createPlanet('Saturn', 'saturn.jpg', celestialData.saturn); +const uranus = createPlanet('Uranus', 'uranus.jpg', celestialData.uranus); +const neptune = createPlanet('Neptune', 'neptune.jpg', celestialData.neptune); -function setOutline(object) { - if (outlineMesh && outlineMesh.parent) { - outlineMesh.parent.remove(outlineMesh); - } +createMoon('Moon', 0x888888, celestialData.moon, earth.object); +createMoon('Io', 0xffff00, celestialData.io, jupiter.object); +createMoon('Europa', 0xffa500, celestialData.europa, jupiter.object); +createMoon('Ganymede', 0x00ff00, celestialData.ganymede, jupiter.object); +createMoon('Callisto', 0x0000ff, celestialData.callisto, jupiter.object); +createMoon('Titan', 0xFFAC1C, celestialData.titan, saturn.object); +createMoon('Triton', 0xADD8E6, celestialData.triton, neptune.object); - outlineMesh = new THREE.Mesh(object.geometry, outlineMaterial); - outlineMesh.scale.set(outlineScale, outlineScale, outlineScale); - object.add(outlineMesh); +// --- RINGS --- +saturn.object.add(createRings(3.5, 5, 0xffffff, 0.6, -Math.PI / 2.5)); +jupiter.object.add(createRings(3.5, 4.5, 0x8c7853, 0.4, -Math.PI / 2)); +uranus.object.add(createRings(2.5, 3.5, 0xadd8e6, 0.3, -Math.PI / 2)); +neptune.object.add(createRings(2.4, 3, 0xadd8e6, 0.2, -Math.PI / 2.5)); + +// --- UI & CONTROLS --- +const scaleToggle = document.getElementById('scale-toggle'); +const focusSelect = document.getElementById('focus-select'); +const dateDisplay = document.getElementById('date-container'); +const slowDownButton = document.getElementById('slow-down'); +const pauseToggleButton = document.getElementById('pause-toggle'); +const speedUpButton = document.getElementById('speed-up'); +const speedDisplay = document.getElementById('speed-display'); + +// Populate Focus Dropdown +celestialBodies.forEach(body => { + const option = document.createElement('option'); + option.value = body.name; + option.textContent = body.name; + focusSelect.appendChild(option); +}); + +function focusOnObject(name) { + const body = celestialBodies.find(b => b.name === name); + if (!body) return; + + const target = new THREE.Vector3(); + body.object.getWorldPosition(target); + controls.target.copy(target); + + const size = body.object.geometry.parameters.radius * body.object.scale.x; + const offset = size * 5; + + const cameraPosition = new THREE.Vector3(target.x + offset, target.y + offset / 2, target.z + offset); + camera.position.copy(cameraPosition); + controls.update(); } +focusSelect.addEventListener('change', (event) => { + focusOnObject(event.target.value); +}); -// Stats Panel -const statsInfo = document.getElementById('stats-info'); -const statsButtons = document.getElementById('stats-buttons'); +scaleToggle.addEventListener('change', (event) => { + const scale = event.target.checked ? 'realistic' : 'artistic'; + updateScale(scale); +}); -function updateStats(planetUUID) { - const data = planetData[planetUUID]; - if (data) { - statsInfo.innerHTML = ` -

${data.name}

-

Mass: ${data.mass}

-

Radius: ${data.radius}

-

Orbital Speed: ${data.orbital_speed}

- `; - } +// --- TIME CONTROLS --- +let simulationSpeed = 1; // Represents days per second +let isPaused = false; +let currentDate = new Date(); + +function updateSpeedDisplay() { + speedDisplay.textContent = `Speed: ${simulationSpeed}x`; } -statsButtons.addEventListener('click', (event) => { - if (event.target.tagName === 'BUTTON') { - const planetName = event.target.dataset.planet; - let planetObject, planetUUID; +pauseToggleButton.addEventListener('click', () => { + isPaused = !isPaused; + pauseToggleButton.textContent = isPaused ? 'Resume' : 'Pause'; +}); - statsButtons.querySelectorAll('button').forEach(btn => btn.classList.remove('active')); - event.target.classList.add('active'); +slowDownButton.addEventListener('click', () => { + simulationSpeed /= 2; + updateSpeedDisplay(); +}); - if (planetName === 'earth') { - planetObject = earthData.planet; - planetUUID = earthData.planet.uuid; - } else if (planetName === 'mercury') { - planetObject = mercuryData.planet; - planetUUID = mercuryData.planet.uuid; - } else if (planetName === 'venus') { - planetObject = venusData.planet; - planetUUID = venusData.planet.uuid; - } else if (planetName === 'mars') { - planetObject = marsData.planet; - planetUUID = marsData.planet.uuid; - } else if (planetName === 'jupiter') { - planetObject = jupiterData.planet; - planetUUID = jupiterData.planet.uuid; - } else if (planetName === 'saturn') { - planetObject = saturnData.planet; - planetUUID = saturnData.planet.uuid; - } else if (planetName === 'uranus') { - planetObject = uranusData.planet; - planetUUID = uranusData.planet.uuid; - } else if (planetName === 'neptune') { - planetObject = neptuneData.planet; - planetUUID = neptuneData.planet.uuid; - } +speedUpButton.addEventListener('click', () => { + simulationSpeed *= 2; + updateSpeedDisplay(); +}); - if (planetUUID) { - updateStats(planetUUID); - if (planetObject) { - setOutline(planetObject); + +// --- SCALE UPDATE LOGIC --- +function updateScale(scaleType) { + currentScale = scaleType; + const scaleConfig = SCALES[scaleType]; + + sun.scale.setScalar(scaleConfig.sunSize); + + celestialBodies.forEach(body => { + if (body.name === 'Sun') return; + + const { object, pivot, data } = body; + object.scale.setScalar(scaleConfig.planetScale); + + if (pivot) { + if (body.parent) { + object.position.x = data.distance * scaleConfig.moonOrbitScale; + } else { + object.position.x = data.distance * scaleConfig.orbitScale; } } + }); + + if (scaleType === 'realistic') { + controls.maxDistance = 400000; + controls.minDistance = 0.01; + } else { + controls.maxDistance = 1000; + controls.minDistance = 1; } -}); - -// Display Earth's stats by default and set button to active -updateStats(earthData.planet.uuid); -statsButtons.querySelector('button[data-planet="earth"]').classList.add('active'); -setOutline(earthData.planet); // Initial outline for Earth - - -// --- Controls Logic --- -let isPaused = false; -const pauseButton = document.getElementById('pause-button'); -const speedToggleButton = document.getElementById('speed-toggle-button'); - -pauseButton.addEventListener('click', () => { - isPaused = !isPaused; - pauseButton.textContent = isPaused ? 'Play' : 'Pause'; -}); - -const speeds = [1, 100, 500, 1000, 10000]; -let currentSpeedIndex = 0; -let timeScale = speeds[currentSpeedIndex]; // Start with 1x speed - -speedToggleButton.addEventListener('click', () => { - currentSpeedIndex = (currentSpeedIndex + 1) % speeds.length; - timeScale = speeds[currentSpeedIndex]; - speedToggleButton.textContent = 'Speed: ' + timeScale + 'x'; -}); - - -// --- Time & Simulation --- -const clock = new THREE.Clock(); -const timeContainer = document.getElementById('time-container'); -let simulationTime = new Date(); -const TIME_SPEED_FACTOR = 60; // 1 real second = 1 simulation minute at 1x -const MS_IN_A_DAY = 24 * 60 * 60 * 1000; -const MOON_ORBIT_DAYS = 27.3; - - -function updateTimeDisplay() { - const hours = String(simulationTime.getHours()).padStart(2, '0'); - const minutes = String(simulationTime.getMinutes()).padStart(2, '0'); - const seconds = String(simulationTime.getSeconds()).padStart(2, '0'); - const day = String(simulationTime.getDate()).padStart(2, '0'); - const month = String(simulationTime.getMonth() + 1).padStart(2, '0'); // Month is 0-indexed - const year = simulationTime.getFullYear(); - timeContainer.textContent = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; + focusOnObject(focusSelect.value); } -// Animation loop +// Initial setup +updateScale('artistic'); +updateSpeedDisplay(); + +// --- LABELS --- +const labels = celestialBodies.map(body => ({ + object: body.object, + element: document.getElementById(`label-${body.name.toLowerCase()}`), +})).filter(label => label.element); + +// --- ANIMATION LOOP --- +const clock = new THREE.Clock(); +let simulationTime = 0; +const ORBIT_SPEED_FACTOR = 0.1; // Slows down overall orbit speed + function animate() { requestAnimationFrame(animate); - - // Get time delta for frame-rate independent animation - let delta = clock.getDelta(); - // Clamp the delta to a maximum value to prevent large jumps, e.g., on the first frame or after tab refocus. - delta = Math.min(delta, 0.1); - - // Update controls - controls.update(); + const deltaTime = clock.getDelta(); if (!isPaused) { - // Advance simulation time using milliseconds for precision - const incrementMs = delta * 1000 * timeScale * TIME_SPEED_FACTOR; - simulationTime.setTime(simulationTime.getTime() + incrementMs); - - // Sun's self-rotation (can be slower and independent of timeScale) - sun.rotation.y += 0.005 * delta; - - const maxTrailPoints = 200; - const worldPosition = new THREE.Vector3(); - - planets.forEach(p => { - const orbitalPeriodMs = p.orbitalPeriodDays * MS_IN_A_DAY; - const angleIncrement = (incrementMs / orbitalPeriodMs) * (2 * Math.PI); - p.pivot.rotation.y += angleIncrement; - - // Planet's self-rotation (can also be constant) - p.planet.rotation.y += 0.05 * delta; - - // Update trail - p.planet.getWorldPosition(worldPosition); - p.trailPoints.push(worldPosition.clone()); - - if (p.trailPoints.length > maxTrailPoints) { - p.trailPoints.shift(); - } - - p.trail.geometry.setFromPoints(p.trailPoints); - }); - - // Moon's orbit (also scaled by timeScale) - const moonOrbitalPeriodMs = MOON_ORBIT_DAYS * MS_IN_A_DAY; - const moonAngleIncrement = (incrementMs / moonOrbitalPeriodMs) * (2 * Math.PI); - moonPivot.rotation.y += moonAngleIncrement; + const timePassed = deltaTime * simulationSpeed; + simulationTime += timePassed; + // Advance current date by days + currentDate.setDate(currentDate.getDate() + timePassed); } + + // Update Date Display + dateDisplay.textContent = currentDate.toDateString(); - // Update time display every frame - updateTimeDisplay(); + sun.rotation.y += 0.0005 * simulationSpeed * deltaTime; + celestialBodies.forEach(body => { + if (!body.pivot || !body.data.period) return; + + const angle = (simulationTime * ORBIT_SPEED_FACTOR) / body.data.period * (2 * Math.PI); + body.pivot.rotation.y = angle; + + body.object.rotation.y += 0.05 * deltaTime * simulationSpeed; + }); + + // Update labels + labels.forEach(labelData => { + const { object, element } = labelData; + if (!element) return; + const vector = new THREE.Vector3(); + object.getWorldPosition(vector); + vector.project(camera); + + const x = (vector.x * 0.5 + 0.5) * window.innerWidth; + const y = (vector.y * -0.5 + 0.5) * window.innerHeight; + + element.style.transform = `translate(-50%, -50%) translate(${x}px, ${y}px)`; + }); + + controls.update(); renderer.render(scene, camera); } - animate(); // Handle window resize @@ -386,6 +331,3 @@ window.addEventListener('resize', () => { camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); - -// Initial call to set time -updateTimeDisplay(); diff --git a/index.php b/index.php index d1ecee0..a94a96e 100644 --- a/index.php +++ b/index.php @@ -7,7 +7,27 @@ -
+
+
+
+ + +
+
+ + +
+
+ +
+ + + + Speed: 1x +
+
@@ -21,10 +41,7 @@
-
- - -
+ +
Sun
+
Mercury
+
Venus
+
Earth
+
Mars
+
Jupiter
+
Saturn
+
Uranus
+
Neptune
+
Io
+
Europa
+
Ganymede
+
Callisto
+
Titan
+
Triton
\ No newline at end of file