File size: 5,518 Bytes
ec18068 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | // --- CONFIGURATION & STATE ---
const config = {
localApiUrl: localStorage.getItem('motif_api_url') || null,
};
// --- DOM ELEMENTS ---
const modal = document.getElementById('guide-modal');
const showGuideBtn = document.getElementById('show-guide');
const closeModalBtn = document.querySelector('.close-modal');
const saveConnectionBtn = document.getElementById('save-connection');
const apiUrlInput = document.getElementById('api-url');
const navItems = document.querySelectorAll('.nav-item');
const sections = document.querySelectorAll('main section');
// --- STARTUP BEHAVIOR ---
document.addEventListener('DOMContentLoaded', () => {
// 1. Mandatory Setup Guide - Show popup if no API is saved
if (!config.localApiUrl) {
openModal();
} else {
apiUrlInput.value = config.localApiUrl;
}
// 2. Initialize Cool Cursor Trail Effect
initializeCursorTrail();
});
// --- UI / NAVIGATION HANDLERS ---
navItems.forEach(item => {
item.addEventListener('click', (e) => {
// Handle Sidebar active state
navItems.forEach(nav => nav.classList.remove('active'));
item.classList.add('active');
// Handle Main Section visibility (Scrolling effect control)
const targetSectionId = item.getAttribute('data-target');
sections.forEach(sec => sec.classList.remove('active-section'));
document.getElementById(targetSectionId).classList.add('active-section');
});
});
// --- MODAL / CONNECTION GUIDE LOGIC ---
function openModal() { modal.classList.add('active-modal'); }
function closeModal() { modal.classList.remove('active-modal'); }
showGuideBtn.addEventListener('click', openModal);
closeModalBtn.addEventListener('click', closeModal);
modal.addEventListener('click', (e) => {
// Close if clicking overlay area outside the content box
if (e.target === modal) closeModal();
});
saveConnectionBtn.addEventListener('click', () => {
const enteredUrl = apiUrlInput.value.trim();
if (enteredUrl) {
localStorage.setItem('motif_api_url', enteredUrl);
config.localApiUrl = enteredUrl;
closeModal();
alert(`Setup Complete! 🦄 Portal connected to backend at: ${enteredUrl}`);
} else {
alert('Please enter your local API address (e.g., http://localhost:7860)');
}
});
// --- COOL MOUSE EFFECTS (PASTEL CURSOR TRAIL) ---
function initializeCursorTrail() {
const trailContainer = document.getElementById('cursor-trail');
const dots = [];
const numDots = 12;
// Create dots with alternating pastel colors
for (let i = 0; i < numDots; i++) {
const dot = document.createElement('div');
dot.className = 'trail-dot';
dot.style.backgroundColor = getPastelColor(i);
trailContainer.appendChild(dot);
dots.push({ element: dot, x: 0, y: 0 });
}
let mouseX = 0, mouseY = 0;
window.addEventListener('mousemove', (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
});
// Animation loop for dots lagging smoothly behind cursor
function animateTrail() {
let x = mouseX;
let y = mouseY;
dots.forEach((dot, index) => {
const nextDot = dots[index + 1] || dots[0];
dot.x = x;
dot.y = y;
dot.element.style.left = x + 'px';
dot.element.style.top = y + 'px';
dot.element.style.opacity = 1 - (index / numDots); // Trail fades out
// Apply smooth lag effect
x += (nextDot.x - x) * 0.3;
y += (nextDot.y - y) * 0.3;
});
requestAnimationFrame(animateTrail);
}
animateTrail();
}
function getPastelColor(index) {
const colors = ['#ffe6d9', '#d6eaff', '#fbe0e6', '#e1f7f1']; // Peach, Blue, Pink, Mint
return colors[index % colors.length];
}
// --- GENERATION LOGIC (CONNECTION PLACEHOLDER) ---
const generateButtons = document.querySelectorAll('.generate-btn');
generateButtons.forEach(btn => {
btn.addEventListener('click', handleGeneration);
});
async function handleGeneration(e) {
if (!config.localApiUrl) {
alert("Wait! 🛑 To keep this portal unlimited and free, you must connect to your own powerful local computer first. Click 'Connection Guide'.");
openModal();
return;
}
const outputArea = document.getElementById('video-output');
// Add loading animation and swell effect
outputArea.innerHTML = '<span class="status-text">Connecting to local GPU...</span><div class="loading-spinner"></div>';
outputArea.closest('.animated-frame').classList.add('generating-active');
// PLACEHOLDER GENERATION SIMULATION
// In a real application, you would send a POST request to ${config.localApiUrl} here.
console.log(`Sending generation request to local backend: ${config.localApiUrl}`);
// Simulate backend processing time (4 seconds)
setTimeout(() => {
outputArea.innerHTML = ''; // Clear status spinner
// Use placeholder output from model card
const video = document.createElement('video');
video.src = 'https://huggingface.co/Motif-Technologies/Motif-Video-2B/resolve/main/assets/banner.mp4';
video.autoplay = true;
video.loop = true;
video.controls = true;
video.style.width = '100%';
outputArea.appendChild(video);
outputArea.closest('.animated-frame').classList.remove('generating-active');
}, 4000);
} |