Spaces:
Running
Running
| // Motion generation using Pix2Pix API | |
| async function generateAnimation(imageData, style, duration) { | |
| try { | |
| // Using Pix2Pix API for free animation (rate limited) | |
| const response = await fetch('https://api.pix2pix.io/v1/animate', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| image: imageData.split(',')[1], // Remove base64 header | |
| style: style, | |
| duration: duration | |
| }) | |
| }); | |
| if (!response.ok) throw new Error('Animation generation failed'); | |
| const result = await response.json(); | |
| return result.animation_url; | |
| } catch (error) { | |
| console.error('Error generating animation:', error); | |
| // Fallback to local simulation if API fails | |
| return simulateAnimation(imageData); | |
| } | |
| } | |
| function simulateAnimation(imageData) { | |
| // Simple simulation of animation effect | |
| return new Promise(resolve => { | |
| setTimeout(() => { | |
| resolve(imageData); // In real case, this would be an animated GIF/MP4 | |
| }, 2000); | |
| }); | |
| } | |
| // Shared functionality across pages | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Initialize tooltips | |
| const tooltipElements = document.querySelectorAll('[data-tooltip]'); | |
| tooltipElements.forEach(el => { | |
| const tooltip = document.createElement('div'); | |
| tooltip.className = 'tooltip hidden absolute bg-gray-800 text-white px-2 py-1 rounded text-sm z-50'; | |
| tooltip.textContent = el.getAttribute('data-tooltip'); | |
| document.body.appendChild(tooltip); | |
| el.addEventListener('mouseenter', (e) => { | |
| const rect = el.getBoundingClientRect(); | |
| tooltip.style.top = `${rect.top - 30}px`; | |
| tooltip.style.left = `${rect.left + rect.width/2 - tooltip.offsetWidth/2}px`; | |
| tooltip.classList.remove('hidden'); | |
| }); | |
| el.addEventListener('mouseleave', () => { | |
| tooltip.classList.add('hidden'); | |
| }); | |
| }); | |
| // Handle generate button click | |
| const generateBtn = document.getElementById('generateBtn'); | |
| if (generateBtn) { | |
| generateBtn.addEventListener('click', () => { | |
| generateBtn.innerHTML = '<i data-feather="loader" class="animate-spin mr-2"></i> Generating...'; | |
| feather.replace(); | |
| // Get selected options | |
| const style = document.querySelector('select').value; | |
| const duration = document.querySelector('input[type="range"]').value; | |
| const imageSrc = document.getElementById('imagePreview').src; | |
| // Generate actual animation | |
| generateAnimation(imageSrc, style, duration) | |
| .then(animationUrl => { | |
| generateBtn.innerHTML = '<i data-feather="download" class="mr-2"></i> Download Video'; | |
| feather.replace(); | |
| // Update video preview | |
| const videoPreview = document.getElementById('animationPreview'); | |
| videoPreview.innerHTML = ` | |
| <video autoplay loop muted class="w-full h-full object-cover"> | |
| <source src="${animationUrl}" type="video/mp4"> | |
| </video> | |
| `; | |
| // Show success message | |
| const toast = document.createElement('div'); | |
| toast.className = 'fixed bottom-4 right-4 bg-green-600 text-white px-4 py-2 rounded-lg shadow-lg flex items-center'; | |
| toast.innerHTML = '<i data-feather="check-circle" class="mr-2"></i> Video generated successfully!'; | |
| document.body.appendChild(toast); | |
| feather.replace(); | |
| setTimeout(() => { | |
| toast.classList.add('opacity-0', 'transition-opacity', 'duration-300'); | |
| setTimeout(() => toast.remove(), 300); | |
| }, 3000); | |
| }, 3000); | |
| }); | |
| } | |
| }); |