casmopedia / static /js /preloader.js
aradhyapavan's picture
CospmoPedia
7e3b585 verified
/*
* CREATIVE SPACE STATION DOCKING PRELOADER
* Realistic and immersive space experience
*/
console.log('🚀 Space Station Docking Preloader loaded!');
// Creative Space Station Docking Preloader
class SpaceStationPreloader {
constructor() {
this.loadingProgress = 0;
this.isDestroyed = false;
this.init();
}
init() {
this.createContainer();
this.startLoadingSequence();
}
createContainer() {
// Remove immediate preloader first
const immediatePreloader = document.getElementById('immediatePreloader');
if (immediatePreloader) {
immediatePreloader.remove();
}
// Remove any existing JS preloader
const existing = document.getElementById('spacePreloader');
if (existing) existing.remove();
// Create main container
this.container = document.createElement('div');
this.container.id = 'spacePreloader';
this.container.innerHTML = `
<div class="space-scene">
<div class="stars-field"></div>
<div class="nebula-cloud"></div>
<div class="space-station">
<div class="station-core"></div>
<div class="station-ring ring-1"></div>
<div class="station-ring ring-2"></div>
<div class="station-antenna"></div>
<div class="docking-bay"></div>
</div>
<div class="approaching-ship">
<div class="ship-body"></div>
<div class="ship-engines">
<div class="engine engine-1"></div>
<div class="engine engine-2"></div>
</div>
<div class="engine-trail"></div>
</div>
<div class="ui-overlay">
<div class="hud-frame">
<div class="hud-corner tl"></div>
<div class="hud-corner tr"></div>
<div class="hud-corner bl"></div>
<div class="hud-corner br"></div>
</div>
<div class="mission-info">
<div class="mission-title">COSMOPEDIA</div>
<div class="mission-subtitle">Deep Space Command Center</div>
<div class="docking-status">
<div class="status-label">DOCKING SEQUENCE</div>
<div class="progress-container">
<div class="progress-bar" id="dockingProgress"></div>
<div class="progress-glow"></div>
</div>
<div class="progress-percent" id="dockingPercent">0%</div>
</div>
<div class="system-status" id="systemStatus">Approaching Space Station...</div>
</div>
<div class="radar-display">
<div class="radar-circle">
<div class="radar-sweep"></div>
<div class="radar-blip station-blip"></div>
<div class="radar-blip ship-blip"></div>
</div>
</div>
</div>
</div>
`;
// Add creative space station styles
const style = document.createElement('style');
style.textContent = `
#spacePreloader {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: #000;
z-index: 999999;
overflow: hidden;
font-family: 'Orbitron', 'Space Grotesk', monospace;
}
.space-scene {
position: relative;
width: 100%;
height: 100%;
perspective: 1000px;
}
.stars-field {
position: absolute;
width: 200%;
height: 200%;
top: -50%;
left: -50%;
background-image:
radial-gradient(1px 1px at 20px 30px, #fff, transparent),
radial-gradient(1px 1px at 40px 70px, #fff, transparent),
radial-gradient(1px 1px at 90px 40px, #fff, transparent),
radial-gradient(1px 1px at 130px 80px, #fff, transparent),
radial-gradient(1px 1px at 160px 30px, #fff, transparent);
background-repeat: repeat;
background-size: 200px 100px;
animation: starsMove 60s linear infinite;
opacity: 0.8;
}
.nebula-cloud {
position: absolute;
top: 20%;
right: 10%;
width: 300px;
height: 200px;
background: radial-gradient(ellipse,
rgba(138, 43, 226, 0.3) 0%,
rgba(75, 0, 130, 0.2) 30%,
rgba(0, 191, 255, 0.1) 60%,
transparent 80%);
border-radius: 50%;
filter: blur(2px);
animation: nebulaFloat 20s ease-in-out infinite;
}
.space-station {
position: absolute;
top: 50%;
left: 75%;
transform: translate(-50%, -50%);
width: 200px;
height: 200px;
}
.station-core {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 60px;
height: 60px;
background: linear-gradient(45deg, #333, #666);
border-radius: 8px;
box-shadow:
0 0 20px rgba(0, 150, 255, 0.5),
inset 0 0 10px rgba(0, 100, 200, 0.3);
}
.station-ring {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border: 3px solid rgba(0, 150, 255, 0.7);
border-radius: 50%;
box-shadow: 0 0 15px rgba(0, 150, 255, 0.5);
}
.ring-1 {
width: 120px;
height: 120px;
animation: stationRotate 15s linear infinite;
}
.ring-2 {
width: 160px;
height: 160px;
animation: stationRotate 25s linear infinite reverse;
}
.station-antenna {
position: absolute;
top: 25%;
left: 50%;
transform: translateX(-50%);
width: 2px;
height: 40px;
background: linear-gradient(to top, #444, #0096ff);
box-shadow: 0 0 10px rgba(0, 150, 255, 0.8);
}
.docking-bay {
position: absolute;
bottom: 20%;
left: 50%;
transform: translateX(-50%);
width: 30px;
height: 15px;
background: rgba(0, 255, 0, 0.3);
border: 2px solid rgba(0, 255, 0, 0.8);
box-shadow: 0 0 15px rgba(0, 255, 0, 0.6);
animation: dockingPulse 2s ease-in-out infinite;
}
.approaching-ship {
position: absolute;
top: 65%;
left: 20%;
transform: translate(-50%, -50%);
width: 80px;
height: 40px;
animation: shipApproach 8s ease-in-out infinite;
}
.ship-body {
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 50px;
height: 20px;
background: linear-gradient(45deg, #555, #888);
clip-path: polygon(0% 50%, 20% 0%, 80% 0%, 100% 50%, 80% 100%, 20% 100%);
box-shadow: 0 0 10px rgba(255, 255, 255, 0.3);
}
.ship-engines {
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
}
.engine {
position: absolute;
width: 8px;
height: 8px;
background: radial-gradient(circle, #00ffff, #0080ff);
border-radius: 50%;
box-shadow: 0 0 15px rgba(0, 255, 255, 0.8);
animation: enginePulse 0.5s ease-in-out infinite alternate;
}
.engine-1 { top: -8px; }
.engine-2 { top: 4px; }
.engine-trail {
position: absolute;
top: 50%;
right: -20px;
transform: translateY(-50%);
width: 30px;
height: 4px;
background: linear-gradient(to right, rgba(0, 255, 255, 0.8), transparent);
border-radius: 50px;
animation: trailFlicker 0.3s ease-in-out infinite;
}
.ui-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.hud-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.hud-corner {
position: absolute;
width: 40px;
height: 40px;
border: 2px solid rgba(0, 255, 255, 0.8);
box-shadow: 0 0 10px rgba(0, 255, 255, 0.5);
}
.tl { top: 20px; left: 20px; border-right: none; border-bottom: none; }
.tr { top: 20px; right: 20px; border-left: none; border-bottom: none; }
.bl { bottom: 20px; left: 20px; border-right: none; border-top: none; }
.br { bottom: 20px; right: 20px; border-left: none; border-top: none; }
.mission-info {
position: absolute;
top: 50px;
left: 50%;
transform: translateX(-50%);
text-align: center;
color: #fff;
}
.mission-title {
font-size: 2.5rem;
font-weight: 700;
color: #00ffff;
text-shadow: 0 0 20px rgba(0, 255, 255, 0.8);
margin-bottom: 0.5rem;
letter-spacing: 0.2rem;
animation: titleGlow 3s ease-in-out infinite alternate;
}
.mission-subtitle {
font-size: 1rem;
color: #aaa;
margin-bottom: 2rem;
letter-spacing: 0.1rem;
}
.docking-status {
margin-bottom: 1rem;
}
.status-label {
font-size: 0.9rem;
color: #00ff00;
margin-bottom: 1rem;
text-shadow: 0 0 10px rgba(0, 255, 0, 0.5);
}
.progress-container {
position: relative;
width: 300px;
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
margin: 0 auto 1rem auto;
overflow: hidden;
}
.progress-bar {
height: 100%;
background: linear-gradient(90deg, #00ffff, #00ff00);
border-radius: 3px;
width: 0%;
transition: width 0.3s ease;
box-shadow: 0 0 15px rgba(0, 255, 255, 0.6);
}
.progress-glow {
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 20px;
background: rgba(255, 255, 255, 0.5);
border-radius: 3px;
animation: progressSweep 2s ease-in-out infinite;
}
.progress-percent {
font-size: 1.2rem;
color: #00ffff;
font-weight: bold;
margin-bottom: 1rem;
}
.system-status {
font-size: 0.9rem;
color: #ffffff;
opacity: 0.8;
}
.radar-display {
position: absolute;
bottom: 50px;
right: 50px;
width: 120px;
height: 120px;
}
.radar-circle {
position: relative;
width: 100%;
height: 100%;
border: 2px solid rgba(0, 255, 0, 0.5);
border-radius: 50%;
background: radial-gradient(circle, rgba(0, 255, 0, 0.1), transparent 70%);
}
.radar-sweep {
position: absolute;
top: 50%;
left: 50%;
width: 2px;
height: 50%;
background: linear-gradient(to top, rgba(0, 255, 0, 0.8), transparent);
transform-origin: bottom center;
animation: radarSweep 3s linear infinite;
}
.radar-blip {
position: absolute;
width: 6px;
height: 6px;
border-radius: 50%;
animation: blipPulse 2s ease-in-out infinite;
}
.station-blip {
top: 30%;
right: 20%;
background: rgba(0, 150, 255, 0.8);
box-shadow: 0 0 10px rgba(0, 150, 255, 0.6);
}
.ship-blip {
bottom: 25%;
left: 25%;
background: rgba(255, 255, 0, 0.8);
box-shadow: 0 0 10px rgba(255, 255, 0, 0.6);
}
/* Animations */
@keyframes starsMove {
0% { transform: translate(0, 0); }
100% { transform: translate(-100px, -50px); }
}
@keyframes nebulaFloat {
0%, 100% { transform: translate(0, 0) scale(1); }
50% { transform: translate(20px, -10px) scale(1.1); }
}
@keyframes stationRotate {
0% { transform: translate(-50%, -50%) rotate(0deg); }
100% { transform: translate(-50%, -50%) rotate(360deg); }
}
@keyframes dockingPulse {
0%, 100% { opacity: 0.3; }
50% { opacity: 1; }
}
@keyframes shipApproach {
0% { transform: translate(-50%, -50%) scale(0.8); }
50% { transform: translate(-40%, -45%) scale(1); }
100% { transform: translate(-50%, -50%) scale(0.8); }
}
@keyframes enginePulse {
0% { transform: scale(1); opacity: 1; }
100% { transform: scale(1.3); opacity: 0.7; }
}
@keyframes trailFlicker {
0%, 100% { opacity: 0.8; }
50% { opacity: 0.4; }
}
@keyframes titleGlow {
0% { text-shadow: 0 0 20px rgba(0, 255, 255, 0.8); }
100% { text-shadow: 0 0 30px rgba(0, 255, 255, 1), 0 0 40px rgba(0, 255, 255, 0.5); }
}
@keyframes progressSweep {
0% { left: -20px; }
100% { left: 100%; }
}
@keyframes radarSweep {
0% { transform: translate(-50%, 0) rotate(0deg); }
100% { transform: translate(-50%, 0) rotate(360deg); }
}
@keyframes blipPulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.5; transform: scale(1.2); }
}
.space-exit {
animation: spaceExit 1s ease-out forwards;
}
@keyframes spaceExit {
0% { opacity: 1; transform: scale(1); }
100% { opacity: 0; transform: scale(1.1); }
}
@media (max-width: 768px) {
.mission-title { font-size: 2rem; }
.progress-container { width: 250px; }
.radar-display { bottom: 30px; right: 30px; width: 100px; height: 100px; }
}
`;
document.head.appendChild(style);
document.body.appendChild(this.container);
document.body.style.overflow = 'hidden';
}
startLoadingSequence() {
const progressBar = document.getElementById('dockingProgress');
const percentText = document.getElementById('dockingPercent');
const statusText = document.getElementById('systemStatus');
const messages = [
"Approaching Space Station...",
"Requesting Docking Permission...",
"Permission Granted - Bay 7",
"Aligning Docking Trajectory...",
"Reducing Approach Velocity...",
"Engaging Magnetic Clamps...",
"Docking Sequence Complete!",
"Welcome to Cosmopedia"
];
const updateProgress = () => {
if (this.isDestroyed) return;
this.loadingProgress += Math.random() * 6 + 3;
if (this.loadingProgress >= 100) {
this.loadingProgress = 100;
progressBar.style.width = '100%';
percentText.textContent = '100%';
statusText.textContent = messages[messages.length - 1];
setTimeout(() => {
if (!this.isDestroyed) {
this.destroy();
}
}, 1200);
return;
}
// Update progress
progressBar.style.width = this.loadingProgress + '%';
percentText.textContent = Math.floor(this.loadingProgress) + '%';
// Update message based on progress
const messageIndex = Math.floor((this.loadingProgress / 100) * (messages.length - 1));
statusText.textContent = messages[messageIndex] || messages[0];
setTimeout(updateProgress, 120 + Math.random() * 80);
};
updateProgress();
}
destroy() {
this.isDestroyed = true;
// Add exit animation
this.container.classList.add('space-exit');
setTimeout(() => {
// Remove DOM elements
if (this.container && this.container.parentNode) {
this.container.parentNode.removeChild(this.container);
}
// Restore page
document.body.style.overflow = '';
console.log('🚀 Space Station Docking Complete!');
}, 1000);
}
}
// Initialize function with error handling
function initSpacePreloader() {
try {
console.log('🚀 Initiating Space Station Docking Sequence...');
// For testing, always show (uncomment for session storage)
// if (sessionStorage.getItem('spacePreloaderShown')) {
// console.log('⏭️ Preloader already shown this session');
// return;
// }
new SpaceStationPreloader();
// sessionStorage.setItem('spacePreloaderShown', 'true');
} catch (error) {
console.error('Preloader error:', error);
document.body.style.overflow = '';
}
}
// Start immediately with safety checks
function safeStart() {
try {
initSpacePreloader();
} catch (error) {
console.error('Failed to start preloader:', error);
// Ensure page is usable even if preloader fails
document.body.style.overflow = '';
}
}
// Multiple start points for reliability
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', safeStart);
} else {
safeStart();
}
// Emergency cleanup functions
window.clearSpacePreloader = () => {
const preloader = document.getElementById('spacePreloader');
if (preloader) preloader.remove();
document.body.style.overflow = '';
sessionStorage.clear();
};
window.clearPreloader = () => {
window.clearSpacePreloader();
};
window.resetSpacePreloader = () => {
sessionStorage.removeItem('spacePreloaderShown');
location.reload();
};
class CinemaSpacePreloader {
constructor() {
this.scene = null;
this.camera = null;
this.renderer = null;
this.spaceship = null;
this.planets = [];
this.particles = [];
this.nebula = null;
this.blackhole = null;
this.comet = null;
this.engineTrails = [];
this.loadingProgress = 0;
this.animationId = null;
this.isDestroyed = false;
this.loadingMessages = [
"Initializing Quantum Drive...",
"Scanning Deep Space...",
"Aligning Stellar Coordinates...",
"Charging Warp Core...",
"Calculating Trajectory...",
"Engaging Hyperdrive...",
"Reality Matrix Stabilized!",
"Jump Complete!"
];
this.init();
}
init() {
this.createContainer();
this.initThreeJS();
this.createEnvironment();
this.createSpaceship();
this.createPlanets();
this.createComet();
this.createBlackhole();
this.createParticleField();
this.startLoadingSequence();
this.animate();
}
createContainer() {
// Remove any existing preloader
const existing = document.getElementById('ultimateSpacePreloader');
if (existing) existing.remove();
// Create main container
this.container = document.createElement('div');
this.container.id = 'ultimateSpacePreloader';
this.container.innerHTML = `
<div class="preloader-canvas"></div>
<div class="preloader-overlay">
<div class="loading-interface">
<div class="hologram-title">COSMOPEDIA</div>
<div class="scan-lines"></div>
<div class="status-display">
<div class="status-message" id="statusMessage">Initializing Quantum Drive...</div>
<div class="progress-hologram">
<div class="progress-core" id="progressCore"></div>
<div class="progress-rings">
<div class="ring ring1"></div>
<div class="ring ring2"></div>
<div class="ring ring3"></div>
</div>
</div>
<div class="progress-percent" id="progressPercent">0%</div>
</div>
<div class="quantum-particles">
${Array.from({length: 30}, () => '<div class="quantum-dot"></div>').join('')}
</div>
</div>
</div>
`;
// Add ultimate styles
const style = document.createElement('style');
style.textContent = `
#ultimateSpacePreloader {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: #000000;
z-index: 999999;
overflow: hidden;
font-family: 'Orbitron', 'Space Grotesk', monospace;
}
.preloader-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.preloader-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: radial-gradient(ellipse at center, rgba(0,20,40,0.3) 0%, rgba(0,0,0,0.8) 70%);
display: flex;
align-items: center;
justify-content: center;
}
.loading-interface {
text-align: center;
position: relative;
z-index: 10;
}
.hologram-title {
font-size: 4rem;
font-weight: 700;
color: #00ffff;
text-shadow:
0 0 10px #00ffff,
0 0 20px #00ffff,
0 0 40px #00ffff,
0 0 80px #00ffff;
margin-bottom: 3rem;
letter-spacing: 0.5rem;
animation: hologramFlicker 3s ease-in-out infinite;
position: relative;
background: linear-gradient(45deg, #00ffff, #ff0080, #00ff80, #ffff00);
background-size: 400% 400%;
background-clip: text;
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: hologramFlicker 3s ease-in-out infinite, gradientShift 8s ease-in-out infinite;
}
.hologram-title::before {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
color: #ff0080;
z-index: -1;
animation: hologramGlitch 5s infinite;
}
.scan-lines {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: repeating-linear-gradient(
0deg,
transparent,
transparent 2px,
rgba(0,255,255,0.03) 2px,
rgba(0,255,255,0.03) 4px
);
animation: scanMove 2s linear infinite;
pointer-events: none;
}
.status-display {
margin-bottom: 2rem;
}
.status-message {
font-size: 1.5rem;
color: #00ccff;
margin-bottom: 3rem;
text-shadow: 0 0 10px rgba(0,204,255,0.5);
animation: statusPulse 2s ease-in-out infinite;
}
.progress-hologram {
position: relative;
width: 200px;
height: 200px;
margin: 0 auto 2rem auto;
}
.progress-core {
position: absolute;
top: 50%;
left: 50%;
width: 80px;
height: 80px;
transform: translate(-50%, -50%);
border: 3px solid #00ffff;
border-radius: 50%;
background: radial-gradient(circle, rgba(0,255,255,0.2) 0%, transparent 70%);
box-shadow:
0 0 20px #00ffff,
inset 0 0 20px rgba(0,255,255,0.1);
animation: coreEnergy 2s ease-in-out infinite;
}
.progress-rings {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.ring {
position: absolute;
border: 2px solid transparent;
border-radius: 50%;
animation: ringRotate 3s linear infinite;
}
.ring1 {
top: 10px;
left: 10px;
right: 10px;
bottom: 10px;
border-top-color: #ff0080;
border-right-color: #ff0080;
animation-duration: 2s;
box-shadow: 0 0 15px rgba(255,0,128,0.5);
}
.ring2 {
top: 25px;
left: 25px;
right: 25px;
bottom: 25px;
border-bottom-color: #00ff80;
border-left-color: #00ff80;
animation-duration: 3s;
animation-direction: reverse;
box-shadow: 0 0 15px rgba(0,255,128,0.5);
}
.ring3 {
top: 40px;
left: 40px;
right: 40px;
bottom: 40px;
border-top-color: #ffff00;
border-bottom-color: #ffff00;
animation-duration: 4s;
box-shadow: 0 0 15px rgba(255,255,0,0.5);
}
.progress-percent {
font-size: 2rem;
font-weight: bold;
color: #00ffff;
text-shadow: 0 0 20px #00ffff;
animation: percentGlow 1s ease-in-out infinite alternate;
}
.quantum-particles {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.quantum-dot {
position: absolute;
width: 4px;
height: 4px;
background: #00ffff;
border-radius: 50%;
box-shadow: 0 0 10px #00ffff;
animation: quantumFloat 6s linear infinite;
}
.quantum-dot:nth-child(even) {
background: #ff0080;
box-shadow: 0 0 10px #ff0080;
animation-duration: 8s;
}
.quantum-dot:nth-child(3n) {
background: #00ff80;
box-shadow: 0 0 10px #00ff80;
animation-duration: 7s;
}
@keyframes hologramFlicker {
0%, 100% { opacity: 1; }
5% { opacity: 0.8; }
10% { opacity: 1; }
15% { opacity: 0.9; }
20% { opacity: 1; }
}
@keyframes hologramGlitch {
0%, 90%, 100% { transform: translate(0); }
10% { transform: translate(-2px, 1px); }
20% { transform: translate(1px, -1px); }
30% { transform: translate(-1px, 1px); }
}
@keyframes scanMove {
0% { transform: translateY(-100vh); }
100% { transform: translateY(100vh); }
}
@keyframes statusPulse {
0%, 100% { opacity: 0.8; }
50% { opacity: 1; }
}
@keyframes coreEnergy {
0%, 100% { transform: translate(-50%, -50%) scale(1); }
50% { transform: translate(-50%, -50%) scale(1.1); }
}
@keyframes ringRotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes percentGlow {
0% { text-shadow: 0 0 20px #00ffff; }
100% { text-shadow: 0 0 30px #00ffff, 0 0 40px #00ffff; }
}
@keyframes quantumFloat {
0% {
transform: translate(0, 100vh) scale(0);
opacity: 0;
}
10% {
opacity: 1;
transform: scale(1);
}
90% {
opacity: 1;
}
100% {
transform: translate(${Math.random() * 200 - 100}px, -100vh) scale(0);
opacity: 0;
}
}
@keyframes ultimateExit {
0% { opacity: 1; transform: scale(1); }
100% { opacity: 0; transform: scale(1.2); }
}
@keyframes gradientShift {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
@keyframes ultimateExit {
0% { opacity: 1; transform: scale(1); }
100% { opacity: 0; transform: scale(1.2); }
}
.preloader-exit {
animation: ultimateExit 1s ease-out forwards;
}
@media (max-width: 768px) {
.hologram-title { font-size: 2.5rem; }
.progress-hologram { width: 150px; height: 150px; }
} particles = this.container.querySelectorAll('.quantum-dot');
particles.forEach((particle, index) => {
particle.style.left = Math.random() * 100 + '%';
particle.style.animationDelay = (index * 0.2) + 's';
});
document.body.appendChild(this.container);
document.body.style.overflow = 'hidden';
}
initThreeJS() {
const canvas = document.createElement('canvas');
this.container.querySelector('.preloader-canvas').appendChild(canvas);
// Scene
this.scene = new THREE.Scene();
this.scene.fog = new THREE.FogExp2(0x000011, 0.0003);
// Camera
this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
this.camera.position.set(0, 20, 100);
// Renderer with enhanced settings
this.renderer = new THREE.WebGLRenderer({
canvas: canvas,
alpha: true,
antialias: true,
powerPreference: "high-performance"
});
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.setClearColor(0x000000, 0);
this.renderer.shadowMap.enabled = true;
this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Enhanced lighting system
const ambientLight = new THREE.AmbientLight(0x404040, 0.4);
this.scene.add(ambientLight);
// Main light
const mainLight = new THREE.DirectionalLight(0x00aaff, 1.5);
mainLight.position.set(50, 50, 50);
mainLight.castShadow = true;
mainLight.shadow.mapSize.width = 2048;
mainLight.shadow.mapSize.height = 2048;
this.scene.add(mainLight);
// Accent lights
const light1 = new THREE.PointLight(0xff0080, 2, 100);
light1.position.set(-50, 20, 30);
this.scene.add(light1);
const light2 = new THREE.PointLight(0x00ff80, 1.5, 80);
light2.position.set(50, -20, -30);
this.scene.add(light2);
const light3 = new THREE.PointLight(0xffff00, 1, 60);
light3.position.set(0, 50, -50);
this.scene.add(light3);
}
createEnvironment() {
// Create massive starfield
const starGeometry = new THREE.BufferGeometry();
const starCount = 5000;
const positions = [];
const colors = [];
for (let i = 0; i < starCount; i++) {
positions.push(
(Math.random() - 0.5) * 800,
(Math.random() - 0.5) * 800,
(Math.random() - 0.5) * 800
);
// Different colored stars
const colorChoice = Math.random();
if (colorChoice < 0.7) {
colors.push(1, 1, 1); // White
} else if (colorChoice < 0.85) {
colors.push(0.8, 0.8, 1); // Blue
} else {
colors.push(1, 0.8, 0.6); // Orange
}
}
starGeometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
starGeometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
const starMaterial = new THREE.PointsMaterial({
size: 2,
vertexColors: true,
transparent: true,
opacity: 0.8,
blending: THREE.AdditiveBlending
});
this.stars = new THREE.Points(starGeometry, starMaterial);
this.scene.add(this.stars);
// Create nebula clouds
for (let i = 0; i < 8; i++) {
const nebulaGeometry = new THREE.SphereGeometry(25, 16, 16);
const nebulaMaterial = new THREE.MeshBasicMaterial({
color: new THREE.Color().setHSL(Math.random(), 0.8, 0.3),
transparent: true,
opacity: 0.1,
side: THREE.DoubleSide,
blending: THREE.AdditiveBlending
});
const nebula = new THREE.Mesh(nebulaGeometry, nebulaMaterial);
nebula.position.set(
(Math.random() - 0.5) * 400,
(Math.random() - 0.5) * 200,
(Math.random() - 0.5) * 400
);
nebula.scale.set(
1 + Math.random() * 2,
0.5 + Math.random(),
1 + Math.random() * 2
);
this.scene.add(nebula);
}
}
createSpaceship() {
const spaceshipGroup = new THREE.Group();
// Main fuselage - sleek design
const fuselageGeometry = new THREE.CylinderGeometry(0.8, 2.5, 12, 16);
const fuselageMaterial = new THREE.MeshPhongMaterial({
color: 0x4A90E2,
shininess: 150,
specular: 0x111111
});
const fuselage = new THREE.Mesh(fuselageGeometry, fuselageMaterial);
fuselage.rotation.z = Math.PI / 2;
fuselage.castShadow = true;
spaceshipGroup.add(fuselage);
// Wings - more realistic
const wingGeometry = new THREE.BoxGeometry(8, 0.5, 3);
const wingMaterial = new THREE.MeshPhongMaterial({
color: 0x7B68EE,
shininess: 100
});
const leftWing = new THREE.Mesh(wingGeometry, wingMaterial);
leftWing.position.set(-3, 3, 0);
leftWing.rotation.z = -0.2;
leftWing.castShadow = true;
spaceshipGroup.add(leftWing);
const rightWing = new THREE.Mesh(wingGeometry, wingMaterial);
rightWing.position.set(-3, -3, 0);
rightWing.rotation.z = 0.2;
rightWing.castShadow = true;
spaceshipGroup.add(rightWing);
// Engine clusters with glow
for (let i = 0; i < 4; i++) {
const engineGeometry = new THREE.CylinderGeometry(0.3, 0.5, 2, 8);
const engineMaterial = new THREE.MeshBasicMaterial({
color: 0x00ffff,
transparent: true,
opacity: 0.9
});
const engine = new THREE.Mesh(engineGeometry, engineMaterial);
const angle = (i / 4) * Math.PI * 2;
engine.position.set(
5,
Math.cos(angle) * 1.5,
Math.sin(angle) * 1.5
);
engine.rotation.z = Math.PI / 2;
spaceshipGroup.add(engine);
// Engine glow effect
const glowGeometry = new THREE.SphereGeometry(0.8, 8, 8);
const glowMaterial = new THREE.MeshBasicMaterial({
color: 0x00ffff,
transparent: true,
opacity: 0.3,
blending: THREE.AdditiveBlending
});
const glow = new THREE.Mesh(glowGeometry, glowMaterial);
glow.position.copy(engine.position);
glow.position.x += 1;
spaceshipGroup.add(glow);
}
spaceshipGroup.position.set(-80, 10, 20);
spaceshipGroup.scale.set(1.5, 1.5, 1.5);
this.spaceship = spaceshipGroup;
this.scene.add(this.spaceship);
}
createPlanets() {
// Create several planets with different characteristics
const planetData = [
{ radius: 8, color: 0x4169E1, distance: 120, speed: 0.005, name: 'earth' },
{ radius: 6, color: 0xff6b47, distance: 180, speed: 0.003, name: 'mars' },
{ radius: 12, color: 0xFFD700, distance: 250, speed: 0.002, name: 'saturn' },
{ radius: 10, color: 0xFF4500, distance: 320, speed: 0.001, name: 'jupiter' }
];
planetData.forEach((data, index) => {
const planetGroup = new THREE.Group();
// Main planet
const planetGeometry = new THREE.SphereGeometry(data.radius, 32, 32);
const planetMaterial = new THREE.MeshPhongMaterial({
color: data.color,
shininess: 30,
transparent: true,
opacity: 0.9
});
const planet = new THREE.Mesh(planetGeometry, planetMaterial);
planet.castShadow = true;
planet.receiveShadow = true;
planetGroup.add(planet);
// Add atmosphere
const atmosphereGeometry = new THREE.SphereGeometry(data.radius * 1.15, 32, 32);
const atmosphereMaterial = new THREE.MeshBasicMaterial({
color: data.color,
transparent: true,
opacity: 0.15,
side: THREE.BackSide,
blending: THREE.AdditiveBlending
});
const atmosphere = new THREE.Mesh(atmosphereGeometry, atmosphereMaterial);
planetGroup.add(atmosphere);
// Special features for specific planets
if (data.name === 'saturn') {
// Add Saturn's rings
for (let i = 0; i < 4; i++) {
const ringGeometry = new THREE.RingGeometry(data.radius * (1.5 + i * 0.3), data.radius * (1.7 + i * 0.3), 64);
const ringMaterial = new THREE.MeshBasicMaterial({
color: new THREE.Color().setHSL(0.1 + i * 0.05, 0.8, 0.6),
transparent: true,
opacity: 0.7 - i * 0.1,
side: THREE.DoubleSide
});
const ring = new THREE.Mesh(ringGeometry, ringMaterial);
ring.rotation.x = Math.PI / 2 + (Math.random() - 0.5) * 0.1;
planetGroup.add(ring);
}
}
if (data.name === 'earth') {
// Add Earth's moon
const moonGeometry = new THREE.SphereGeometry(data.radius * 0.25, 16, 16);
const moonMaterial = new THREE.MeshPhongMaterial({
color: 0xaaaaaa,
shininess: 5
});
const moon = new THREE.Mesh(moonGeometry, moonMaterial);
moon.position.set(data.radius * 2, 0, 0);
planetGroup.add(moon);
}
planetGroup.position.set(data.distance, Math.random() * 40 - 20, Math.random() * 40 - 20);
this.planets.push({ mesh: planetGroup, speed: data.speed, distance: data.distance });
this.scene.add(planetGroup);
});
}
createComet() {
const cometGroup = new THREE.Group();
// Comet nucleus
const nucleusGeometry = new THREE.SphereGeometry(2, 16, 16);
const nucleusMaterial = new THREE.MeshPhongMaterial({
color: 0xaaaaaa,
shininess: 10
});
const nucleus = new THREE.Mesh(nucleusGeometry, nucleusMaterial);
nucleus.castShadow = true;
cometGroup.add(nucleus);
// Comet coma (fuzzy atmosphere)
const comaGeometry = new THREE.SphereGeometry(8, 16, 16);
const comaMaterial = new THREE.MeshBasicMaterial({
color: 0x00aaff,
transparent: true,
opacity: 0.2,
blending: THREE.AdditiveBlending
});
const coma = new THREE.Mesh(comaGeometry, comaMaterial);
cometGroup.add(coma);
// Comet tail - create multiple segments
for (let i = 0; i < 20; i++) {
const tailGeometry = new THREE.SphereGeometry(1 + i * 0.5, 8, 8);
const tailMaterial = new THREE.MeshBasicMaterial({
color: new THREE.Color().setHSL(0.6, 0.8, 0.8),
transparent: true,
opacity: 0.3 - i * 0.01,
blending: THREE.AdditiveBlending
});
const tailSegment = new THREE.Mesh(tailGeometry, tailMaterial);
tailSegment.position.set(-i * 3, Math.sin(i * 0.5) * 2, Math.cos(i * 0.3) * 1);
cometGroup.position.set(-200, 50, -100);
this.comet = cometGroup;
this.scene.add(this.comet);
} this.scene.add(this.comet);
} this.scene.add(planetGroup);
});
}
createBlackhole() {
const blackholeGroup = new THREE.Group();
// Event horizon
const horizonGeometry = new THREE.SphereGeometry(15, 32, 32);
const horizonMaterial = new THREE.MeshBasicMaterial({
color: 0x000000,
transparent: true,
opacity: 0.9
});
const horizon = new THREE.Mesh(horizonGeometry, horizonMaterial);
blackholeGroup.add(horizon);
// Accretion disk
for (let i = 0; i < 5; i++) {
const ringGeometry = new THREE.TorusGeometry(20 + i * 8, 2, 8, 64);
const ringMaterial = new THREE.MeshBasicMaterial({
color: new THREE.Color().setHSL(0.1 + i * 0.1, 1, 0.5),
transparent: true,
opacity: 0.6 - i * 0.1,
blending: THREE.AdditiveBlending
});
const ring = new THREE.Mesh(ringGeometry, ringMaterial);
ring.rotation.x = Math.PI / 2 + Math.random() * 0.2;
blackholeGroup.add(ring);
}
blackholeGroup.position.set(200, -100, -200);
this.blackhole = blackholeGroup;
this.scene.add(this.blackhole);
}
createParticleField() {
// Create multiple particle systems
for (let system = 0; system < 4; system++) {
const particleCount = 1500;
const geometry = new THREE.BufferGeometry();
const positions = [];
const colors = [];
const velocities = [];
for (let i = 0; i < particleCount; i++) {
positions.push(
(Math.random() - 0.5) * 600,
(Math.random() - 0.5) * 300,
(Math.random() - 0.5) * 600
);
// Different particle colors per system
if (system === 0) {
colors.push(0, 1, 1); // Cyan
} else if (system === 1) {
colors.push(1, 0, 0.5); // Magenta
} else if (system === 2) {
colors.push(0, 1, 0.5); // Green
} else {
colors.push(1, 1, 0); // Yellow
}
velocities.push(
(Math.random() - 0.5) * 0.3,
(Math.random() - 0.5) * 0.2,
(Math.random() - 0.5) * 0.3
);
}
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
geometry.setAttribute('color', new THREE.Float32BufferAttribute(colors, 3));
geometry.setAttribute('velocity', new THREE.Float32BufferAttribute(velocities, 3));
const material = new THREE.PointsMaterial({
size: 1.5 + system * 0.5,
vertexColors: true,
transparent: true,
opacity: 0.7,
blending: THREE.AdditiveBlending
});
const particles = new THREE.Points(geometry, material);
this.particles.push(particles);
this.scene.add(particles);
}
}
startLoadingSequence() {
let messageIndex = 0;
const messageElement = document.getElementById('statusMessage');
const progressCore = document.getElementById('progressCore');
const progressPercent = document.getElementById('progressPercent');
const updateProgress = () => {
if (this.isDestroyed) return;
this.loadingProgress += Math.random() * 4 + 2;
if (this.loadingProgress >= 100) {
this.loadingProgress = 100;
if (this.loadingProgress >= 100) {
this.loadingProgress = 100;
messageElement.textContent = this.loadingMessages[this.loadingMessages.length - 1];
progressPercent.textContent = '100%';
setTimeout(() => {
if (!this.isDestroyed) {
this.destroy();
}
}, 1500);
return;
}
// Update progress core intensity
const intensity = this.loadingProgress / 100;
progressCore.style.boxShadow =
`0 0 ${20 + intensity * 30}px #00ffff, inset 0 0 ${20 + intensity * 20}px rgba(0,255,255,${0.1 + intensity * 0.3})`;
progressPercent.textContent = Math.floor(this.loadingProgress) + '%';
// Update message
const expectedIndex = Math.floor((this.loadingProgress / 100) * (this.loadingMessages.length - 1));
if (expectedIndex !== messageIndex && expectedIndex < this.loadingMessages.length - 1) {
messageIndex = expectedIndex;
messageElement.textContent = this.loadingMessages[messageIndex];
}
// Update message
const expectedIndex = Math.floor((this.loadingProgress / 100) * (this.loadingMessages.length - 1));
if (expectedIndex !== messageIndex && expectedIndex < this.loadingMessages.length - 1) {
messageIndex = expectedIndex;
messageElement.textContent = this.loadingMessages[messageIndex];
} time = Date.now() * 0.001;
// Rotate stars
if (this.stars) {
this.stars.rotation.y += 0.002;
}
// Animate spaceship
if (this.spaceship) {
this.spaceship.position.y = Math.sin(time * 2) * 0.5;
this.spaceship.rotation.z = Math.sin(time) * 0.1;
}
// Animate planets in orbital motion
this.planets.forEach((planetObj) => {
planetObj.mesh.rotation.y += planetObj.speed * 2; // Planet rotation
// Orbital motion around center
const orbitSpeed = planetObj.speed * 0.5;
const angle = time * orbitSpeed;
animate() {
if (this.isDestroyed) return;
this.animationId = requestAnimationFrame(() => this.animate());
const time = Date.now() * 0.001;
// Animate twinkling stars
if (this.stars) {
this.stars.rotation.y += 0.001;
this.stars.rotation.x += 0.0005;
// Animate star opacity for twinkling effect
const starMaterial = this.stars.material;
starMaterial.opacity = 0.8 + Math.sin(time * 2) * 0.2;
}
// Animate spaceship with enhanced effects
if (this.spaceship) {
this.spaceship.position.y = 10 + Math.sin(time * 2) * 2;
this.spaceship.position.x = -80 + Math.sin(time * 0.5) * 10;
this.spaceship.rotation.z = Math.sin(time) * 0.1;
this.spaceship.rotation.y = Math.sin(time * 0.3) * 0.05;
// Animate engine glows
this.spaceship.children.forEach((child) => {
if (child.material && child.material.color && child.material.color.r === 0) {
// This is an engine glow
child.material.opacity = 0.3 + Math.sin(time * 10) * 0.2;
child.scale.setScalar(0.8 + Math.sin(time * 8) * 0.3);
}
});
}
// Animate planets in orbital motion
this.planets.forEach((planetObj) => {
planetObj.mesh.rotation.y += planetObj.speed * 2; // Planet rotation
// Orbital motion around center
const orbitSpeed = planetObj.speed * 0.5;
const angle = time * orbitSpeed;
planetObj.mesh.position.x = Math.cos(angle) * planetObj.distance;
planetObj.mesh.position.z = Math.sin(angle) * planetObj.distance;
// Slight vertical oscillation
planetObj.mesh.position.y += Math.sin(time * planetObj.speed * 20) * 0.2;
});
// Animate comet
if (this.comet) {
// Comet follows an elliptical path
const cometSpeed = time * 0.3;
this.comet.position.x = -200 + Math.cos(cometSpeed) * 150;
this.comet.position.y = 50 + Math.sin(cometSpeed * 0.7) * 30;
this.comet.position.z = -100 + Math.sin(cometSpeed) * 80;
// Rotate comet slowly
this.comet.rotation.y += 0.01;
// Animate tail segments
this.comet.children.forEach((child, index) => {
if (index > 1) { // Skip nucleus and coma
child.position.y += Math.sin(time * 3 + index) * 0.1;
child.scale.setScalar(0.8 + Math.sin(time * 2 + index) * 0.2);
}
});
}
// Animate blackhole
if (this.blackhole) {
this.blackhole.rotation.y += 0.005;
this.blackhole.children.forEach((ring, index) => {
if (index > 0) { // Skip the event horizon
ring.rotation.z += 0.01 * (index + 1);
}
});
}
// Animate particles
this.particles.forEach((particleSystem) => {
const positions = particleSystem.geometry.attributes.position.array;
const velocities = particleSystem.geometry.attributes.velocity.array;
for (let i = 0; i < positions.length; i += 3) {
positions[i] += velocities[i];
positions[i + 1] += velocities[i + 1];
positions[i + 2] += velocities[i + 2];
// Reset particles that go too far
if (Math.abs(positions[i]) > 300 || Math.abs(positions[i + 1]) > 150 || Math.abs(positions[i + 2]) > 300) {
positions[i] = (Math.random() - 0.5) * 600;
positions[i + 1] = (Math.random() - 0.5) * 300;
positions[i + 2] = (Math.random() - 0.5) * 600;
}
}
particleSystem.geometry.attributes.position.needsUpdate = true;
});
// Cinematic camera movement with parallax
const parallaxX = Math.sin(time * 0.5) * 8;
const parallaxY = 20 + Math.cos(time * 0.3) * 5;
const parallaxZ = 100 + Math.sin(time * 0.2) * 20;
this.camera.position.x = parallaxX;
this.camera.position.y = parallaxY;
this.camera.position.z = parallaxZ;
// Look at a point slightly offset for dynamic feel
this.camera.lookAt(
Math.sin(time * 0.1) * 5,
Math.cos(time * 0.15) * 3,
0
);
this.renderer.render(this.scene, this.camera);
}
// Remove DOM elements
if (this.container && this.container.parentNode) {
this.container.parentNode.removeChild(this.container);
}
// Restore page
document.body.style.overflow = '';
console.log('✨ Cinema-Quality Space Preloader completed!');
}, 1200);
}
}
// Start immediately - ALWAYS SHOW FOR TESTING (remove comment to enable session storage)
function initCinemaPreloader() {
console.log('🎬 Checking session storage...');
// TEMPORARILY DISABLED FOR TESTING - UNCOMMENT TO ENABLE SESSION STORAGE
// if (sessionStorage.getItem('spacePreloaderShown')) {
// console.log('⏭️ Preloader already shown this session');
// return;
// }
console.log('🎬 Creating Cinema-Quality Space Preloader!');
if (window.THREE) {
// Remove immediate preloader first
const immediatePreloader = document.getElementById('immediatePreloader');
if (immediatePreloader) {
immediatePreloader.remove();
}
new CinemaSpacePreloader();
// sessionStorage.setItem('spacePreloaderShown', 'true');
} else {
console.log('Loading Three.js...');
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js';
script.onload = () => {
console.log('Three.js loaded! Creating Cinema-Quality Space Preloader!');
// Remove immediate preloader first
const immediatePreloader = document.getElementById('immediatePreloader');
if (immediatePreloader) {
immediatePreloader.remove();
}
new CinemaSpacePreloader();
// sessionStorage.setItem('spacePreloaderShown', 'true');
};
script.onerror = () => {
console.error('Failed to load Three.js');
// Remove immediate preloader on error
const immediatePreloader = document.getElementById('immediatePreloader');
if (immediatePreloader) {
immediatePreloader.remove();
document.body.style.overflow = '';
}
};
document.head.appendChild(script);
}
}
// Start immediately
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initCinemaPreloader);
} else {
initCinemaPreloader();
}
// Global function to reset preloader (for testing)
window.resetProfessionalPreloader = () => {
sessionStorage.removeItem('spacePreloaderShown');
location.reload();
};
// Clear preloader session on development
window.addEventListener('beforeunload', () => {
if (window.location.hostname === 'localhost' || window.location.search.includes('dev')) {
// Only clear on localhost for development
// sessionStorage.removeItem('spacePreloaderShown');
}
});
// Emergency function to clear and restart
window.clearSpacePreloader = () => {
sessionStorage.clear();
location.reload();
};