631 lines
18 KiB
JavaScript
631 lines
18 KiB
JavaScript
/* ==========================================================================
|
|
SYSTEM AWAKENING - Main Application Entry Point
|
|
Initializes and coordinates all system components
|
|
========================================================================== */
|
|
|
|
import { ParticleSystem } from './particleSystem.js';
|
|
import { ProgressCircles } from './progressCircles.js';
|
|
import { Terminal } from './terminal.js';
|
|
import { Typewriter } from './typewriter.js';
|
|
import { AnimationCoordinator } from './animate.js';
|
|
import { EventManager } from './events.js';
|
|
|
|
/**
|
|
* System Awakening Application Class
|
|
* Main controller for the entire application
|
|
*/
|
|
class SystemAwakening {
|
|
/**
|
|
* Create and initialize the application
|
|
*/
|
|
constructor() {
|
|
// Application state
|
|
this.isInitialized = false;
|
|
this.components = {};
|
|
this.isMobile = window.innerWidth <= 768;
|
|
|
|
// Performance tracking
|
|
this.startTime = Date.now();
|
|
this.initTime = 0;
|
|
|
|
// Initialize the application
|
|
this.init();
|
|
}
|
|
|
|
/**
|
|
* Initialize the application
|
|
*/
|
|
async init() {
|
|
console.log('SYSTEM AWAKENING - Initializing...');
|
|
|
|
try {
|
|
// Show loading state
|
|
this.showLoading();
|
|
|
|
// Initialize core components
|
|
await this.initComponents();
|
|
|
|
// Start the application
|
|
this.start();
|
|
|
|
// Record initialization time
|
|
this.initTime = Date.now() - this.startTime;
|
|
|
|
// Mark as initialized
|
|
this.isInitialized = true;
|
|
|
|
console.log(`SYSTEM AWAKENING - Initialized in ${this.initTime}ms`);
|
|
console.log('All systems operational.');
|
|
|
|
// Hide loading state
|
|
this.hideLoading();
|
|
|
|
} catch (error) {
|
|
console.error('Failed to initialize SYSTEM AWAKENING:', error);
|
|
this.showError(error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize all application components
|
|
*/
|
|
async initComponents() {
|
|
// Initialize particle system
|
|
await this.initParticleSystem();
|
|
|
|
// Initialize progress circles
|
|
await this.initProgressCircles();
|
|
|
|
// Initialize terminal
|
|
await this.initTerminal();
|
|
|
|
// Initialize typewriter
|
|
await this.initTypewriter();
|
|
|
|
// Initialize animation coordinator
|
|
await this.initAnimationCoordinator();
|
|
|
|
// Initialize event manager
|
|
await this.initEventManager();
|
|
}
|
|
|
|
/**
|
|
* Initialize the particle system
|
|
*/
|
|
async initParticleSystem() {
|
|
console.log('Initializing particle system...');
|
|
|
|
const canvas = document.getElementById('particle-canvas');
|
|
if (!canvas) {
|
|
throw new Error('Particle canvas not found');
|
|
}
|
|
|
|
try {
|
|
this.components.particleSystem = new ParticleSystem(canvas);
|
|
console.log('Particle system initialized');
|
|
} catch (error) {
|
|
console.warn('Failed to initialize particle system:', error);
|
|
// Continue without particle system
|
|
this.components.particleSystem = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize the progress circles
|
|
*/
|
|
async initProgressCircles() {
|
|
console.log('Initializing progress circles...');
|
|
|
|
const canvases = [
|
|
document.getElementById('compute-ring'),
|
|
document.getElementById('storage-ring'),
|
|
document.getElementById('sync-ring')
|
|
];
|
|
|
|
// Check if all canvases exist
|
|
const missingCanvases = canvases.filter(canvas => !canvas);
|
|
if (missingCanvases.length > 0) {
|
|
console.warn('Some progress canvases not found:', missingCanvases);
|
|
// Create fallback canvases if needed
|
|
this.createFallbackCanvases(canvases);
|
|
}
|
|
|
|
try {
|
|
this.components.progressCircles = new ProgressCircles(canvases);
|
|
console.log('Progress circles initialized');
|
|
} catch (error) {
|
|
console.warn('Failed to initialize progress circles:', error);
|
|
// Continue without progress circles
|
|
this.components.progressCircles = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create fallback canvases if some are missing
|
|
* @param {Array} canvases - Array of canvas elements
|
|
*/
|
|
createFallbackCanvases(canvases) {
|
|
canvases.forEach((canvas, index) => {
|
|
if (!canvas) {
|
|
console.log(`Creating fallback canvas ${index}`);
|
|
// This would create a fallback element
|
|
// For now, we'll just log it
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Initialize the terminal
|
|
*/
|
|
async initTerminal() {
|
|
console.log('Initializing terminal...');
|
|
|
|
const terminalContainer = document.querySelector('.terminal-container');
|
|
if (!terminalContainer) {
|
|
console.warn('Terminal container not found');
|
|
this.components.terminal = null;
|
|
return;
|
|
}
|
|
|
|
try {
|
|
this.components.terminal = new Terminal(terminalContainer);
|
|
console.log('Terminal initialized');
|
|
} catch (error) {
|
|
console.warn('Failed to initialize terminal:', error);
|
|
this.components.terminal = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize the typewriter
|
|
*/
|
|
async initTypewriter() {
|
|
console.log('Initializing typewriter...');
|
|
|
|
const typewriterElement = document.getElementById('typewriter-text');
|
|
if (!typewriterElement) {
|
|
console.warn('Typewriter element not found');
|
|
this.components.typewriter = null;
|
|
return;
|
|
}
|
|
|
|
try {
|
|
this.components.typewriter = new Typewriter(typewriterElement);
|
|
console.log('Typewriter initialized');
|
|
} catch (error) {
|
|
console.warn('Failed to initialize typewriter:', error);
|
|
this.components.typewriter = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize the animation coordinator
|
|
*/
|
|
async initAnimationCoordinator() {
|
|
console.log('Initializing animation coordinator...');
|
|
|
|
try {
|
|
this.components.animationCoordinator = new AnimationCoordinator(this.components);
|
|
console.log('Animation coordinator initialized');
|
|
} catch (error) {
|
|
console.warn('Failed to initialize animation coordinator:', error);
|
|
this.components.animationCoordinator = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize the event manager
|
|
*/
|
|
async initEventManager() {
|
|
console.log('Initializing event manager...');
|
|
|
|
try {
|
|
this.components.eventManager = new EventManager(this.components);
|
|
console.log('Event manager initialized');
|
|
} catch (error) {
|
|
console.warn('Failed to initialize event manager:', error);
|
|
this.components.eventManager = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start the application
|
|
*/
|
|
start() {
|
|
console.log('Starting SYSTEM AWAKENING...');
|
|
|
|
// Start animation coordinator
|
|
if (this.components.animationCoordinator) {
|
|
this.components.animationCoordinator.start();
|
|
}
|
|
|
|
// Start terminal auto-logging (handled internally)
|
|
|
|
// Start progress circle animations (handled internally)
|
|
|
|
// Start typewriter animation (handled internally)
|
|
|
|
// Dispatch startup event
|
|
this.dispatchEvent('system:start', {
|
|
timestamp: Date.now(),
|
|
components: Object.keys(this.components).filter(key => this.components[key])
|
|
});
|
|
|
|
console.log('SYSTEM AWAKENING started successfully');
|
|
}
|
|
|
|
/**
|
|
* Show loading state
|
|
*/
|
|
showLoading() {
|
|
// Create loading overlay
|
|
const loadingOverlay = document.createElement('div');
|
|
loadingOverlay.id = 'loading-overlay';
|
|
loadingOverlay.style.cssText = `
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: var(--color-bg);
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 10000;
|
|
opacity: 1;
|
|
transition: opacity 0.5s ease;
|
|
`;
|
|
|
|
// Add loading text
|
|
const loadingText = document.createElement('div');
|
|
loadingText.textContent = 'SYSTEM AWAKENING';
|
|
loadingText.style.cssText = `
|
|
font-family: var(--font-heading);
|
|
font-size: 2.5rem;
|
|
color: var(--color-primary);
|
|
text-shadow: var(--glow-primary);
|
|
margin-bottom: 2rem;
|
|
letter-spacing: 0.2em;
|
|
`;
|
|
|
|
// Add spinner
|
|
const spinner = document.createElement('div');
|
|
spinner.style.cssText = `
|
|
width: 50px;
|
|
height: 50px;
|
|
border: 3px solid rgba(0, 243, 255, 0.3);
|
|
border-radius: 50%;
|
|
border-top-color: var(--color-primary);
|
|
animation: spin 1s linear infinite;
|
|
`;
|
|
|
|
// Add spinner animation
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
@keyframes spin {
|
|
0% { transform: rotate(0deg); }
|
|
100% { transform: rotate(360deg); }
|
|
}
|
|
`;
|
|
|
|
document.head.appendChild(style);
|
|
loadingOverlay.appendChild(loadingText);
|
|
loadingOverlay.appendChild(spinner);
|
|
document.body.appendChild(loadingOverlay);
|
|
|
|
// Store reference for later removal
|
|
this.loadingOverlay = loadingOverlay;
|
|
}
|
|
|
|
/**
|
|
* Hide loading state
|
|
*/
|
|
hideLoading() {
|
|
if (this.loadingOverlay) {
|
|
// Fade out
|
|
this.loadingOverlay.style.opacity = '0';
|
|
|
|
// Remove after fade
|
|
setTimeout(() => {
|
|
if (this.loadingOverlay.parentNode) {
|
|
this.loadingOverlay.parentNode.removeChild(this.loadingOverlay);
|
|
}
|
|
}, 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show error state
|
|
* @param {Error} error - Error object
|
|
*/
|
|
showError(error) {
|
|
console.error('Application error:', error);
|
|
|
|
// Create error overlay
|
|
const errorOverlay = document.createElement('div');
|
|
errorOverlay.id = 'error-overlay';
|
|
errorOverlay.style.cssText = `
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: var(--color-bg-dark);
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 10000;
|
|
color: var(--color-text);
|
|
font-family: var(--font-body);
|
|
text-align: center;
|
|
padding: 2rem;
|
|
`;
|
|
|
|
// Error icon
|
|
const errorIcon = document.createElement('div');
|
|
errorIcon.innerHTML = '⚠️';
|
|
errorIcon.style.fontSize = '4rem';
|
|
errorIcon.style.marginBottom = '1rem';
|
|
|
|
// Error message
|
|
const errorMessage = document.createElement('div');
|
|
errorMessage.style.fontSize = '1.5rem';
|
|
errorMessage.style.marginBottom = '1rem';
|
|
errorMessage.textContent = 'SYSTEM INITIALIZATION FAILED';
|
|
|
|
// Error details
|
|
const errorDetails = document.createElement('div');
|
|
errorDetails.style.fontSize = '1rem';
|
|
errorDetails.style.color = 'var(--color-text-dim)';
|
|
errorDetails.style.marginBottom = '2rem';
|
|
errorDetails.textContent = error.message || 'Unknown error occurred';
|
|
|
|
// Retry button
|
|
const retryButton = document.createElement('button');
|
|
retryButton.textContent = 'RETRY INITIALIZATION';
|
|
retryButton.style.cssText = `
|
|
background: var(--color-primary);
|
|
color: var(--color-bg);
|
|
border: none;
|
|
padding: 0.75rem 1.5rem;
|
|
font-family: var(--font-heading);
|
|
font-size: 1rem;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
letter-spacing: 0.1em;
|
|
transition: all 0.3s ease;
|
|
`;
|
|
|
|
retryButton.addEventListener('mouseenter', () => {
|
|
retryButton.style.transform = 'scale(1.05)';
|
|
retryButton.style.boxShadow = 'var(--glow-primary)';
|
|
});
|
|
|
|
retryButton.addEventListener('mouseleave', () => {
|
|
retryButton.style.transform = 'scale(1)';
|
|
retryButton.style.boxShadow = 'none';
|
|
});
|
|
|
|
retryButton.addEventListener('click', () => {
|
|
location.reload();
|
|
});
|
|
|
|
// Assemble overlay
|
|
errorOverlay.appendChild(errorIcon);
|
|
errorOverlay.appendChild(errorMessage);
|
|
errorOverlay.appendChild(errorDetails);
|
|
errorOverlay.appendChild(retryButton);
|
|
|
|
// Remove existing overlays
|
|
if (this.loadingOverlay && this.loadingOverlay.parentNode) {
|
|
this.loadingOverlay.parentNode.removeChild(this.loadingOverlay);
|
|
}
|
|
|
|
// Add to document
|
|
document.body.appendChild(errorOverlay);
|
|
}
|
|
|
|
/**
|
|
* Dispatch a custom event
|
|
* @param {string} eventName - Name of the event
|
|
* @param {Object} detail - Event details
|
|
*/
|
|
dispatchEvent(eventName, detail = {}) {
|
|
const event = new CustomEvent(eventName, {
|
|
detail: detail,
|
|
bubbles: true
|
|
});
|
|
|
|
document.dispatchEvent(event);
|
|
}
|
|
|
|
/**
|
|
* Get application status
|
|
* @returns {Object} Application status
|
|
*/
|
|
getStatus() {
|
|
return {
|
|
initialized: this.isInitialized,
|
|
initTime: this.initTime,
|
|
components: Object.keys(this.components).reduce((acc, key) => {
|
|
acc[key] = !!this.components[key];
|
|
return acc;
|
|
}, {}),
|
|
isMobile: this.isMobile,
|
|
timestamp: Date.now()
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Restart the application
|
|
*/
|
|
restart() {
|
|
console.log('Restarting SYSTEM AWAKENING...');
|
|
|
|
// Clean up current instance
|
|
this.dispose();
|
|
|
|
// Start new instance
|
|
setTimeout(() => {
|
|
new SystemAwakening();
|
|
}, 100);
|
|
}
|
|
|
|
/**
|
|
* Clean up all resources
|
|
*/
|
|
dispose() {
|
|
console.log('Cleaning up SYSTEM AWAKENING...');
|
|
|
|
// Stop animation coordinator
|
|
if (this.components.animationCoordinator) {
|
|
this.components.animationCoordinator.dispose();
|
|
}
|
|
|
|
// Dispose particle system
|
|
if (this.components.particleSystem) {
|
|
this.components.particleSystem.dispose();
|
|
}
|
|
|
|
// Dispose progress circles
|
|
if (this.components.progressCircles) {
|
|
this.components.progressCircles.dispose();
|
|
}
|
|
|
|
// Dispose terminal
|
|
if (this.components.terminal) {
|
|
this.components.terminal.dispose();
|
|
}
|
|
|
|
// Dispose typewriter
|
|
if (this.components.typewriter) {
|
|
this.components.typewriter.dispose();
|
|
}
|
|
|
|
// Dispose event manager
|
|
if (this.components.eventManager) {
|
|
this.components.eventManager.dispose();
|
|
}
|
|
|
|
// Remove event listeners
|
|
this.removeAllEventListeners();
|
|
|
|
console.log('SYSTEM AWAKENING cleaned up');
|
|
}
|
|
|
|
/**
|
|
* Remove all event listeners
|
|
*/
|
|
removeAllEventListeners() {
|
|
// Remove custom event listeners
|
|
const events = ['system:start', 'system:resize', 'system:scroll', 'system:mouseMove'];
|
|
events.forEach(eventName => {
|
|
document.removeEventListener(eventName, () => {});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get component by name
|
|
* @param {string} name - Component name
|
|
* @returns {Object} Component instance
|
|
*/
|
|
getComponent(name) {
|
|
return this.components[name] || null;
|
|
}
|
|
|
|
/**
|
|
* Check if a component is available
|
|
* @param {string} name - Component name
|
|
* @returns {boolean} True if component exists
|
|
*/
|
|
hasComponent(name) {
|
|
return !!this.components[name];
|
|
}
|
|
}
|
|
|
|
// ==========================================================================
|
|
// Application Startup
|
|
// ==========================================================================
|
|
|
|
/**
|
|
* Wait for DOM to be ready before starting the application
|
|
*/
|
|
function startApplication() {
|
|
// Check if Three.js is available
|
|
if (typeof THREE === 'undefined') {
|
|
console.error('Three.js not loaded. Please check CDN connection.');
|
|
// Show error message
|
|
const errorDiv = document.createElement('div');
|
|
errorDiv.style.cssText = `
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #0a0a14;
|
|
color: #ff5555;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
font-family: monospace;
|
|
text-align: center;
|
|
padding: 2rem;
|
|
z-index: 10000;
|
|
`;
|
|
errorDiv.innerHTML = `
|
|
<div>
|
|
<h1>SYSTEM ERROR</h1>
|
|
<p>Three.js library not loaded.</p>
|
|
<p>Please check your internet connection and refresh.</p>
|
|
</div>
|
|
`;
|
|
document.body.appendChild(errorDiv);
|
|
return;
|
|
}
|
|
|
|
// Check if required HTML elements exist
|
|
const requiredElements = [
|
|
'particle-canvas',
|
|
'typewriter-text',
|
|
'compute-ring',
|
|
'terminal-output'
|
|
];
|
|
|
|
const missingElements = requiredElements.filter(id => !document.getElementById(id));
|
|
if (missingElements.length > 0) {
|
|
console.warn('Missing required elements:', missingElements);
|
|
// Continue anyway - some components may gracefully degrade
|
|
}
|
|
|
|
// Start the application
|
|
const app = new SystemAwakening();
|
|
|
|
// Make app globally available for debugging
|
|
window.SYSTEM_AWAKENING = app;
|
|
|
|
// Add global error handling
|
|
window.addEventListener('error', (event) => {
|
|
console.error('Global error caught:', event.error);
|
|
// Log to server in a real application
|
|
});
|
|
|
|
// Handle unhandled promise rejections
|
|
window.addEventListener('unhandledrejection', (event) => {
|
|
console.error('Unhandled promise rejection:', event.reason);
|
|
event.preventDefault();
|
|
});
|
|
|
|
console.log('SYSTEM AWAKENING application instance created');
|
|
}
|
|
|
|
// Start application when DOM is ready
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', startApplication);
|
|
} else {
|
|
startApplication();
|
|
}
|
|
|
|
// Export for module usage (if needed)
|
|
export { SystemAwakening }; |