// State Management const AppState = { currentImage: null, currentVideo: null, isGenerating: false, history: JSON.parse(localStorage.getItem('generationHistory') || '[]'), settings: { width: 1024, height: 1024, steps: 30, cfgScale: 7.5, seed: -1, motionStrength: 5, videoDuration: 4 } }; // Utility Functions const Utils = { generateId: () => Math.random().toString(36).substr(2, 9), async hashString(str) { const encoder = new TextEncoder(); const data = encoder.encode(str); const hashBuffer = await crypto.subtle.digest('SHA-256', data); const hashArray = Array.from(new Uint8Array(hashBuffer)); return hashArray.map(b => b.toString(16).padStart(2, '0')).join(''); }, getRandomSeed() { return Math.floor(Math.random() * 2147483647); }, formatDate(date) { return new Intl.DateTimeFormat('en-US', { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }).format(date); }, debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } }; // API Simulation (Mock) const APIService = { async generateImage(prompt, negativePrompt, settings) { // Simulate API delay await new Promise(resolve => setTimeout(resolve, 2000 + Math.random() * 2000)); // Generate deterministic seed from prompt for consistent demo results const seed = settings.seed > 0 ? settings.seed : Math.abs(Utils.hashString(prompt).split('').reduce((a,b)=>a+b.charCodeAt(0),0)); // Use static.photos with random category based on prompt content const categories = ['technology', 'abstract', 'nature', 'people', 'cityscape', 'minimal']; const category = categories[seed % categories.length]; const dimensions = settings.width > settings.height ? '1200x630' : settings.width < settings.height ? '640x360' : '1024x576'; return { id: Utils.generateId(), url: `http://static.photos/${category}/${dimensions}/${seed % 999}`, prompt: prompt, negativePrompt: negativePrompt, settings: {...settings}, timestamp: new Date(), seed: seed, type: 'image' }; }, async generateVideo(imageUrl, prompt, settings) { await new Promise(resolve => setTimeout(resolve, 3000 + Math.random() * 3000)); const seed = Utils.getRandomSeed(); return { id: Utils.generateId(), imageUrl: imageUrl, videoUrl: `http://static.photos/technology/640x360/${seed % 999}`, // Simulated video thumbnail prompt: prompt, settings: {...settings}, timestamp: new Date(), duration: settings.videoDuration || 4, type: 'video' }; } }; // UI Components Logic const UI = { showLoading(element, text = 'Generating...') { element.innerHTML = `

${text}

`; }, showError(element, message) { element.innerHTML = `

${message}

`; feather.replace(); }, createImageCard(item) { return `
${item.prompt}
${item.type === 'video' ? `
VIDEO
` : ''}

${item.prompt}

${Utils.formatDate(new Date(item.timestamp))} Seed: ${item.seed || 'N/A'}
`; } }; // Main Application Logic class DreamMachineApp { constructor() { this.controls = null; this.preview = null; this.init(); } init() { this.waitForComponents().then(() => { this.bindEvents(); this.loadHistory(); }); } async waitForComponents() { return new Promise((resolve) => { const check = () => { this.controls = document.querySelector('generator-controls'); this.preview = document.querySelector('generator-preview'); if (this.controls && this.preview) { resolve(); } else { setTimeout(check, 50); } }; check(); }); } bindEvents() { // Listen for custom events from web components document.addEventListener('generate-image', () => this.generateImage()); document.addEventListener('generate-video', () => this.generateVideoFromCurrent()); document.addEventListener('enhance-prompt', () => this.enhancePrompt()); document.addEventListener('ratio-change', (e) => this.setAspectRatio(e.detail.ratio)); // Settings changes from shadow DOM - use capture to catch all document.addEventListener('input', (e) => { if (e.target.hasAttribute('data-setting')) { const key = e.target.getAttribute('data-setting'); const value = e.target.type === 'checkbox' ? e.target.checked : (parseFloat(e.target.value) || e.target.value); AppState.settings[key] = value; } }, true); document.addEventListener('change', (e) => { if (e.target.hasAttribute('data-setting')) { const key = e.target.getAttribute('data-setting'); const value = e.target.type === 'checkbox' ? e.target.checked : (parseFloat(e.target.value) || e.target.value); AppState.settings[key] = value; } }, true); } setAspectRatio(ratio) { const ratios = { '1:1': [1024, 1024], '16:9': [1024, 576], '9:16': [576, 1024], '4:3': [1024, 768], '3:4': [768, 1024] }; const [w, h] = ratios[ratio] || ratios['1:1']; AppState.settings.width = w; AppState.settings.height = h; } async generateImage() { if (!this.controls || !this.preview) return; const prompt = this.controls.getPrompt(); if (!prompt.trim()) { // Visual feedback for empty prompt this.controls.shadowRoot.getElementById('prompt-input')?.classList.add('border-red-500'); setTimeout(() => { this.controls.shadowRoot.getElementById('prompt-input')?.classList.remove('border-red-500'); }, 2000); return; } const negativePrompt = this.controls.getNegativePrompt(); AppState.isGenerating = true; this.preview.setLoading(true, 'Generating Image...'); try { const result = await APIService.generateImage(prompt, negativePrompt, AppState.settings); AppState.currentImage = result; // Save to history AppState.history.unshift(result); localStorage.setItem('generationHistory', JSON.stringify(AppState.history)); this.renderPreview(result); this.updateGallery(); this.preview.showVideoControls(true); } catch (error) { this.preview.setContent(`

Generation failed. Please try again.

`); console.error('Generation error:', error); } finally { AppState.isGenerating = false; } } renderPreview(item) { if (!this.preview) return; const content = `
Generated
${item.width || 1024}x${item.height || 1024}
Prompt: ${item.prompt.substring(0, 100)}${item.prompt.length > 100 ? '...' : ''}
`; this.preview.setContent(content); } async generateVideoFromCurrent() { if (!AppState.currentImage || !this.preview) return; this.preview.setLoading(true, 'Generating Video... This may take a minute'); try { const result = await APIService.generateVideo( AppState.currentImage.url, AppState.currentImage.prompt + ', cinematic motion, smooth animation', AppState.settings ); AppState.currentVideo = result; // Update history AppState.history.unshift(result); localStorage.setItem('generationHistory', JSON.stringify(AppState.history)); this.renderVideoPreview(result); this.updateGallery(); } catch (error) { this.preview.setContent(`

Video generation failed.

`); } } renderVideoPreview(item) { if (!this.preview) return; const content = `
Video thumbnail
MP4 ${item.duration}s @ 24fps
`; this.preview.setContent(content); } animateImage(id) { const item = AppState.history.find(h => h.id === id); if (item && item.type === 'image') { AppState.currentImage = item; this.generateVideoFromCurrent(); } } downloadImage(url) { const a = document.createElement('a'); a.href = url; a.download = `dream-machine-${Date.now()}.png`; a.target = '_blank'; a.click(); } deleteItem(id) { AppState.history = AppState.history.filter(h => h.id !== id); localStorage.setItem('generationHistory', JSON.stringify(AppState.history)); this.updateGallery(); } updateGallery() { const gallery = document.querySelector('gallery-grid'); if (!gallery) return; gallery.updateCount(AppState.history.length); if (AppState.history.length === 0) { gallery.setContent(`

No generations yet

Your creations will be saved here automatically

`); } else { const cards = AppState.history.map(item => this.createImageCard(item)).join(''); gallery.setContent(cards); } } createImageCard(item) { const isVideo = item.type === 'video'; return `
${item.prompt}
${!isVideo ? `` : ''}
${isVideo ? `
VIDEO
` : ''}

${item.prompt}

${Utils.formatDate(new Date(item.timestamp))} Seed: ${item.seed || 'N/A'}
`; } loadHistory() { this.updateGallery(); } enhancePrompt() { if (!this.controls) return; const current = this.controls.getPrompt(); const enhancers = [ '8k resolution, photorealistic, highly detailed, professional photography', 'cinematic lighting, unreal engine 5, octane render', 'masterpiece, best quality, intricate details', 'trending on artstation, sharp focus, vivid colors' ]; const randomEnhancer = enhancers[Math.floor(Math.random() * enhancers.length)]; const newValue = current ? `${current}, ${randomEnhancer}` : randomEnhancer; this.controls.setPrompt(newValue); // Visual feedback const input = this.controls.shadowRoot.getElementById('prompt-input'); if (input) { input.style.boxShadow = '0 0 0 2px #06b6d4'; setTimeout(() => input.style.boxShadow = '', 500); } } clearHistory() { AppState.history = []; localStorage.removeItem('generationHistory'); this.updateGallery(); } } // Initialize const app = new DreamMachineApp(); // Expose to window for onclick handlers window.app = app;