/** * Animation Queue Module * Handles scheduling and executing animations with proper resource management * and synchronization with TTS */ import { BaseModule } from './base-module.js'; import { moduleRegistry } from './module-registry.js'; import { ModuleEvent } from './base-module.js'; // Add this import class AnimationQueueModule extends BaseModule { constructor() { super('animation-queue', 'Animation Queue'); // Queue of scheduled animations/functions this.queue = []; // Animation timing properties this.speed = 0.05; // Base animation speed (seconds per character) this.delay = 0; // Current accumulated delay // Module dependencies this.dependencies = ['tts']; this.tts = null; // TTS module reference // Fast-forwarding state this.isFastForwarding = false; // Bind methods this.schedule = this.schedule.bind(this); this.fastForward = this.fastForward.bind(this); this.clearAll = this.clearAll.bind(this); this.setSpeed = this.setSpeed.bind(this); } async waitForDependencies() { try { // Wait for TTS module to be available this.tts = moduleRegistry.getModule('tts'); if (!this.tts) { console.warn("TTS module not ready, Animation Queue will have limited functionality"); return true; // Continue anyway } return true; } catch (error) { console.error("Error waiting for Animation Queue dependencies:", error); return false; } } async initialize() { try { // Nothing special to initialize here this.reportProgress(100, "Animation Queue ready"); return true; } catch (error) { console.error("Error initializing Animation Queue:", error); return false; } } /** * Schedule a function to execute after a delay * @param {Function} func - Function to execute * @param {number} delay - Delay in milliseconds * @param {...any} args - Arguments to pass to the function * @returns {Object} - Timeout object that can be used to cancel */ schedule(func, delay, ...args) { if (typeof func !== 'function') { console.error('Animation Queue: Not a function passed to schedule'); return null; } // Create timeout object with execute method const timeoutObject = { execute: () => { try { func(...args); } catch (error) { console.error('Error executing scheduled function:', error); } }, timeoutId: null, createdAt: Date.now(), delay: delay }; // Apply speed factor to the delay const adjustedDelay = delay * this.speed; // Schedule execution timeoutObject.timeoutId = setTimeout(() => { // Execute the function timeoutObject.execute(); // Remove from queue const index = this.queue.indexOf(timeoutObject); if (index !== -1) { this.queue.splice(index, 1); } }, adjustedDelay); // Add to queue this.queue.push(timeoutObject); // Update current total delay this.delay = adjustedDelay + delay; return timeoutObject; } /** * Fast-forward all pending animations */ fastForward() { console.log(`Animation Queue: Fast-forwarding ${this.queue.length} pending items`); // Stop TTS if playing if (this.tts) { this.tts.stop(); } // Execute and clear all timeouts const queueCopy = [...this.queue]; // Make a copy to avoid modification during iteration queueCopy.forEach(timeoutObject => { // Clear timeout if (timeoutObject.timeoutId !== null) { clearTimeout(timeoutObject.timeoutId); } // Execute immediately timeoutObject.execute(); }); // Clear queue this.queue = []; // Reset delay this.delay = 0; // Use direct DOM event dispatch instead of this.dispatchEvent document.dispatchEvent(new CustomEvent('animations:fastForwarded', { detail: { moduleId: this.id } })); } /** * Clear all scheduled animations without executing them */ clearAll() { console.log(`Animation Queue: Clearing ${this.queue.length} pending items`); // Clear all timeouts this.queue.forEach(timeoutObject => { if (timeoutObject.timeoutId !== null) { clearTimeout(timeoutObject.timeoutId); } }); // Clear queue this.queue = []; // Reset delay this.delay = 0; } /** * Set the animation speed * @param {number} speed - Animation speed factor (lower is faster) */ setSpeed(speed) { if (typeof speed !== 'number' || speed <= 0) { console.error('Animation Queue: Invalid speed value'); return; } this.speed = speed; console.log(`Animation Queue: Speed set to ${speed}`); } /** * Get current queue length * @returns {number} - Number of items in the queue */ getQueueLength() { return this.queue.length; } /** * Get current accumulated delay * @returns {number} - Current delay in milliseconds */ getCurrentDelay() { return this.delay; } } // Create the singleton instance const AnimationQueue = new AnimationQueueModule(); // Register with the module registry moduleRegistry.register(AnimationQueue); // Export the module export { AnimationQueue }; // Keep a reference in window for loader system window.AnimationQueue = AnimationQueue;