Spaces:
Running
Running
Download script.js from dazman72/spingenius-pro: direct link, hf CLI and curl.
- Browser
- Download file 17.4 kB
-
https://huggingface.co/spaces/dazman72/spingenius-pro/resolve/main/script.js
- Command line
-
hf download hf://spaces/dazman72/spingenius-pro/script.js
-
curl -L -o script.js https://huggingface.co/spaces/dazman72/spingenius-pro/resolve/main/script.js
17.4 kB
| document.addEventListener('DOMContentLoaded', function() { | |
| // DOM Elements | |
| const spinner = document.getElementById('spinner'); | |
| const animationContainer = document.getElementById('animation-container'); | |
| const playBtn = document.getElementById('play-btn'); | |
| const spinnerType = document.getElementById('spinner-type'); | |
| const spinnerColor = document.getElementById('spinner-color'); | |
| const spinnerColor2 = document.getElementById('spinner-color-2'); | |
| const spinnerSize = document.getElementById('spinner-size'); | |
| const sizeValue = document.getElementById('size-value'); | |
| const spinnerSpeed = document.getElementById('spinner-speed'); | |
| const speedValue = document.getElementById('speed-value'); | |
| const animationStyle = document.getElementById('animation-style'); | |
| const customSvgUpload = document.getElementById('custom-svg-upload'); | |
| const svgUpload = document.getElementById('svg-upload'); | |
| const particleControls = document.getElementById('particle-controls'); | |
| const particleCount = document.getElementById('particle-count'); | |
| const particleSize = document.getElementById('particle-size'); | |
| // Export buttons | |
| const exportCssBtn = document.getElementById('export-css'); | |
| const exportHtmlBtn = document.getElementById('export-html'); | |
| const exportJsBtn = document.getElementById('export-js'); | |
| const exportReactBtn = document.getElementById('export-react'); | |
| const exportVueBtn = document.getElementById('export-vue'); | |
| const exportGifBtn = document.getElementById('export-gif'); | |
| const exportSvgBtn = document.getElementById('export-svg'); | |
| const exportLottieBtn = document.getElementById('export-lottie'); | |
| const animationCards = document.querySelectorAll('.animation-card'); | |
| // Current animation state | |
| let currentAnimation = 'circle'; | |
| let isPlaying = true; | |
| let customSvgPath = null; | |
| let animationTimeline = null; | |
| // Initialize | |
| updateSizeDisplay(); | |
| updateSpeedDisplay(); | |
| feather.replace(); | |
| // Setup Konva stage for advanced animations | |
| const stage = new Konva.Stage({ | |
| container: animationContainer, | |
| width: animationContainer.clientWidth, | |
| height: animationContainer.clientHeight | |
| }); | |
| const layer = new Konva.Layer(); | |
| stage.add(layer); | |
| // Event Listeners | |
| spinnerType.addEventListener('change', function() { | |
| updateSpinnerType(); | |
| toggleAdvancedControls(); | |
| }); | |
| spinnerColor.addEventListener('input', updateSpinnerColor); | |
| spinnerColor2.addEventListener('input', updateSpinnerColor); | |
| spinnerSize.addEventListener('input', updateSpinnerSize); | |
| spinnerSpeed.addEventListener('input', updateSpinnerSpeed); | |
| animationStyle.addEventListener('change', updateAnimationStyle); | |
| svgUpload.addEventListener('change', handleSvgUpload); | |
| particleCount.addEventListener('input', updateParticles); | |
| particleSize.addEventListener('input', updateParticles); | |
| playBtn.addEventListener('click', toggleAnimation); | |
| exportCssBtn.addEventListener('click', exportCSS); | |
| exportHtmlBtn.addEventListener('click', exportHTML); | |
| exportJsBtn.addEventListener('click', exportJS); | |
| exportReactBtn.addEventListener('click', exportReact); | |
| exportVueBtn.addEventListener('click', exportVue); | |
| exportGifBtn.addEventListener('click', exportGIF); | |
| exportSvgBtn.addEventListener('click', exportSVG); | |
| exportLottieBtn.addEventListener('click', exportLottie); | |
| // Add click events to gallery items | |
| animationCards.forEach(card => { | |
| card.addEventListener('click', function() { | |
| const type = this.getAttribute('data-type'); | |
| spinnerType.value = type; | |
| updateSpinnerType(); | |
| }); | |
| }); | |
| // Toggle advanced controls based on selected animation type | |
| function toggleAdvancedControls() { | |
| customSvgUpload.classList.add('hidden'); | |
| particleControls.classList.add('hidden'); | |
| if (currentAnimation === 'custom') { | |
| customSvgUpload.classList.remove('hidden'); | |
| } else if (currentAnimation === 'particles') { | |
| particleControls.classList.remove('hidden'); | |
| } | |
| } | |
| // Handle SVG upload | |
| function handleSvgUpload(e) { | |
| const file = e.target.files[0]; | |
| if (!file) return; | |
| const reader = new FileReader(); | |
| reader.onload = function(event) { | |
| customSvgPath = event.target.result; | |
| updateSpinnerType(); | |
| }; | |
| reader.readAsText(file); | |
| } | |
| // Update particle animation | |
| function updateParticles() { | |
| if (currentAnimation === 'particles') { | |
| updateSpinnerType(); | |
| } | |
| } | |
| // Update animation easing style | |
| function updateAnimationStyle() { | |
| if (animationTimeline) { | |
| animationTimeline.easing(animationStyle.value); | |
| } | |
| } | |
| // Main function to update spinner type | |
| function updateSpinnerType() { | |
| currentAnimation = spinnerType.value; | |
| animationContainer.innerHTML = ''; | |
| let newSpinner; | |
| switch(currentAnimation) { | |
| case 'circle': | |
| newSpinner = document.createElement('div'); | |
| newSpinner.className = 'rounded-full border-4 border-t-transparent animate-spin'; | |
| newSpinner.style.borderColor = spinnerColor.value; | |
| newSpinner.style.width = `${spinnerSize.value}px`; | |
| newSpinner.style.height = `${spinnerSize.value}px`; | |
| newSpinner.style.animationDuration = `${spinnerSpeed.value}s`; | |
| break; | |
| case 'dots': | |
| newSpinner = document.createElement('div'); | |
| newSpinner.className = 'flex gap-2 items-center'; | |
| for (let i = 0; i < 3; i++) { | |
| const dot = document.createElement('div'); | |
| dot.className = 'rounded-full animate-bounce'; | |
| dot.style.backgroundColor = spinnerColor.value; | |
| dot.style.width = `${spinnerSize.value/5}px`; | |
| dot.style.height = `${spinnerSize.value/5}px`; | |
| dot.style.animationDuration = `${spinnerSpeed.value}s`; | |
| dot.style.animationDelay = `${i * 0.2}s`; | |
| newSpinner.appendChild(dot); | |
| } | |
| break; | |
| case 'bar': | |
| newSpinner = document.createElement('div'); | |
| newSpinner.className = 'w-3/4 h-2 bg-gray-200 rounded-full overflow-hidden'; | |
| const innerBar = document.createElement('div'); | |
| innerBar.className = 'h-full rounded-full animate-progress'; | |
| innerBar.style.backgroundColor = spinnerColor.value; | |
| innerBar.style.animationDuration = `${spinnerSpeed.value}s`; | |
| newSpinner.appendChild(innerBar); | |
| break; | |
| case 'pulse': | |
| newSpinner = document.createElement('div'); | |
| newSpinner.className = 'rounded-full animate-pulse'; | |
| newSpinner.style.backgroundColor = spinnerColor.value; | |
| newSpinner.style.width = `${spinnerSize.value}px`; | |
| newSpinner.style.height = `${spinnerSize.value}px`; | |
| newSpinner.style.animationDuration = `${spinnerSpeed.value}s`; | |
| break; | |
| case 'bounce': | |
| newSpinner = document.createElement('div'); | |
| newSpinner.className = 'rounded-full animate-custom-bounce'; | |
| newSpinner.style.backgroundColor = spinnerColor.value; | |
| newSpinner.style.width = `${spinnerSize.value}px`; | |
| newSpinner.style.height = `${spinnerSize.value}px`; | |
| newSpinner.style.animationDuration = `${spinnerSpeed.value}s`; | |
| break; | |
| } | |
| animationContainer.appendChild(newSpinner); | |
| spinner = newSpinner; | |
| } | |
| function updateSpinnerColor() { | |
| const elements = animationContainer.querySelectorAll('div'); | |
| elements.forEach(el => { | |
| if (el.style.borderColor) { | |
| el.style.borderColor = spinnerColor.value; | |
| } | |
| if (el.style.backgroundColor) { | |
| el.style.backgroundColor = spinnerColor.value; | |
| } | |
| }); | |
| } | |
| function updateSpinnerSize() { | |
| sizeValue.textContent = spinnerSize.value; | |
| const elements = animationContainer.querySelectorAll('div'); | |
| elements.forEach(el => { | |
| if (currentAnimation === 'dots') { | |
| el.style.width = `${spinnerSize.value/5}px`; | |
| el.style.height = `${spinnerSize.value/5}px`; | |
| } else { | |
| if (el.style.width) el.style.width = `${spinnerSize.value}px`; | |
| if (el.style.height) el.style.height = `${spinnerSize.value}px`; | |
| } | |
| }); | |
| } | |
| function updateSpinnerSpeed() { | |
| speedValue.textContent = spinnerSpeed.value; | |
| const elements = animationContainer.querySelectorAll('div'); | |
| elements.forEach(el => { | |
| if (el.style.animationDuration) { | |
| el.style.animationDuration = `${spinnerSpeed.value}s`; | |
| } | |
| }); | |
| } | |
| function updateSizeDisplay() { | |
| sizeValue.textContent = spinnerSize.value; | |
| } | |
| function updateSpeedDisplay() { | |
| speedValue.textContent = spinnerSpeed.value; | |
| } | |
| function toggleAnimation() { | |
| const elements = animationContainer.querySelectorAll('div'); | |
| if (isPlaying) { | |
| elements.forEach(el => { | |
| el.style.animationPlayState = 'paused'; | |
| }); | |
| playBtn.innerHTML = '<i data-feather="play"></i> Play'; | |
| isPlaying = false; | |
| } else { | |
| elements.forEach(el => { | |
| el.style.animationPlayState = 'running'; | |
| }); | |
| playBtn.innerHTML = '<i data-feather="pause"></i> Pause'; | |
| isPlaying = true; | |
| } | |
| feather.replace(); | |
| } | |
| function createParticleAnimation() { | |
| layer.destroyChildren(); | |
| const count = parseInt(particleCount.value); | |
| const size = parseInt(particleSize.value); | |
| const centerX = stage.width() / 2; | |
| const centerY = stage.height() / 2; | |
| const radius = Math.min(stage.width(), stage.height()) * 0.3; | |
| const particles = []; | |
| for (let i = 0; i < count; i++) { | |
| const angle = (i / count) * Math.PI * 2; | |
| const x = centerX + Math.cos(angle) * radius; | |
| const y = centerY + Math.sin(angle) * radius; | |
| const particle = new Konva.Circle({ | |
| x: x, | |
| y: y, | |
| radius: size, | |
| fill: spinnerColor.value, | |
| opacity: 0.7 | |
| }); | |
| layer.add(particle); | |
| particles.push(particle); | |
| } | |
| animationTimeline = anime.timeline({ | |
| duration: parseInt(spinnerSpeed.value) * 1000, | |
| easing: animationStyle.value, | |
| loop: true | |
| }); | |
| particles.forEach((particle, i) => { | |
| const angle = (i / particles.length) * Math.PI * 2; | |
| animationTimeline.add({ | |
| targets: particle, | |
| x: centerX + Math.cos(angle + Math.PI) * radius, | |
| y: centerY + Math.sin(angle + Math.PI) * radius, | |
| fill: spinnerColor2.value, | |
| duration: parseInt(spinnerSpeed.value) * 1000, | |
| offset: 0 | |
| }); | |
| }); | |
| layer.draw(); | |
| } | |
| function exportCSS() { | |
| let cssCode = ''; | |
| switch(currentAnimation) { | |
| case 'circle': | |
| cssCode = `/* Circle Spinner */ | |
| .spinner { | |
| width: ${spinnerSize.value}px; | |
| height: ${spinnerSize.value}px; | |
| border: 4px solid ${spinnerColor.value}; | |
| border-top-color: transparent; | |
| border-radius: 50%; | |
| animation: spin ${spinnerSpeed.value}s linear infinite; | |
| } | |
| @keyframes spin { | |
| to { transform: rotate(360deg); } | |
| }`; | |
| break; | |
| case 'dots': | |
| cssCode = `/* Bouncing Dots */ | |
| .dots-container { | |
| display: flex; | |
| gap: 8px; | |
| align-items: center; | |
| } | |
| .dot { | |
| width: ${spinnerSize.value/5}px; | |
| height: ${spinnerSize.value/5}px; | |
| background-color: ${spinnerColor.value}; | |
| border-radius: 50%; | |
| animation: bounce ${spinnerSpeed.value}s infinite; | |
| } | |
| .dot:nth-child(2) { | |
| animation-delay: 0.2s; | |
| } | |
| .dot:nth-child(3) { | |
| animation-delay: 0.4s; | |
| } | |
| @keyframes bounce { | |
| 0%, 100% { transform: translateY(0); } | |
| 50% { transform: translateY(-15px); } | |
| }`; | |
| break; | |
| case 'bar': | |
| cssCode = `/* Progress Bar */ | |
| .progress-container { | |
| width: 75%; | |
| height: 8px; | |
| background-color: #e5e7eb; | |
| border-radius: 4px; | |
| overflow: hidden; | |
| } | |
| .progress-bar { | |
| height: 100%; | |
| background-color: ${spinnerColor.value}; | |
| border-radius: 4px; | |
| animation: progress ${spinnerSpeed.value}s ease-in-out infinite; | |
| } | |
| @keyframes progress { | |
| 0% { width: 0%; } | |
| 100% { width: 100%; } | |
| }`; | |
| break; | |
| case 'pulse': | |
| cssCode = `/* Pulse Animation */ | |
| .pulse { | |
| width: ${spinnerSize.value}px; | |
| height: ${spinnerSize.value}px; | |
| background-color: ${spinnerColor.value}; | |
| border-radius: 50%; | |
| animation: pulse ${spinnerSpeed.value}s cubic-bezier(0.4, 0, 0.6, 1) infinite; | |
| } | |
| @keyframes pulse { | |
| 0%, 100% { transform: scale(1); opacity: 1; } | |
| 50% { transform: scale(0.8); opacity: 0.5; } | |
| }`; | |
| break; | |
| case 'bounce': | |
| cssCode = `/* Bounce Animation */ | |
| .bounce { | |
| width: ${spinnerSize.value}px; | |
| height: ${spinnerSize.value}px; | |
| background-color: ${spinnerColor.value}; | |
| border-radius: 50%; | |
| animation: customBounce ${spinnerSpeed.value}s infinite; | |
| } | |
| @keyframes customBounce { | |
| 0%, 100% { transform: translateY(0) scale(1); } | |
| 25% { transform: translateY(-20px) scale(1.1); } | |
| 50% { transform: translateY(0) scale(1); } | |
| 75% { transform: translateY(-10px) scale(1.05); } | |
| }`; | |
| break; | |
| } | |
| // Create download link | |
| const blob = new Blob([cssCode], { type: 'text/css' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'spinner-animation.css'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| } | |
| function exportHTML() { | |
| let htmlCode = ''; | |
| switch(currentAnimation) { | |
| case 'circle': | |
| htmlCode = `<div class="spinner"></div>`; | |
| break; | |
| case 'dots': | |
| htmlCode = `<div class="dots-container"> | |
| <div class="dot"></div> | |
| <div class="dot"></div> | |
| <div class="dot"></div> | |
| </div>`; | |
| break; | |
| case 'bar': | |
| htmlCode = `<div class="progress-container"> | |
| <div class="progress-bar"></div> | |
| </div>`; | |
| break; | |
| case 'pulse': | |
| htmlCode = `<div class="pulse"></div>`; | |
| break; | |
| case 'bounce': | |
| htmlCode = `<div class="bounce"></div>`; | |
| break; | |
| } | |
| // Create download link | |
| const blob = new Blob([htmlCode], { type: 'text/html' }); | |
| const url = URL.createObjectURL(blob); | |
| const a = document.createElement('a'); | |
| a.href = url; | |
| a.download = 'spinner-animation.html'; | |
| document.body.appendChild(a); | |
| a.click(); | |
| document.body.removeChild(a); | |
| URL.revokeObjectURL(url); | |
| } | |
| function exportJS() { | |
| let jsCode = ''; | |
| // Generate JavaScript code for the animation | |
| // This would use the animation parameters to create a vanilla JS implementation | |
| alert('JavaScript export would generate code using the current animation parameters'); | |
| } | |
| function exportReact() { | |
| let reactCode = ''; | |
| // Generate React component code for the animation | |
| alert('React export would generate a React component with the current animation'); | |
| } | |
| function exportVue() { | |
| let vueCode = ''; | |
| // Generate Vue component code for the animation | |
| alert('Vue export would generate a Vue component with the current animation'); | |
| } | |
| function exportSVG() { | |
| // Generate SVG markup for the current animation | |
| alert('SVG export would generate SVG markup for the current animation'); | |
| } | |
| function exportLottie() { | |
| // Generate Lottie JSON for the current animation | |
| alert('Lottie export would generate JSON for use with Lottie/Bodymovin'); | |
| } | |
| function exportGIF() { | |
| // Use gif.js or similar library to capture frames and create GIF | |
| alert('GIF export would capture frames and generate an animated GIF'); | |
| } | |
| }); |