// Celestial Cycles Symphony - Main JavaScript class CelestialSystem { constructor() { this.isPlaying = true; this.timeScale = 10; this.currentTime = 6 * 60; // 6:00 AM in minutes this.dayDuration = 24 * 60; // 24 hours in minutes this.initializeElements(); this.startSimulation(); this.setupEventListeners(); } initializeElements() { this.sun = document.getElementById('sun'); this.moon = document.getElementById('moon'); this.stars = document.getElementById('stars'); this.currentTimeDisplay = document.getElementById('currentTime'); this.timeScaleInput = document.getElementById('timeScale'); this.timeScaleValue = document.getElementById('timeScaleValue'); this.pauseBtn = document.getElementById('pauseBtn'); this.sunPosition = document.getElementById('sunPosition'); this.moonPosition = document.getElementById('moonPosition'); this.timeProgress = document.getElementById('timeProgress'); } setupEventListeners() { this.timeScaleInput.addEventListener('input', (e) => { this.timeScale = parseInt(e.target.value); this.timeScaleValue.textContent = `${this.timeScale}x`; this.updateSimulationSpeed(); this.updateCelestialInfo(); this.updateBackground(); this.updateAtmosphericEffects(); this.updateLighting(); this.updateTimeDisplay(); this.updateProgress(); this.updateStars(); this.updateHorizon(); this.updateClouds(); this.updateShadows(); this.updateReflections(); this.updateParticles(); this.updateAudio(); this.updateWeather(); this.updateSeasonalEffects(); }); this.pauseBtn.addEventListener('click', () => { this.togglePause(); }); // Keyboard controls document.addEventListener('keydown', (e) => { if (e.code === 'Space') { e.preventDefault(); this.togglePause(); } }); } togglePause() { this.isPlaying = !this.isPlaying; const icon = this.pauseBtn.querySelector('i'); const text = this.pauseBtn.querySelector('span:last-child'); if (this.isPlaying) { icon.setAttribute('data-feather', 'pause'); text.textContent = 'Pause'; this.pauseBtn.classList.remove('bg-red-600'); this.pauseBtn.classList.add('bg-primary-600'); } else { icon.setAttribute('data-feather', 'play'); text.textContent = 'Play'; this.pauseBtn.classList.remove('bg-primary-600'); this.pauseBtn.classList.add('bg-red-600'); } feather.replace(); } startSimulation() { const update = () => { if (this.isPlaying) { this.currentTime += this.timeScale / 60; // Convert to minutes if (this.currentTime >= this.dayDuration) { this.currentTime = 0; } this.updateAll(); } requestAnimationFrame(update); }; update(); } updateAll() { this.updateCelestialPositions(); this.updateBackground(); this.updateAtmosphericEffects(); this.updateLighting(); this.updateTimeDisplay(); this.updateCelestialInfo(); this.updateProgress(); this.updateStars(); this.updateHorizon(); this.updateClouds(); this.updateShadows(); this.updateReflections(); this.updateParticles(); this.updateAudio(); this.updateWeather(); this.updateSeasonalEffects(); } updateCelestialPositions() { const timeRatio = this.currentTime / this.dayDuration; // Sun movement (east to west) const sunX = 10 + (timeRatio * 80); // 10% to 90% of container width const sunY = this.calculateSunElevation(timeRatio); // Moon movement (west to east, opposite of sun) const moonX = 90 - (timeRatio * 80); const moonY = this.calculateMoonElevation(timeRatio); this.sun.style.left = `${sunX}%`; this.sun.style.bottom = `${sunY}%`; this.moon.style.left = `${moonX}%`; this.moon.style.bottom = `${moonY}%`; // Update sun and moon visibility const sunOpacity = this.calculateSunOpacity(timeRatio); const moonOpacity = this.calculateMoonOpacity(timeRatio); this.sun.style.opacity = sunOpacity; this.moon.style.opacity = moonOpacity; } calculateSunElevation(timeRatio) { // Parabolic curve for sun elevation const angle = (timeRatio - 0.5) * Math.PI; return 5 + (Math.cos(angle) * 25); } calculateMoonElevation(timeRatio) { // Similar to sun but offset const angle = ((timeRatio + 0.5) % 1 - 0.5) * Math.PI; return 5 + (Math.cos(angle) * 20); } calculateSunOpacity(timeRatio) { // Sun is visible during daytime if (timeRatio >= 0.25 && timeRatio <= 0.75) { return 1; } // Gradual fade during sunrise/sunset if (timeRatio >= 0.2 && timeRatio < 0.25) { return (timeRatio - 0.2) / 0.05; } if (timeRatio > 0.75 && timeRatio <= 0.8) { return (0.8 - timeRatio) / 0.05; } return 0; } calculateMoonOpacity(timeRatio) { // Moon is visible during nighttime if (timeRatio <= 0.2 || timeRatio >= 0.8) { return 1; } // Gradual fade during moonrise/moonset if (timeRatio > 0.75 && timeRatio < 0.8) { return (timeRatio - 0.75) / 0.05; } if (timeRatio > 0.2 && timeRatio < 0.25) { return (0.25 - timeRatio) / 0.05; } return 0; } updateBackground() { const timeRatio = this.currentTime / this.dayDuration; const container = this.sun.parentElement; // Dynamic sky gradient based on time let gradient; if (timeRatio < 0.25) { // Night to morning gradient = 'from-indigo-900 via-purple-700 to-blue-500'; } else if (timeRatio < 0.35) { // Morning gradient = 'from-blue-500 via-cyan-400 to-blue-300'; } else if (timeRatio < 0.65) { // Day gradient = 'from-blue-400 via-cyan-300 to-blue-200'; } else if (timeRatio < 0.75) { // Evening gradient = 'from-orange-400 via-red-500 to-purple-700'; } else { // Evening to night gradient = 'from-purple-700 via-indigo-800 to-gray-900'; } container.className = container.className.replace(/from-\S+ via-\S+ to-\S+/, gradient); } updateAtmosphericEffects() { const timeRatio = this.currentTime / this.dayDuration; // Update sun glow intensity const sunGlow = this.sun.querySelector('div'); if (timeRatio >= 0.35 && timeRatio <= 0.65) { sunGlow.classList.add('animate-pulse'); } else { sunGlow.classList.remove('animate-pulse'); } } updateLighting() { const timeRatio = this.currentTime / this.dayDuration; // Simulate lighting changes document.documentElement.style.setProperty('--light-intensity', this.calculateLightIntensity(timeRatio)); } calculateLightIntensity(timeRatio) { // Bell curve for light intensity const center = 0.5; const width = 0.25; const distance = Math.abs(timeRatio - center); return Math.max(0, 1 - (distance / width) ** 2); } updateTimeDisplay() { const hours = Math.floor(this.currentTime / 60); const minutes = Math.floor(this.currentTime % 60); const period = hours >= 12 ? 'PM' : 'AM'; const displayHours = hours % 12 || 12; this.currentTimeDisplay.textContent = `${displayHours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')} ${period}`; } updateCelestialInfo() { const timeRatio = this.currentTime / this.dayDuration; // Sun position info const sunElevation = Math.round(this.calculateSunElevation(timeRatio) * 3.6); const sunAzimuth = Math.round(90 + (timeRatio * 180) % 360); this.sunPosition.textContent = `Elevation: ${sunElevation}° | Azimuth: ${sunAzimuth}°`; // Moon position info const moonElevation = Math.round(this.calculateMoonElevation(timeRatio) * 3.6); const moonAzimuth = Math.round(270 - (timeRatio * 180) % 360); this.moonPosition.textContent = `Elevation: ${moonElevation}° | Azimuth: ${moonAzimuth}°`; } updateProgress() { const dayProgress = Math.min(1, Math.max(0, (this.currentTime / this.dayDuration - 0.25) / 0.5); const nightProgress = 1 - dayProgress; this.timeProgress.textContent = `Day: ${Math.round(dayProgress * 100)}% | Night: ${Math.round(nightProgress * 100)}%`; } updateStars() { const timeRatio = this.currentTime / this.dayDuration; const starOpacity = (timeRatio <= 0.2 || timeRatio >= 0.8) ? 1 : 0; this.stars.style.opacity = starOpacity; } updateHorizon() { // Update horizon line color based on time const timeRatio = this.currentTime / this.dayDuration; const horizon = document.querySelector('.absolute.bottom-0'); if (timeRatio < 0.25 || timeRatio > 0.75) { horizon.className = horizon.className.replace(/from-\S+ to-\S+/, 'from-gray-900 to-gray-700'); } else { horizon.className = horizon.className.replace(/from-\S+ to-\S+/, 'from-green-900 to-green-700'); } updateClouds() { // Cloud movement and lighting simulation const timeRatio = this.currentTime / this.dayDuration; document.documentElement.style.setProperty('--cloud-brightness', this.calculateCloudBrightness(timeRatio)); } calculateCloudBrightness(timeRatio) { return Math.max(0.3, Math.min(1, this.calculateLightIntensity(timeRatio) + 0.3)); } updateShadows() { const timeRatio = this.currentTime / this.dayDuration; const shadowLength = 50 + (Math.abs(timeRatio - 0.5) * 100); document.documentElement.style.setProperty('--shadow-length', `${shadowLength}px`); } updateReflections() { // Water reflection intensity const timeRatio = this.currentTime / this.dayDuration; const reflectionIntensity = timeRatio >= 0.35 && timeRatio <= 0.65 ? 0.8 : 0.3; document.documentElement.style.setProperty('--reflection-intensity', reflectionIntensity); } updateParticles() { // Dust particles, fireflies, etc. const timeRatio = this.currentTime / this.dayDuration; const particleDensity = timeRatio < 0.25 || timeRatio > 0.75 ? 0.7 : 0.1); document.documentElement.style.setProperty('--particle-density', particleDensity); } updateAudio() { // Background audio changes const timeRatio = this.currentTime / this.dayDuration; const audioVolume = Math.min(1, Math.max(0.1, this.calculateLightIntensity(timeRatio))); document.documentElement.style.setProperty('--audio-volume', audioVolume); } updateWeather() { // Weather system integration placeholder const timeRatio = this.currentTime / this.dayDuration; document.documentElement.style.setProperty('--weather-intensity', Math.random())); } updateSeasonalEffects() { // Seasonal variations placeholder const timeRatio = this.currentTime / this.dayDuration; document.documentElement.style.setProperty('--season-factor', 1); } updateSimulationSpeed() { // Adjust animation speeds based on time scale document.documentElement.style.setProperty('--animation-speed', `${this.timeScale / 10}s`); } } // Initialize the celestial system when the page loads document.addEventListener('DOMContentLoaded', () => { new CelestialSystem(); // Add fade-in animations to sections const sections = document.querySelectorAll('section'); sections.forEach((section, index) => { section.classList.add('fade-in-up'); section.style.animationDelay = `${index * 0.2}s`; }); }); // Utility function for smooth transitions function smoothTransition(element, property, targetValue, duration = 1000) { element.style.transition = `${property} ${duration}ms cubic-bezier(0.4, 0, 0.2, 1)'; element.style[property] = targetValue; } // Export for potential module usage if (typeof module !== 'undefined' && module.exports) { module.exports = CelestialSystem; }