Download script.js from tedbeardk/testcomix-a-splashy-visual-narrative: direct link, hf CLI and curl.
- Browser
- Download file 10.6 kB
-
https://huggingface.co/spaces/tedbeardk/testcomix-a-splashy-visual-narrative/resolve/main/script.js
- Command line
-
hf download hf://spaces/tedbeardk/testcomix-a-splashy-visual-narrative/script.js
-
curl -L -o script.js https://huggingface.co/spaces/tedbeardk/testcomix-a-splashy-visual-narrative/resolve/main/script.js
10.6 kB
| // Main JavaScript for TestComix | |
| document.addEventListener('DOMContentLoaded', function() { | |
| // Initialize components | |
| initComicPanels(); | |
| initNextChapterButton(); | |
| initPanelInteractions(); | |
| // Add parallax effect to background | |
| initParallaxEffect(); | |
| // Initialize tooltips for icons (if any) | |
| initTooltips(); | |
| }); | |
| function initComicPanels() { | |
| const panels = document.querySelectorAll('.comic-panel'); | |
| panels.forEach((panel, index) => { | |
| // Add staggered entrance animation | |
| panel.style.opacity = '0'; | |
| panel.style.transform = 'translateY(30px)'; | |
| setTimeout(() => { | |
| panel.style.transition = 'opacity 0.8s ease, transform 0.8s ease'; | |
| panel.style.opacity = '1'; | |
| panel.style.transform = 'translateY(0)'; | |
| }, 200 * index); | |
| // Add click effect | |
| panel.addEventListener('click', function() { | |
| const panelNumber = this.getAttribute('data-panel'); | |
| showPanelDetails(panelNumber); | |
| }); | |
| }); | |
| } | |
| function showPanelDetails(panelNumber) { | |
| const panelTitles = { | |
| '1': 'THE DAWN', | |
| '2': 'THE CONVERGENCE', | |
| '3': 'THE BEYOND' | |
| }; | |
| const panelDescriptions = { | |
| '1': 'A breathtaking display of colors awakening from their digital slumber. This panel represents the beginning of our visual journey.', | |
| '2': 'The explosive meeting point of urban reality and digital fantasy. Watch as worlds collide in spectacular fashion.', | |
| '3': 'Venture into the unknown territories of imagination where anything is possible and every pixel tells a story.' | |
| }; | |
| // Create modal for panel details | |
| const modal = document.createElement('div'); | |
| modal.className = 'fixed inset-0 bg-black/80 flex items-center justify-center z-50 p-4'; | |
| modal.style.backdropFilter = 'blur(10px)'; | |
| modal.innerHTML = ` | |
| <div class="bg-gradient-to-br from-gray-900 to-gray-800 rounded-2xl max-w-2xl w-full border-2 border-electric-500/30 overflow-hidden"> | |
| <div class="p-6"> | |
| <div class="flex justify-between items-center mb-6"> | |
| <h3 class="text-3xl font-bold bg-gradient-to-r from-electric-300 to-neon-300 bg-clip-text text-transparent"> | |
| PANEL ${panelNumber}: ${panelTitles[panelNumber]} | |
| </h3> | |
| <button class="close-modal text-gray-400 hover:text-white transition-colors"> | |
| <i data-feather="x" class="w-6 h-6"></i> | |
| </button> | |
| </div> | |
| <div class="aspect-video rounded-lg overflow-hidden mb-6"> | |
| <img src="http://static.photos/${panelNumber === '1' ? 'gradient' : panelNumber === '2' ? 'cityscape' : 'abstract'}/1024x576/${panelNumber}0${panelNumber}" | |
| class="w-full h-full object-cover" | |
| alt="${panelTitles[panelNumber]}"> | |
| </div> | |
| <p class="text-gray-300 text-lg mb-6">${panelDescriptions[panelNumber]}</p> | |
| <div class="flex items-center justify-between"> | |
| <div class="flex space-x-2"> | |
| <span class="px-3 py-1 rounded-full bg-electric-500/20 text-electric-300 text-sm">Comic Art</span> | |
| <span class="px-3 py-1 rounded-full bg-neon-500/20 text-neon-300 text-sm">Digital</span> | |
| <span class="px-3 py-1 rounded-full bg-purple-500/20 text-purple-300 text-sm">${panelNumber === '1' ? 'Abstract' : panelNumber === '2' ? 'Urban' : 'Fantasy'}</span> | |
| </div> | |
| <button class="bg-gradient-to-r from-electric-500 to-neon-500 hover:from-electric-600 hover:to-neon-600 text-white font-medium py-2 px-6 rounded-full transition-all duration-300 transform hover:scale-105"> | |
| <i data-feather="download" class="w-4 h-4 inline-block mr-2"></i> | |
| Download Panel | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| `; | |
| document.body.appendChild(modal); | |
| // Replace feather icons in modal | |
| feather.replace(); | |
| // Close modal functionality | |
| const closeBtn = modal.querySelector('.close-modal'); | |
| closeBtn.addEventListener('click', () => { | |
| modal.style.opacity = '0'; | |
| setTimeout(() => { | |
| document.body.removeChild(modal); | |
| }, 300); | |
| }); | |
| // Close on background click | |
| modal.addEventListener('click', (e) => { | |
| if (e.target === modal) { | |
| modal.style.opacity = '0'; | |
| setTimeout(() => { | |
| document.body.removeChild(modal); | |
| }, 300); | |
| } | |
| }); | |
| // Animate modal entrance | |
| setTimeout(() => { | |
| modal.style.opacity = '1'; | |
| modal.style.transition = 'opacity 0.3s ease'; | |
| }, 10); | |
| } | |
| function initNextChapterButton() { | |
| const nextChapterBtn = document.getElementById('nextChapterBtn'); | |
| if (nextChapterBtn) { | |
| nextChapterBtn.addEventListener('click', function() { | |
| // Add click animation | |
| this.style.transform = 'scale(0.95)'; | |
| // Show loading state | |
| const originalText = this.innerHTML; | |
| this.innerHTML = '<span class="flex items-center justify-center"><i data-feather="loader" class="w-5 h-5 mr-2 animate-spin"></i>Loading Next Chapter...</span>'; | |
| feather.replace(); | |
| // Simulate loading | |
| setTimeout(() => { | |
| this.innerHTML = originalText; | |
| this.style.transform = 'scale(1)'; | |
| feather.replace(); | |
| // Show notification | |
| showNotification('Coming Soon: Chapter II! Stay tuned for more visual adventures.'); | |
| }, 1500); | |
| }); | |
| } | |
| } | |
| function initPanelInteractions() { | |
| // Add keyboard navigation | |
| document.addEventListener('keydown', (e) => { | |
| if (e.key === 'ArrowRight' || e.key === 'ArrowLeft') { | |
| const panels = document.querySelectorAll('.comic-panel'); | |
| const focusedPanel = document.querySelector('.comic-panel:focus'); | |
| if (focusedPanel) { | |
| const currentIndex = Array.from(panels).indexOf(focusedPanel); | |
| let nextIndex; | |
| if (e.key === 'ArrowRight') { | |
| nextIndex = (currentIndex + 1) % panels.length; | |
| } else { | |
| nextIndex = (currentIndex - 1 + panels.length) % panels.length; | |
| } | |
| panels[nextIndex].focus(); | |
| panels[nextIndex].scrollIntoView({ behavior: 'smooth', block: 'nearest' }); | |
| } | |
| } | |
| }); | |
| } | |
| function initParallaxEffect() { | |
| // Create subtle parallax effect on scroll | |
| const hero = document.querySelector('h1'); | |
| const panels = document.querySelectorAll('.comic-panel'); | |
| window.addEventListener('scroll', () => { | |
| const scrolled = window.pageYOffset; | |
| if (hero) { | |
| hero.style.transform = `translateY(${scrolled * 0.1}px)`; | |
| } | |
| panels.forEach((panel, index) => { | |
| const speed = 0.05 + (index * 0.02); | |
| panel.style.transform = `translateY(${scrolled * speed}px) scale(${1 - (scrolled * 0.0001)})`; | |
| }); | |
| }); | |
| } | |
| function initTooltips() { | |
| // Initialize tooltips for interactive elements | |
| const tooltipElements = document.querySelectorAll('[data-tooltip]'); | |
| tooltipElements.forEach(element => { | |
| element.addEventListener('mouseenter', (e) => { | |
| const tooltipText = e.target.getAttribute('data-tooltip'); | |
| const tooltip = document.createElement('div'); | |
| tooltip.className = 'absolute bg-gray-900 text-white text-sm px-3 py-2 rounded-lg shadow-xl z-50'; | |
| tooltip.textContent = tooltipText; | |
| const rect = e.target.getBoundingClientRect(); | |
| tooltip.style.top = `${rect.top - 40}px`; | |
| tooltip.style.left = `${rect.left + rect.width / 2}px`; | |
| tooltip.style.transform = 'translateX(-50%)'; | |
| document.body.appendChild(tooltip); | |
| e.target._tooltip = tooltip; | |
| }); | |
| element.addEventListener('mouseleave', (e) => { | |
| if (e.target._tooltip) { | |
| document.body.removeChild(e.target._tooltip); | |
| delete e.target._tooltip; | |
| } | |
| }); | |
| }); | |
| } | |
| function showNotification(message) { | |
| // Create notification element | |
| const notification = document.createElement('div'); | |
| notification.className = 'fixed top-4 right-4 bg-gradient-to-r from-electric-500 to-neon-500 text-white px-6 py-3 rounded-lg shadow-xl z-50 transform translate-x-full transition-transform duration-500'; | |
| notification.textContent = message; | |
| notification.innerHTML = ` | |
| <div class="flex items-center"> | |
| <i data-feather="bell" class="w-5 h-5 mr-3"></i> | |
| <span>${message}</span> | |
| </div> | |
| `; | |
| document.body.appendChild(notification); | |
| feather.replace(); | |
| // Animate in | |
| setTimeout(() => { | |
| notification.style.transform = 'translateX(0)'; | |
| }, 10); | |
| // Auto-remove after 5 seconds | |
| setTimeout(() => { | |
| notification.style.transform = 'translateX(100%)'; | |
| setTimeout(() => { | |
| document.body.removeChild(notification); | |
| }, 500); | |
| }, 5000); | |
| } | |
| // Utility function to check if element is in viewport | |
| function isElementInViewport(el) { | |
| const rect = el.getBoundingClientRect(); | |
| return ( | |
| rect.top >= 0 && | |
| rect.left >= 0 && | |
| rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && | |
| rect.right <= (window.innerWidth || document.documentElement.clientWidth) | |
| ); | |
| } | |
| // Add hover sound effect for panels (optional) | |
| function addHoverSoundEffect() { | |
| const panels = document.querySelectorAll('.comic-panel'); | |
| const hoverSound = new Audio('data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAZGF0YQQAAAAAAA=='); // Silent audio as placeholder | |
| panels.forEach(panel => { | |
| panel.addEventListener('mouseenter', () => { | |
| hoverSound.currentTime = 0; | |
| hoverSound.volume = 0.1; | |
| hoverSound.play().catch(e => console.log('Audio play failed:', e)); | |
| }); | |
| }); | |
| } |