|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>AvatarSync Studio - Create Animated Avatars</title> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<script src="https://unpkg.com/feather-icons"></script> |
|
|
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> |
|
|
<script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.globe.min.js"></script> |
|
|
<style> |
|
|
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap'); |
|
|
|
|
|
body { |
|
|
font-family: 'Poppins', sans-serif; |
|
|
overflow-x: hidden; |
|
|
} |
|
|
|
|
|
.dropzone { |
|
|
border: 2px dashed #9CA3AF; |
|
|
transition: all 0.3s ease; |
|
|
} |
|
|
|
|
|
.dropzone.active { |
|
|
border-color: #4F46E5; |
|
|
background-color: rgba(79, 70, 229, 0.05); |
|
|
} |
|
|
|
|
|
.theme-selector input:checked + label { |
|
|
border-color: #4F46E5; |
|
|
box-shadow: 0 0 0 3px rgba(79, 70, 229, 0.2); |
|
|
} |
|
|
|
|
|
.color-picker { |
|
|
-webkit-appearance: none; |
|
|
-moz-appearance: none; |
|
|
appearance: none; |
|
|
width: 40px; |
|
|
height: 40px; |
|
|
border: none; |
|
|
cursor: pointer; |
|
|
border-radius: 50%; |
|
|
padding: 0; |
|
|
} |
|
|
|
|
|
.color-picker::-webkit-color-swatch { |
|
|
border-radius: 50%; |
|
|
border: 2px solid white; |
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); |
|
|
} |
|
|
|
|
|
#previewCanvas { |
|
|
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); |
|
|
border-radius: 12px; |
|
|
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1); |
|
|
} |
|
|
|
|
|
.animation-preview { |
|
|
transition: all 0.5s cubic-bezier(0.68, -0.6, 0.32, 1.6); |
|
|
} |
|
|
|
|
|
.animation-preview:hover { |
|
|
transform: scale(1.05); |
|
|
} |
|
|
|
|
|
.tooltip { |
|
|
visibility: hidden; |
|
|
opacity: 0; |
|
|
transition: opacity 0.3s; |
|
|
} |
|
|
|
|
|
.has-tooltip:hover .tooltip { |
|
|
visibility: visible; |
|
|
opacity: 1; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-50 min-h-screen"> |
|
|
|
|
|
<div id="vanta-bg" class="fixed top-0 left-0 w-full h-full -z-10"></div> |
|
|
|
|
|
|
|
|
<div class="container mx-auto px-4 py-12 max-w-6xl"> |
|
|
|
|
|
<header class="text-center mb-12"> |
|
|
<h1 class="text-4xl md:text-5xl font-bold text-gray-800 mb-2">AvatarSync Studio</h1> |
|
|
<p class="text-lg text-gray-600 max-w-2xl mx-auto">Transform your image and audio into a personalized animated avatar with synchronized movements</p> |
|
|
<div class="flex justify-center mt-4"> |
|
|
<div class="w-16 h-1 bg-indigo-500 rounded-full"></div> |
|
|
</div> |
|
|
</header> |
|
|
|
|
|
|
|
|
<div class="bg-white rounded-xl shadow-xl overflow-hidden mb-12"> |
|
|
|
|
|
<div class="flex justify-between items-center px-8 py-4 border-b"> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<div class="w-8 h-8 rounded-full bg-indigo-500 text-white flex items-center justify-center">1</div> |
|
|
<span class="font-medium text-indigo-600">Upload Media</span> |
|
|
</div> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<div class="w-8 h-8 rounded-full bg-gray-200 text-gray-600 flex items-center justify-center">2</div> |
|
|
<span class="font-medium text-gray-500">Customize</span> |
|
|
</div> |
|
|
<div class="flex items-center space-x-2"> |
|
|
<div class="w-8 h-8 rounded-full bg-gray-200 text-gray-600 flex items-center justify-center">3</div> |
|
|
<span class="font-medium text-gray-500">Generate</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="p-8"> |
|
|
|
|
|
<div id="step1" class=""> |
|
|
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Upload Your Media</h2> |
|
|
|
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8"> |
|
|
|
|
|
<div class="space-y-4"> |
|
|
<h3 class="text-lg font-medium text-gray-700 flex items-center"> |
|
|
<i data-feather="image" class="mr-2"></i> Avatar Image |
|
|
</h3> |
|
|
<div class="dropzone rounded-lg p-8 text-center cursor-pointer" id="imageDropzone"> |
|
|
<i data-feather="upload" class="w-12 h-12 mx-auto text-gray-400 mb-3"></i> |
|
|
<p class="text-gray-500 mb-2">Drag & drop your image here</p> |
|
|
<p class="text-sm text-gray-400">or click to browse files</p> |
|
|
<input type="file" id="imageInput" accept="image/*" class="hidden"> |
|
|
</div> |
|
|
<div class="flex justify-center"> |
|
|
<button id="clearImageBtn" class="text-sm text-gray-500 hover:text-gray-700 flex items-center" disabled> |
|
|
<i data-feather="trash-2" class="w-4 h-4 mr-1"></i> Clear |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="space-y-4"> |
|
|
<h3 class="text-lg font-medium text-gray-700 flex items-center"> |
|
|
<i data-feather="music" class="mr-2"></i> Audio Track |
|
|
</h3> |
|
|
<div class="dropzone rounded-lg p-8 text-center cursor-pointer" id="audioDropzone"> |
|
|
<i data-feather="upload" class="w-12 h-12 mx-auto text-gray-400 mb-3"></i> |
|
|
<p class="text-gray-500 mb-2">Drag & drop your audio file here</p> |
|
|
<p class="text-sm text-gray-400">or click to browse files</p> |
|
|
<input type="file" id="audioInput" accept="audio/*" class="hidden"> |
|
|
</div> |
|
|
<div class="flex justify-center"> |
|
|
<button id="clearAudioBtn" class="text-sm text-gray-500 hover:text-gray-700 flex items-center" disabled> |
|
|
<i data-feather="trash-2" class="w-4 h-4 mr-1"></i> Clear |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="flex justify-end"> |
|
|
<button id="nextStep1Btn" class="bg-indigo-500 hover:bg-indigo-600 text-white px-6 py-2 rounded-lg flex items-center disabled:opacity-50" disabled> |
|
|
Next <i data-feather="arrow-right" class="w-4 h-4 ml-2"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="step2" class="hidden"> |
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8"> |
|
|
|
|
|
<div class="lg:col-span-2"> |
|
|
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Customize Your Animation</h2> |
|
|
|
|
|
<div class="bg-gray-100 rounded-xl p-4 mb-6"> |
|
|
<canvas id="previewCanvas" class="w-full h-64 md:h-96 mx-auto"></canvas> |
|
|
</div> |
|
|
|
|
|
<div class="bg-gray-100 rounded-xl p-4"> |
|
|
<div class="flex items-center justify-between mb-2"> |
|
|
<span class="text-gray-700">Audio Timeline</span> |
|
|
<button id="playPauseBtn" class="text-indigo-500 hover:text-indigo-700"> |
|
|
<i data-feather="play" class="w-5 h-5"></i> |
|
|
</button> |
|
|
</div> |
|
|
<div class="relative h-2 bg-gray-300 rounded-full"> |
|
|
<div id="progressBar" class="absolute top-0 left-0 h-full bg-indigo-500 rounded-full" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div> |
|
|
<h3 class="text-xl font-semibold text-gray-800 mb-4">Customization</h3> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<h4 class="text-sm font-medium text-gray-700 uppercase tracking-wider mb-3">Color Scheme</h4> |
|
|
<div class="grid grid-cols-2 gap-4"> |
|
|
<div> |
|
|
<label class="block text-sm text-gray-600 mb-1">Primary Color</label> |
|
|
<input type="color" class="color-picker" value="#4F46E5" id="primaryColor"> |
|
|
</div> |
|
|
<div> |
|
|
<label class="block text-sm text-gray-600 mb-1">Secondary Color</label> |
|
|
<input type="color" class="color-picker" value="#EC4899" id="secondaryColor"> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<h4 class="text-sm font-medium text-gray-700 uppercase tracking-wider mb-3">Theme Style</h4> |
|
|
<div class="grid grid-cols-3 gap-2"> |
|
|
<div> |
|
|
<input type="radio" name="theme" id="theme-light" value="light" class="hidden" checked> |
|
|
<label for="theme-light" class="theme-selector block p-2 border rounded-lg cursor-pointer text-center"> |
|
|
<div class="w-full h-16 bg-gradient-to-br from-gray-100 to-gray-200 rounded-md mb-1"></div> |
|
|
<span class="text-xs">Light</span> |
|
|
</label> |
|
|
</div> |
|
|
<div> |
|
|
<input type="radio" name="theme" id="theme-dark" value="dark" class="hidden"> |
|
|
<label for="theme-dark" class="theme-selector block p-2 border rounded-lg cursor-pointer text-center"> |
|
|
<div class="w-full h-16 bg-gradient-to-br from-gray-800 to-gray-900 rounded-md mb-1"></div> |
|
|
<span class="text-xs">Dark</span> |
|
|
</label> |
|
|
</div> |
|
|
<div> |
|
|
<input type="radio" name="theme" id="theme-neon" value="neon" class="hidden"> |
|
|
<label for="theme-neon" class="theme-selector block p-2 border rounded-lg cursor-pointer text-center"> |
|
|
<div class="w-full h-16 bg-gradient-to-br from-purple-900 to-pink-600 rounded-md mb-1"></div> |
|
|
<span class="text-xs">Neon</span> |
|
|
</label> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<h4 class="text-sm font-medium text-gray-700 uppercase tracking-wider mb-3">Animation Style</h4> |
|
|
<select class="w-full px-3 py-2 text-gray-700 bg-gray-100 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-indigo-500"> |
|
|
<option>3D Cartoon</option> |
|
|
<option>2D Minimal</option> |
|
|
<option>Realistic</option> |
|
|
<option>Anime Style</option> |
|
|
<option>Pixel Art</option> |
|
|
</select> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<h4 class="text-sm font-medium text-gray-700 uppercase tracking-wider mb-3">Motion Intensity</h4> |
|
|
<input type="range" min="0" max="100" value="50" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer" id="motionRange"> |
|
|
<div class="flex justify-between text-xs text-gray-500 mt-1"> |
|
|
<span>Subtle</span> |
|
|
<span>Dynamic</span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-6"> |
|
|
<h4 class="text-sm font-medium text-gray-700 uppercase tracking-wider mb-3">Sync Options</h4> |
|
|
<div class="space-y-2"> |
|
|
<label class="flex items-center space-x-2"> |
|
|
<input type="checkbox" class="rounded text-indigo-500" checked> |
|
|
<span>Sync to Beat</span> |
|
|
</label> |
|
|
<label class="flex items-center space-x-2"> |
|
|
<input type="checkbox" class="rounded text-indigo-500" checked> |
|
|
<span>Lip Sync</span> |
|
|
</label> |
|
|
<label class="flex items-center space-x-2"> |
|
|
<input type="checkbox" class="rounded text-indigo-500"> |
|
|
<span>Head Movement</span> |
|
|
</label> |
|
|
<label class="flex items-center space-x-2"> |
|
|
<input type="checkbox" class="rounded text-indigo-500" checked> |
|
|
<span>Hand Gestures</span> |
|
|
</label> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="flex justify-between"> |
|
|
<button id="backStep2Btn" class="text-gray-600 hover:text-gray-800 px-4 py-2 rounded-lg flex items-center"> |
|
|
<i data-feather="arrow-left" class="w-4 h-4 mr-2"></i> Back |
|
|
</button> |
|
|
<button id="nextStep2Btn" class="bg-indigo-500 hover:bg-indigo-600 text-white px-6 py-2 rounded-lg flex items-center"> |
|
|
Next <i data-feather="arrow-right" class="w-4 h-4 ml-2"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="step3" class="hidden"> |
|
|
<h2 class="text-2xl font-semibold text-gray-800 mb-6">Generate Your Animated Avatar</h2> |
|
|
|
|
|
<div class="bg-gray-100 rounded-xl p-8 text-center mb-8"> |
|
|
<div id="processingAnimation" class="flex justify-center mb-4"> |
|
|
<div class="w-16 h-16 border-4 border-indigo-500 border-t-transparent rounded-full animate-spin"></div> |
|
|
</div> |
|
|
<h3 class="text-xl font-medium text-gray-800 mb-2">Processing Your Animation</h3> |
|
|
<p class="text-gray-600 max-w-md mx-auto">We're synchronizing your avatar with the audio and applying your customizations. This may take a few moments.</p> |
|
|
<div class="w-full bg-gray-300 rounded-full h-2.5 mt-6"> |
|
|
<div id="progressBar" class="bg-indigo-600 h-2.5 rounded-full" style="width: 0%"></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div id="resultSection" class="hidden"> |
|
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mb-8"> |
|
|
<div class="bg-gray-100 rounded-xl p-4"> |
|
|
<h3 class="text-lg font-medium text-gray-700 mb-3">Preview</h3> |
|
|
<div class="animation-preview bg-white rounded-lg overflow-hidden shadow-md"> |
|
|
<video id="resultVideo" class="w-full" controls></video> |
|
|
</div> |
|
|
</div> |
|
|
<div class="space-y-6"> |
|
|
<div> |
|
|
<h3 class="text-lg font-medium text-gray-700 mb-3">Export Options</h3> |
|
|
<div class="grid grid-cols-2 gap-4"> |
|
|
<button class="bg-gray-200 hover:bg-gray-300 text-gray-800 py-3 rounded-lg flex flex-col items-center justify-center"> |
|
|
<i data-feather="download" class="w-6 h-6 mb-2"></i> |
|
|
<span>Download Video</span> |
|
|
</button> |
|
|
<button class="bg-gray-200 hover:bg-gray-300 text-gray-800 py-3 rounded-lg flex flex-col items-center justify-center"> |
|
|
<i data-feather="image" class="w-6 h-6 mb-2"></i> |
|
|
<span>Download GIF</span> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<h3 class="text-lg font-medium text-gray-700 mb-3">Share</h3> |
|
|
<div class="flex space-x-3"> |
|
|
<button class="bg-blue-500 hover:bg-blue-600 text-white p-3 rounded-full"> |
|
|
<i data-feather="facebook" class="w-5 h-5"></i> |
|
|
</button> |
|
|
<button class="bg-pink-500 hover:bg-pink-600 text-white p-3 rounded-full"> |
|
|
<i data-feather="instagram" class="w-5 h-5"></i> |
|
|
</button> |
|
|
<button class="bg-blue-400 hover:bg-blue-500 text-white p-3 rounded-full"> |
|
|
<i data-feather="twitter" class="w-5 h-5"></i> |
|
|
</button> |
|
|
<button class="bg-gray-800 hover:bg-gray-900 text-white p-3 rounded-full"> |
|
|
<i data-feather="share-2" class="w-5 h-5"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div> |
|
|
<h3 class="text-lg font-medium text-gray-700 mb-3">Save Project</h3> |
|
|
<div class="flex items-center space-x-4"> |
|
|
<input type="text" placeholder="Project Name" class="flex-1 px-4 py-2 border rounded-lg focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"> |
|
|
<button class="bg-indigo-500 hover:bg-indigo-600 text-white px-4 py-2 rounded-lg"> |
|
|
Save |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
<div class="flex justify-center space-x-4"> |
|
|
<button id="newProjectBtn" class="bg-white border border-indigo-500 text-indigo-500 hover:bg-indigo-50 px-6 py-2 rounded-lg flex items-center"> |
|
|
<i data-feather="plus" class="w-4 h-4 mr-2"></i> Create New |
|
|
</button> |
|
|
<button id="helpBtn" class="bg-indigo-500 hover:bg-indigo-600 text-white px-6 py-2 rounded-lg flex items-center"> |
|
|
<i data-feather="help-circle" class="w-4 h-4 mr-2"></i> How to Use |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="mb-16"> |
|
|
<h2 class="text-2xl font-semibold text-gray-800 text-center mb-8">Features</h2> |
|
|
<div class="grid grid-cols-1 md:grid-cols-3 gap-8"> |
|
|
<div class="bg-white p-6 rounded-xl shadow-md hover:shadow-lg transition-shadow"> |
|
|
<div class="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-4"> |
|
|
<i data-feather="sliders" class="text-indigo-500 w-6 h-6"></i> |
|
|
</div> |
|
|
<h3 class="text-lg font-medium text-gray-800 mb-2">Advanced Customization</h3> |
|
|
<p class="text-gray-600">Fine-tune colors, themes, and animation styles to match your brand or personal style.</p> |
|
|
</div> |
|
|
<div class="bg-white p-6 rounded-xl shadow-md hover:shadow-lg transition-shadow"> |
|
|
<div class="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-4"> |
|
|
<i data-feather="zap" class="text-indigo-500 w-6 h-6"></i> |
|
|
</div> |
|
|
<h3 class="text-lg font-medium text-gray-800 mb-2">Real-time Sync</h3> |
|
|
<p class="text-gray-600">Perfect synchronization between audio and avatar movements for natural-looking animations.</p> |
|
|
</div> |
|
|
<div class="bg-white p-6 rounded-xl shadow-md hover:shadow-lg transition-shadow"> |
|
|
<div class="w-12 h-12 bg-indigo-100 rounded-lg flex items-center justify-center mb-4"> |
|
|
<i data-feather="download" class="text-indigo-500 w-6 h-6"></i> |
|
|
</div> |
|
|
<h3 class="text-lg font-medium text-gray-800 mb-2">Multiple Formats</h3> |
|
|
<p class="text-gray-600">Export as high-quality video or GIF for use on any platform or device.</p> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<footer class="text-center text-gray-600 text-sm"> |
|
|
<p>© 2023 AvatarSync Studio. All rights reserved.</p> |
|
|
<p class="mt-1">Made with <i data-feather="heart" class="w-4 h-4 inline text-red-500"></i> for content creators</p> |
|
|
</footer> |
|
|
</div> |
|
|
|
|
|
<script> |
|
|
|
|
|
VANTA.GLOBE({ |
|
|
el: "#vanta-bg", |
|
|
mouseControls: true, |
|
|
touchControls: true, |
|
|
gyroControls: false, |
|
|
minHeight: 200.00, |
|
|
minWidth: 200.00, |
|
|
scale: 1.00, |
|
|
scaleMobile: 1.00, |
|
|
color: 0x4f46e5, |
|
|
backgroundColor: 0xf5f7fa, |
|
|
size: 0.8 |
|
|
}); |
|
|
|
|
|
|
|
|
feather.replace(); |
|
|
|
|
|
|
|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
const imageDropzone = document.getElementById('imageDropzone'); |
|
|
const audioDropzone = document.getElementById('audioDropzone'); |
|
|
const imageInput = document.getElementById('imageInput'); |
|
|
const audioInput = document.getElementById('audioInput'); |
|
|
const clearImageBtn = document.getElementById('clearImageBtn'); |
|
|
const clearAudioBtn = document.getElementById('clearAudioBtn'); |
|
|
const nextStep1Btn = document.getElementById('nextStep1Btn'); |
|
|
|
|
|
let hasImage = false; |
|
|
let hasAudio = false; |
|
|
|
|
|
|
|
|
imageDropzone.addEventListener('click', () => imageInput.click()); |
|
|
imageInput.addEventListener('change', handleImageFile); |
|
|
|
|
|
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { |
|
|
imageDropzone.addEventListener(eventName, preventDefaults, false); |
|
|
}); |
|
|
|
|
|
['dragenter', 'dragover'].forEach(eventName => { |
|
|
imageDropzone.addEventListener(eventName, highlightImage, false); |
|
|
}); |
|
|
|
|
|
['dragleave', 'drop'].forEach(eventName => { |
|
|
imageDropzone.addEventListener(eventName, unhighlightImage, false); |
|
|
}); |
|
|
|
|
|
imageDropzone.addEventListener('drop', handleImageDrop, false); |
|
|
|
|
|
|
|
|
audioDropzone.addEventListener('click', () => audioInput.click()); |
|
|
audioInput.addEventListener('change', handleAudioFile); |
|
|
|
|
|
['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => { |
|
|
audioDropzone.addEventListener(eventName, preventDefaults, false); |
|
|
}); |
|
|
|
|
|
['dragenter', 'dragover'].forEach(eventName => { |
|
|
audioDropzone.addEventListener(eventName, highlightAudio, false); |
|
|
}); |
|
|
|
|
|
['dragleave', 'drop'].forEach(eventName => { |
|
|
audioDropzone.addEventListener(eventName, unhighlightAudio, false); |
|
|
}); |
|
|
|
|
|
audioDropzone.addEventListener('drop', handleAudioDrop, false); |
|
|
|
|
|
|
|
|
clearImageBtn.addEventListener('click', clearImage); |
|
|
clearAudioBtn.addEventListener('click', clearAudio); |
|
|
|
|
|
nextStep1Btn.addEventListener('click', goToStep2); |
|
|
document.getElementById('backStep2Btn').addEventListener('click', goToStep1); |
|
|
document.getElementById('nextStep2Btn').addEventListener('click', goToStep3); |
|
|
document.getElementById('newProjectBtn').addEventListener('click', resetAll); |
|
|
document.getElementById('helpBtn').addEventListener('click', showHelp); |
|
|
function preventDefaults(e) { |
|
|
e.preventDefault(); |
|
|
e.stopPropagation(); |
|
|
} |
|
|
|
|
|
function highlightImage() { |
|
|
imageDropzone.classList.add('active'); |
|
|
} |
|
|
|
|
|
function unhighlightImage() { |
|
|
imageDropzone.classList.remove('active'); |
|
|
} |
|
|
|
|
|
function highlightAudio() { |
|
|
audioDropzone.classList.add('active'); |
|
|
} |
|
|
|
|
|
function unhighlightAudio() { |
|
|
audioDropzone.classList.remove('active'); |
|
|
} |
|
|
|
|
|
function handleImageDrop(e) { |
|
|
const dt = e.dataTransfer; |
|
|
const file = dt.files[0]; |
|
|
handleImageFile({ target: { files: [file] } }); |
|
|
} |
|
|
|
|
|
function handleAudioDrop(e) { |
|
|
const dt = e.dataTransfer; |
|
|
const file = dt.files[0]; |
|
|
handleAudioFile({ target: { files: [file] } }); |
|
|
} |
|
|
|
|
|
function handleImageFile(e) { |
|
|
const file = e.target.files[0]; |
|
|
if (file && file.type.match('image.*')) { |
|
|
const reader = new FileReader(); |
|
|
|
|
|
reader.onload = function(e) { |
|
|
imageDropzone.innerHTML = ` |
|
|
<div class="flex flex-col items-center"> |
|
|
<img src="${e.target.result}" class="h-32 object-contain mb-2" alt="Preview"> |
|
|
<p class="text-sm text-gray-600">${file.name}</p> |
|
|
</div> |
|
|
`; |
|
|
hasImage = true; |
|
|
clearImageBtn.disabled = false; |
|
|
checkNextButton(); |
|
|
}; |
|
|
|
|
|
reader.readAsDataURL(file); |
|
|
} |
|
|
} |
|
|
|
|
|
function handleAudioFile(e) { |
|
|
const file = e.target.files[0]; |
|
|
if (file && file.type.match('audio.*')) { |
|
|
const reader = new FileReader(); |
|
|
|
|
|
reader.onload = function(e) { |
|
|
audioDropzone.innerHTML = ` |
|
|
<div class="flex flex-col items-center"> |
|
|
<i data-feather="music" class="w-12 h-12 mx-auto text-indigo-400 mb-3"></i> |
|
|
<p class="text-sm text-gray-600 truncate w-full">${file.name}</p> |
|
|
</div> |
|
|
`; |
|
|
feather.replace(); |
|
|
hasAudio = true; |
|
|
clearAudioBtn.disabled = false; |
|
|
checkNextButton(); |
|
|
}; |
|
|
|
|
|
reader.readAsDataURL(file); |
|
|
} |
|
|
} |
|
|
|
|
|
function clearImage() { |
|
|
imageDropzone.innerHTML = ` |
|
|
<i data-feather="upload" class="w-12 h-12 mx-auto text-gray-400 mb-3"></i> |
|
|
<p class="text-gray-500 mb-2">Drag & drop your image here</p> |
|
|
<p class="text-sm text-gray-400">or click to browse files</p> |
|
|
`; |
|
|
feather.replace(); |
|
|
imageInput.value = ''; |
|
|
hasImage = false; |
|
|
clearImageBtn.disabled = true; |
|
|
checkNextButton(); |
|
|
} |
|
|
|
|
|
function clearAudio() { |
|
|
audioDropzone.innerHTML = ` |
|
|
<i data-feather="upload" class="w-12 h-12 mx-auto text-gray-400 mb-3"></i> |
|
|
<p class="text-gray-500 mb-2">Drag & drop your audio file here</p> |
|
|
<p class="text-sm text-gray-400">or click to browse files</p> |
|
|
`; |
|
|
feather.replace(); |
|
|
audioInput.value = ''; |
|
|
hasAudio = false; |
|
|
clearAudioBtn.disabled = true; |
|
|
checkNextButton(); |
|
|
} |
|
|
|
|
|
function checkNextButton() { |
|
|
nextStep1Btn.disabled = !(hasImage && hasAudio); |
|
|
} |
|
|
|
|
|
function goToStep2() { |
|
|
document.getElementById('step1').classList.add('hidden'); |
|
|
document.getElementById('step2').classList.remove('hidden'); |
|
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
const canvas = document.getElementById('previewCanvas'); |
|
|
const ctx = canvas.getContext('2d'); |
|
|
|
|
|
|
|
|
canvas.width = canvas.offsetWidth; |
|
|
canvas.height = canvas.offsetHeight; |
|
|
|
|
|
|
|
|
ctx.fillStyle = '#4F46E5'; |
|
|
ctx.beginPath(); |
|
|
ctx.arc(canvas.width/2, canvas.height/2, 80, 0, Math.PI * 2); |
|
|
ctx.fill(); |
|
|
|
|
|
ctx.fillStyle = '#ffffff'; |
|
|
ctx.beginPath(); |
|
|
ctx.arc(canvas.width/2 - 30, canvas.height/2 - 20, 10, 0, Math.PI * 2); |
|
|
ctx.arc(canvas.width/2 + 30, canvas.height/2 - 20, 10, 0, Math.PI * 2); |
|
|
ctx.fill(); |
|
|
|
|
|
ctx.beginPath(); |
|
|
ctx.arc(canvas.width/2, canvas.height/2 + 20, 30, 0, Math.PI); |
|
|
ctx.strokeStyle = '#ffffff'; |
|
|
ctx.lineWidth = 3; |
|
|
ctx.stroke(); |
|
|
}, 300); |
|
|
} |
|
|
|
|
|
function goToStep1() { |
|
|
document.getElementById('step2').classList.add('hidden'); |
|
|
document.getElementById('step1').classList.remove('hidden'); |
|
|
} |
|
|
|
|
|
function goToStep3() { |
|
|
document.getElementById('step2').classList.add('hidden'); |
|
|
document.getElementById('step3').classList.remove('hidden'); |
|
|
|
|
|
|
|
|
const progressBar = document.getElementById('progressBar'); |
|
|
const processingAnimation = document.getElementById('processingAnimation'); |
|
|
const resultSection = document.getElementById('resultSection'); |
|
|
|
|
|
let progress = 0; |
|
|
const interval = setInterval(() => { |
|
|
progress += 5; |
|
|
progressBar.style.width = `${progress}%`; |
|
|
|
|
|
if (progress >= 100) { |
|
|
clearInterval(interval); |
|
|
processingAnimation.classList.add('hidden'); |
|
|
resultSection.classList.remove('hidden'); |
|
|
|
|
|
|
|
|
const resultVideo = document.getElementById('resultVideo'); |
|
|
resultVideo.src = "https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4"; |
|
|
resultVideo.load(); |
|
|
} |
|
|
}, 200); |
|
|
} |
|
|
function showHelp() { |
|
|
alert("How to use AvatarSync Studio:\n\n1. Upload an image (your avatar) and an audio file\n2. Customize the animation style and colors\n3. Generate your animated avatar\n4. Download or share your creation!"); |
|
|
} |
|
|
|
|
|
function resetAll() { |
|
|
document.getElementById('step3').classList.add('hidden'); |
|
|
document.getElementById('step1').classList.remove('hidden'); |
|
|
document.getElementById('processingAnimation').classList.remove('hidden'); |
|
|
document.getElementById('resultSection').classList.add('hidden'); |
|
|
document.getElementById('progressBar').style.width = '0%'; |
|
|
|
|
|
clearImage(); |
|
|
clearAudio(); |
|
|
} |
|
|
|
|
|
|
|
|
document.getElementById('playPauseBtn').addEventListener('click', function() { |
|
|
const icon = this.querySelector('i'); |
|
|
if (icon.dataset.feather === 'play') { |
|
|
icon.dataset.feather = 'pause'; |
|
|
feather.replace(); |
|
|
|
|
|
} else { |
|
|
icon.dataset.feather = 'play'; |
|
|
feather.replace(); |
|
|
|
|
|
} |
|
|
}); |
|
|
}); |
|
|
</script> |
|
|
</body> |
|
|
</html> |
|
|
|