wigapp / index.html
savvysmith's picture
it does not show an image - Initial Deployment
16565ce verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HairFastGAN Wig Try-On</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.camera-container {
position: relative;
width: 100%;
height: 0;
padding-bottom: 75%;
background-color: #f3f4f6;
border-radius: 0.5rem;
overflow: hidden;
}
.camera-video {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
}
.camera-controls {
position: absolute;
bottom: 1rem;
left: 0;
width: 100%;
display: flex;
justify-content: center;
gap: 1rem;
}
.gallery-item {
transition: all 0.2s ease;
}
.gallery-item:hover {
transform: scale(1.05);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.gallery-item.selected {
border: 3px solid #6366f1;
transform: scale(1.05);
}
.result-container {
position: relative;
transition: all 0.3s ease;
}
.result-container.loading::after {
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
color: white;
font-size: 1.5rem;
}
.loading-spinner {
width: 50px;
height: 50px;
border: 5px solid #f3f3f3;
border-top: 5px solid #6366f1;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.color-picker {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
width: 100%;
height: 40px;
background-color: transparent;
border: none;
cursor: pointer;
}
.color-picker::-webkit-color-swatch {
border-radius: 8px;
border: 2px solid #e5e7eb;
}
.color-picker::-moz-color-swatch {
border-radius: 8px;
border: 2px solid #e5e7eb;
}
.tab-content {
display: none;
}
.tab-content.active {
display: block;
}
.progress-bar {
height: 6px;
background-color: #e5e7eb;
border-radius: 3px;
overflow: hidden;
}
.progress-fill {
height: 100%;
background-color: #6366f1;
width: 0%;
transition: width 0.3s ease;
}
.processing-step {
display: flex;
align-items: center;
margin-bottom: 0.5rem;
color: #6b7280;
}
.processing-step.active {
color: #111827;
font-weight: 500;
}
.processing-step.completed {
color: #10b981;
}
.processing-step i {
margin-right: 0.5rem;
}
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<div class="container mx-auto px-4 py-8">
<header class="mb-8">
<div class="flex justify-between items-center">
<div>
<h1 class="text-3xl font-bold text-indigo-600">HairFastGAN</h1>
<p class="text-gray-600">AI-Powered Virtual Wig Try-On</p>
</div>
<div class="flex items-center space-x-4">
<button id="loginBtn" class="px-4 py-2 text-gray-600 hover:text-indigo-600">
<i class="fas fa-user mr-2"></i>Login
</button>
<button id="creditsBtn" class="px-4 py-2 bg-indigo-100 text-indigo-600 rounded-full hover:bg-indigo-200">
<i class="fas fa-coins mr-2"></i>5 Credits
</button>
</div>
</div>
</header>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Left Column - Input Section -->
<div class="lg:col-span-2 bg-white rounded-xl shadow-md p-6">
<div class="flex border-b border-gray-200 mb-6">
<button class="tab-btn active px-4 py-2 font-medium text-indigo-600 border-b-2 border-indigo-600" data-tab="upload">
<i class="fas fa-upload mr-2"></i>Upload Photo
</button>
<button class="tab-btn px-4 py-2 font-medium text-gray-500 hover:text-indigo-600" data-tab="camera">
<i class="fas fa-camera mr-2"></i>Live Camera
</button>
</div>
<!-- Upload Tab -->
<div id="upload" class="tab-content active">
<div class="mb-6">
<h3 class="text-lg font-medium text-gray-900 mb-2">Upload Your Photo</h3>
<p class="text-gray-500 mb-4">For best results, use a clear front-facing photo with good lighting.</p>
<div class="flex flex-col items-center justify-center border-2 border-dashed border-gray-300 rounded-lg p-8 bg-gray-50">
<i class="fas fa-cloud-upload-alt text-4xl text-gray-400 mb-3"></i>
<p class="text-gray-500 mb-3">Drag & drop your photo here</p>
<p class="text-gray-400 text-sm mb-4">or</p>
<input type="file" id="photoUpload" accept="image/*" class="hidden">
<button id="uploadBtn" class="px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700">
<i class="fas fa-folder-open mr-2"></i>Browse Files
</button>
</div>
<div id="uploadPreview" class="mt-4 hidden">
<h4 class="text-md font-medium text-gray-900 mb-2">Preview</h4>
<div class="relative">
<img id="uploadedImage" src="" alt="Uploaded photo" class="w-full h-auto rounded-lg max-h-96 object-contain">
<button id="removeUpload" class="absolute top-2 right-2 bg-white p-2 rounded-full shadow-md hover:bg-gray-100">
<i class="fas fa-times text-gray-700"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Camera Tab -->
<div id="camera" class="tab-content">
<div class="mb-6">
<h3 class="text-lg font-medium text-gray-900 mb-2">Live Camera Try-On</h3>
<p class="text-gray-500 mb-4">Allow camera access to try wigs in real-time.</p>
<div class="camera-container">
<video id="cameraVideo" class="camera-video" autoplay playsinline></video>
<div class="camera-controls">
<button id="captureBtn" class="p-3 bg-indigo-600 text-white rounded-full hover:bg-indigo-700">
<i class="fas fa-camera text-xl"></i>
</button>
</div>
</div>
<div id="capturePreview" class="mt-4 hidden">
<h4 class="text-md font-medium text-gray-900 mb-2">Captured Photo</h4>
<div class="relative">
<canvas id="capturedImage" class="w-full h-auto rounded-lg max-h-96 object-contain"></canvas>
<button id="retakeBtn" class="absolute top-2 right-2 bg-white p-2 rounded-full shadow-md hover:bg-gray-100">
<i class="fas fa-redo text-gray-700"></i>
</button>
</div>
</div>
</div>
</div>
<!-- Hairstyle Selection -->
<div class="mb-6">
<h3 class="text-lg font-medium text-gray-900 mb-2">Choose Your Wig Style</h3>
<div class="flex border-b border-gray-200 mb-4">
<button class="style-tab-btn px-4 py-2 font-medium text-gray-500 hover:text-indigo-600" data-style="gallery">
<i class="fas fa-images mr-2"></i>Style Gallery
</button>
<button class="style-tab-btn px-4 py-2 font-medium text-gray-500 hover:text-indigo-600" data-style="color">
<i class="fas fa-palette mr-2"></i>Color Only
</button>
<button class="style-tab-btn active px-4 py-2 font-medium text-indigo-600 border-b-2 border-indigo-600" data-style="upload">
<i class="fas fa-upload mr-2"></i>Upload Your Wig
</button>
</div>
<!-- Style Gallery -->
<div id="gallery" class="style-tab-content active">
<div class="mb-4">
<div class="flex overflow-x-auto pb-2 space-x-3">
<button class="category-btn active px-3 py-1 bg-indigo-600 text-white rounded-full text-sm" data-category="all">All</button>
<button class="category-btn px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm hover:bg-gray-300" data-category="short">Short</button>
<button class="category-btn px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm hover:bg-gray-300" data-category="medium">Medium</button>
<button class="category-btn px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm hover:bg-gray-300" data-category="long">Long</button>
<button class="category-btn px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm hover:bg-gray-300" data-category="curly">Curly</button>
<button class="category-btn px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm hover:bg-gray-300" data-category="straight">Straight</button>
<button class="category-btn px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-sm hover:bg-gray-300" data-category="vip" data-vip="true">
<i class="fas fa-crown mr-1 text-yellow-500"></i>VIP
</button>
</div>
</div>
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-5 gap-3">
<!-- Sample wig styles - in a real app these would come from a database -->
<div class="gallery-item rounded-lg overflow-hidden cursor-pointer" data-id="1" data-category="short straight">
<img src="/wigs/short-bob.jpg" alt="Short straight wig" class="w-full h-24 object-cover">
<div class="p-2 text-center text-xs">Short Bob</div>
</div>
<div class="gallery-item rounded-lg overflow-hidden cursor-pointer" data-id="2" data-category="medium curly">
<img src="/wigs/curly-shoulder.jpg" alt="Medium curly wig" class="w-full h-24 object-cover">
<div class="p-2 text-center text-xs">Curly Shoulder</div>
</div>
<div class="gallery-item rounded-lg overflow-hidden cursor-pointer" data-id="3" data-category="long straight">
<img src="/wigs/long-straight.jpg" alt="Long straight wig" class="w-full h-24 object-cover">
<div class="p-2 text-center text-xs">Long Straight</div>
</div>
<div class="gallery-item rounded-lg overflow-hidden cursor-pointer" data-id="4" data-category="short curly">
<img src="/wigs/short-curly.jpg" alt="Short curly wig" class="w-full h-24 object-cover">
<div class="p-2 text-center text-xs">Short Curly</div>
</div>
<div class="gallery-item rounded-lg overflow-hidden cursor-pointer" data-id="5" data-category="medium straight">
<img src="/wigs/medium-straight.jpg" alt="Medium straight wig" class="w-full h-24 object-cover">
<div class="p-2 text-center text-xs">Medium Straight</div>
</div>
<div class="gallery-item rounded-lg overflow-hidden cursor-pointer" data-id="6" data-category="long curly">
<img src="/wigs/long-curly.jpg" alt="Long curly wig" class="w-full h-24 object-cover">
<div class="p-2 text-center text-xs">Long Curly</div>
</div>
<div class="gallery-item rounded-lg overflow-hidden cursor-pointer" data-id="7" data-category="vip long straight" data-vip="true">
<img src="/wigs/vip-ombre.jpg" alt="VIP long straight wig" class="w-full h-24 object-cover">
<div class="p-2 text-center text-xs flex items-center justify-center">
<span>VIP Ombre</span>
<i class="fas fa-crown ml-1 text-yellow-500"></i>
</div>
</div>
<div class="gallery-item rounded-lg overflow-hidden cursor-pointer" data-id="8" data-category="vip medium curly" data-vip="true">
<img src="/wigs/vip-waves.jpg" alt="VIP medium curly wig" class="w-full h-24 object-cover">
<div class="p-2 text-center text-xs flex items-center justify-center">
<span>VIP Waves</span>
<i class="fas fa-crown ml-1 text-yellow-500"></i>
</div>
</div>
</div>
</div>
<!-- Color Only -->
<div id="color" class="style-tab-content">
<div class="mb-4">
<p class="text-gray-500 mb-3">Select a hair color to apply to your current hairstyle:</p>
<input type="color" id="hairColorPicker" class="color-picker" value="#5a3e2a">
</div>
<div class="grid grid-cols-5 gap-3">
<div class="color-swatch bg-[#000000] h-10 rounded cursor-pointer" data-color="#000000"></div>
<div class="color-swatch bg-[#5a3e2a] h-10 rounded cursor-pointer" data-color="#5a3e2a"></div>
<div class="color-swatch bg-[#a55728] h-10 rounded cursor-pointer" data-color="#a55728"></div>
<div class="color-swatch bg-[#b58143] h-10 rounded cursor-pointer" data-color="#b58143"></div>
<div class="color-swatch bg-[#d4b996] h-10 rounded cursor-pointer" data-color="#d4b996"></div>
<div class="color-swatch bg-[#f0e2c6] h-10 rounded cursor-pointer" data-color="#f0e2c6"></div>
<div class="color-swatch bg-[#c93384] h-10 rounded cursor-pointer" data-color="#c93384"></div>
<div class="color-swatch bg-[#e64980] h-10 rounded cursor-pointer" data-color="#e64980"></div>
<div class="color-swatch bg-[#6741d9] h-10 rounded cursor-pointer" data-color="#6741d9"></div>
<div class="color-swatch bg-[#228be6] h-10 rounded cursor-pointer" data-color="#228be6"></div>
</div>
</div>
<!-- Upload Style -->
<div id="uploadStyle" class="style-tab-content active">
<div class="mb-4">
<p class="text-gray-500 mb-3">Upload a photo of the wig you want to try on:</p>
<div class="flex flex-col items-center justify-center border-2 border-dashed border-gray-300 rounded-lg p-8 bg-gray-50 hover:bg-gray-100 transition-colors duration-200">
<i class="fas fa-wig text-4xl text-indigo-400 mb-3"></i>
<p class="text-gray-500 mb-3 font-medium">Drag & drop wig photo here</p>
<p class="text-gray-400 text-sm mb-4">or</p>
<input type="file" id="styleUpload" accept="image/*" class="hidden">
<button id="uploadStyleBtn" class="px-6 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors duration-200">
<i class="fas fa-upload mr-2"></i>Select Wig Image
</button>
<p class="text-gray-400 text-xs mt-3">Supports JPG, PNG up to 5MB</p>
</div>
</div>
<div id="stylePreview" class="hidden mt-6">
<h4 class="text-lg font-medium text-gray-900 mb-3">Your Selected Wig</h4>
<div class="relative bg-gray-100 rounded-xl p-4">
<img id="uploadedStyleImage" src="" alt="Uploaded wig" class="w-full h-auto rounded-lg max-h-64 object-contain mx-auto">
<button id="removeStyle" class="absolute top-4 right-4 bg-white p-2 rounded-full shadow-md hover:bg-gray-100 transition-colors duration-200">
<i class="fas fa-redo text-gray-700"></i> Change
</button>
</div>
<div class="mt-4 flex items-center justify-between">
<div>
<h5 class="font-medium">Wig Details</h5>
<p id="wigDetails" class="text-sm text-gray-500">Uploaded wig</p>
</div>
<button id="analyzeWigBtn" class="px-4 py-2 bg-indigo-100 text-indigo-700 rounded-lg hover:bg-indigo-200 transition-colors duration-200">
<i class="fas fa-search mr-2"></i> Analyze Wig
</button>
</div>
</div>
</div>
</div>
<!-- Processing Options -->
<div class="mb-6">
<h3 class="text-lg font-medium text-gray-900 mb-2">Processing Options</h3>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label class="flex items-center">
<input type="checkbox" class="rounded text-indigo-600" checked>
<span class="ml-2 text-gray-700">Pose Alignment (Rotate Encoder)</span>
</label>
<p class="text-gray-500 text-sm ml-6">Adjusts head position for better matching</p>
</div>
<div>
<label class="flex items-center">
<input type="checkbox" class="rounded text-indigo-600" checked>
<span class="ml-2 text-gray-700">Shape Alignment (SEAN + StyleGAN)</span>
</label>
<p class="text-gray-500 text-sm ml-6">Matches the wig shape to your face</p>
</div>
<div>
<label class="flex items-center">
<input type="checkbox" class="rounded text-indigo-600" checked>
<span class="ml-2 text-gray-700">Color Alignment (CLIP-guided S editing)</span>
</label>
<p class="text-gray-500 text-sm ml-6">Ensures natural-looking color transfer</p>
</div>
<div>
<label class="flex items-center">
<input type="checkbox" class="rounded text-indigo-600" checked>
<span class="ml-2 text-gray-700">Detail Refinement (64x64 FS fusion)</span>
</label>
<p class="text-gray-500 text-sm ml-6">Restores facial identity and details</p>
</div>
</div>
</div>
<button id="generateBtn" class="w-full py-3 bg-indigo-600 text-white rounded-lg font-medium hover:bg-indigo-700 flex items-center justify-center">
<i class="fas fa-magic mr-2"></i>Generate Wig Try-On (1 Credit)
</button>
</div>
<!-- Right Column - Results Section -->
<div class="bg-white rounded-xl shadow-md p-6">
<h2 class="text-xl font-bold text-gray-900 mb-4">Your Results</h2>
<div id="emptyState" class="flex flex-col items-center justify-center py-12">
<i class="fas fa-cut text-5xl text-gray-300 mb-4"></i>
<h3 class="text-lg font-medium text-gray-700 mb-2">No results yet</h3>
<p class="text-gray-500 text-center mb-4">Upload your photo and select a wig style to see how it would look on you!</p>
</div>
<div id="resultContainer" class="hidden">
<div class="result-container mb-4">
<img id="resultImage" src="" alt="Wig try-on result" class="w-full h-auto rounded-lg">
</div>
<div class="flex justify-between mb-4">
<div>
<h4 class="font-medium text-gray-900">Your Selected Style</h4>
<p id="selectedStyleName" class="text-gray-500 text-sm">Short Bob</p>
</div>
<div class="flex space-x-2">
<button id="downloadBtn" class="p-2 bg-gray-100 rounded-full hover:bg-gray-200">
<i class="fas fa-download text-gray-700"></i>
</button>
<button id="saveBtn" class="p-2 bg-gray-100 rounded-full hover:bg-gray-200">
<i class="fas fa-save text-gray-700"></i>
</button>
<button id="shareBtn" class="p-2 bg-gray-100 rounded-full hover:bg-gray-200">
<i class="fas fa-share-alt text-gray-700"></i>
</button>
</div>
</div>
<div class="mb-6">
<h4 class="font-medium text-gray-900 mb-2">Try Another Style</h4>
<div class="grid grid-cols-4 gap-2">
<div class="rounded overflow-hidden cursor-pointer">
<img src="/wigs/short-bob-thumb.jpg" alt="Short straight wig" class="w-full h-16 object-cover">
</div>
<div class="rounded overflow-hidden cursor-pointer">
<img src="/wigs/curly-shoulder-thumb.jpg" alt="Medium curly wig" class="w-full h-16 object-cover">
</div>
<div class="rounded overflow-hidden cursor-pointer">
<img src="/wigs/long-straight-thumb.jpg" alt="Long straight wig" class="w-full h-16 object-cover">
</div>
<div class="rounded overflow-hidden cursor-pointer">
<img src="/wigs/short-curly-thumb.jpg" alt="Short curly wig" class="w-full h-16 object-cover">
</div>
</div>
</div>
<div class="bg-indigo-50 rounded-lg p-4">
<h4 class="font-medium text-indigo-800 mb-2">Love this style?</h4>
<p class="text-indigo-700 text-sm mb-3">Get this exact wig customized to your measurements.</p>
<button id="buyBtn" class="w-full py-2 bg-indigo-600 text-white rounded-lg text-sm font-medium hover:bg-indigo-700">
Order Custom Wig ($89.99)
</button>
</div>
</div>
<div id="processingContainer" class="hidden">
<div class="flex flex-col items-center justify-center py-8">
<div class="loading-spinner mb-4"></div>
<h3 class="text-lg font-medium text-gray-900 mb-2">Processing Your Image</h3>
<p class="text-gray-500 text-center mb-6">Our AI is applying your selected wig style...</p>
<div class="w-full mb-6">
<div class="progress-bar">
<div id="progressFill" class="progress-fill"></div>
</div>
</div>
<div class="w-full space-y-2">
<div class="processing-step active">
<i class="fas fa-sync-alt"></i>
<span>Pose alignment using Rotate Encoder</span>
</div>
<div class="processing-step">
<i class="fas fa-project-diagram"></i>
<span>Shape alignment in FS space</span>
</div>
<div class="processing-step">
<i class="fas fa-palette"></i>
<span>Color alignment with CLIP guidance</span>
</div>
<div class="processing-step">
<i class="fas fa-magic"></i>
<span>Detail refinement with 64x64 FS fusion</span>
</div>
<div class="processing-step">
<i class="fas fa-check-circle"></i>
<span>Final rendering</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- VIP Modal -->
<div id="vipModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-xl p-6 max-w-md w-full">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-bold text-gray-900">VIP Styles</h3>
<button id="closeVipModal" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="mb-4">
<p class="text-gray-600">VIP styles are premium designs that require additional credits to unlock.</p>
</div>
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-4">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-crown text-yellow-500 mt-1"></i>
</div>
<div class="ml-3">
<h3 class="text-sm font-medium text-yellow-800">VIP Style Detected</h3>
<div class="mt-2 text-sm text-yellow-700">
<p>This style requires 3 credits to try on.</p>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-2 gap-4">
<button id="useCreditsBtn" class="py-2 bg-indigo-600 text-white rounded-lg font-medium hover:bg-indigo-700">
Use 3 Credits
</button>
<button id="buyCreditsBtn" class="py-2 bg-yellow-500 text-white rounded-lg font-medium hover:bg-yellow-600">
Buy More Credits
</button>
</div>
</div>
</div>
<!-- Credits Modal -->
<div id="creditsModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
<div class="bg-white rounded-xl p-6 max-w-md w-full">
<div class="flex justify-between items-center mb-4">
<h3 class="text-xl font-bold text-gray-900">Buy More Credits</h3>
<button id="closeCreditsModal" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="mb-4">
<p class="text-gray-600">Each credit allows you to generate one wig try-on result.</p>
</div>
<div class="space-y-3 mb-6">
<div class="flex items-center justify-between p-3 border border-gray-200 rounded-lg hover:border-indigo-300">
<div>
<h4 class="font-medium text-gray-900">10 Credits</h4>
<p class="text-sm text-gray-500">$9.99 ($1.00 per credit)</p>
</div>
<button class="px-4 py-2 bg-indigo-600 text-white rounded-lg text-sm font-medium hover:bg-indigo-700">
Select
</button>
</div>
<div class="flex items-center justify-between p-3 border border-gray-200 rounded-lg hover:border-indigo-300">
<div>
<h4 class="font-medium text-gray-900">25 Credits</h4>
<p class="text-sm text-gray-500">$19.99 ($0.80 per credit)</p>
</div>
<button class="px-4 py-2 bg-indigo-600 text-white rounded-lg text-sm font-medium hover:bg-indigo-700">
Select
</button>
</div>
<div class="flex items-center justify-between p-3 border border-gray-200 rounded-lg hover:border-indigo-300 bg-indigo-50 border-indigo-200">
<div>
<h4 class="font-medium text-indigo-900">50 Credits</h4>
<p class="text-sm text-indigo-700">$29.99 ($0.60 per credit)</p>
</div>
<div class="flex items-center">
<span class="bg-indigo-600 text-white text-xs font-medium px-2 py-0.5 rounded mr-2">Best Value</span>
<button class="px-4 py-2 bg-indigo-600 text-white rounded-lg text-sm font-medium hover:bg-indigo-700">
Select
</button>
</div>
</div>
</div>
<div class="text-center">
<button id="subscribeBtn" class="text-indigo-600 hover:text-indigo-800 text-sm font-medium">
Or subscribe for unlimited credits at $14.99/month
</button>
</div>
</div>
</div>
</div>
<script>
// DOM Elements
const tabBtns = document.querySelectorAll('.tab-btn');
const tabContents = document.querySelectorAll('.tab-content');
const styleTabBtns = document.querySelectorAll('.style-tab-btn');
const styleTabContents = document.querySelectorAll('.style-tab-content');
const categoryBtns = document.querySelectorAll('.category-btn');
const galleryItems = document.querySelectorAll('.gallery-item');
const colorSwatches = document.querySelectorAll('.color-swatch');
const uploadBtn = document.getElementById('uploadBtn');
const photoUpload = document.getElementById('photoUpload');
const uploadPreview = document.getElementById('uploadPreview');
const uploadedImage = document.getElementById('uploadedImage');
const removeUpload = document.getElementById('removeUpload');
const generateBtn = document.getElementById('generateBtn');
const emptyState = document.getElementById('emptyState');
const resultContainer = document.getElementById('resultContainer');
const resultImage = document.getElementById('resultImage');
const processingContainer = document.getElementById('processingContainer');
const progressFill = document.getElementById('progressFill');
const processingSteps = document.querySelectorAll('.processing-step');
const vipModal = document.getElementById('vipModal');
const closeVipModal = document.getElementById('closeVipModal');
const useCreditsBtn = document.getElementById('useCreditsBtn');
const buyCreditsBtn = document.getElementById('buyCreditsBtn');
const creditsBtn = document.getElementById('creditsBtn');
const creditsModal = document.getElementById('creditsModal');
const closeCreditsModal = document.getElementById('closeCreditsModal');
const captureBtn = document.getElementById('captureBtn');
const cameraVideo = document.getElementById('cameraVideo');
const capturedImage = document.getElementById('capturedImage');
const capturePreview = document.getElementById('capturePreview');
const retakeBtn = document.getElementById('retakeBtn');
const uploadStyleBtn = document.getElementById('uploadStyleBtn');
const styleUpload = document.getElementById('styleUpload');
const stylePreview = document.getElementById('stylePreview');
const uploadedStyleImage = document.getElementById('uploadedStyleImage');
const removeStyle = document.getElementById('removeStyle');
const hairColorPicker = document.getElementById('hairColorPicker');
const selectedStyleName = document.getElementById('selectedStyleName');
// Tab switching
tabBtns.forEach(btn => {
btn.addEventListener('click', () => {
tabBtns.forEach(b => b.classList.remove('active', 'text-indigo-600', 'border-indigo-600'));
btn.classList.add('active', 'text-indigo-600', 'border-indigo-600');
const tabId = btn.getAttribute('data-tab');
tabContents.forEach(content => {
content.classList.remove('active');
if (content.id === tabId) {
content.classList.add('active');
// Initialize camera if camera tab is selected
if (tabId === 'camera') {
initCamera();
} else {
stopCamera();
}
}
});
});
});
// Style tab switching
styleTabBtns.forEach(btn => {
btn.addEventListener('click', () => {
styleTabBtns.forEach(b => b.classList.remove('active', 'text-indigo-600', 'border-indigo-600'));
btn.classList.add('active', 'text-indigo-600', 'border-indigo-600');
const styleTabId = btn.getAttribute('data-style');
styleTabContents.forEach(content => {
content.classList.remove('active');
if (content.id === styleTabId) {
content.classList.add('active');
}
});
});
});
// Category filtering
categoryBtns.forEach(btn => {
btn.addEventListener('click', () => {
categoryBtns.forEach(b => b.classList.remove('active', 'bg-indigo-600', 'text-white'));
btn.classList.add('active', 'bg-indigo-600', 'text-white');
const category = btn.getAttribute('data-category');
const isVip = btn.getAttribute('data-vip') === 'true';
galleryItems.forEach(item => {
const itemCategories = item.getAttribute('data-category').split(' ');
const itemIsVip = item.getAttribute('data-vip') === 'true';
if (category === 'all' ||
itemCategories.includes(category) ||
(isVip && itemIsVip)) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
});
});
});
// Gallery item selection
galleryItems.forEach(item => {
item.addEventListener('click', () => {
// Check if VIP style
const isVip = item.getAttribute('data-vip') === 'true';
if (isVip) {
// Show VIP modal
vipModal.classList.remove('hidden');
return;
}
galleryItems.forEach(i => i.classList.remove('selected'));
item.classList.add('selected');
// Update selected style name
const styleName = item.querySelector('div').textContent.trim();
selectedStyleName.textContent = styleName;
});
});
// Color swatch selection
colorSwatches.forEach(swatch => {
swatch.addEventListener('click', () => {
const color = swatch.getAttribute('data-color');
hairColorPicker.value = color;
// Highlight selected swatch
colorSwatches.forEach(s => s.classList.remove('ring-2', 'ring-indigo-500', 'ring-offset-2'));
swatch.classList.add('ring-2', 'ring-indigo-500', 'ring-offset-2');
});
});
// Photo upload
uploadBtn.addEventListener('click', () => photoUpload.click());
photoUpload.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (event) => {
uploadedImage.src = event.target.result;
uploadPreview.classList.remove('hidden');
};
reader.readAsDataURL(file);
}
});
// Remove uploaded photo
removeUpload.addEventListener('click', () => {
uploadedImage.src = '';
uploadPreview.classList.add('hidden');
photoUpload.value = '';
});
// Style upload
uploadStyleBtn.addEventListener('click', () => styleUpload.click());
styleUpload.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
const file = e.target.files[0];
const reader = new FileReader();
reader.onload = (event) => {
uploadedStyleImage.src = event.target.result;
stylePreview.classList.remove('hidden');
// Update wig details
const wigDetails = document.getElementById('wigDetails');
wigDetails.textContent = `${file.name} (${(file.size/1024/1024).toFixed(1)}MB)`;
};
reader.readAsDataURL(file);
}
});
// Remove/change uploaded style
removeStyle.addEventListener('click', () => {
styleUpload.value = '';
styleUpload.click();
});
// Analyze wig button
document.getElementById('analyzeWigBtn').addEventListener('click', () => {
if (uploadedStyleImage.src) {
// Show processing animation
const analyzeBtn = document.getElementById('analyzeWigBtn');
analyzeBtn.innerHTML = '<i class="fas fa-spinner fa-spin mr-2"></i> Analyzing...';
analyzeBtn.disabled = true;
// Simulate analysis (in real app, this would call backend)
setTimeout(() => {
analyzeBtn.innerHTML = '<i class="fas fa-check mr-2"></i> Analyzed';
// Update wig details with analysis results
const wigDetails = document.getElementById('wigDetails');
wigDetails.innerHTML = `
<span class="font-medium">Long Straight Wig</span><br>
<span class="text-indigo-600">✓ Shape detected</span><br>
<span class="text-indigo-600">✓ Color analyzed (#5a3e2a)</span>
`;
// Enable generate button
document.getElementById('generateBtn').disabled = false;
}, 2000);
} else {
alert('Please upload a wig image first');
}
});
// Generate button click
generateBtn.addEventListener('click', () => {
// Check if photo is uploaded
if (!uploadPreview.classList.contains('hidden') || !capturePreview.classList.contains('hidden')) {
// Show processing state
emptyState.classList.add('hidden');
resultContainer.classList.add('hidden');
processingContainer.classList.remove('hidden');
// Simulate processing steps
simulateProcessing();
// After processing, show result
setTimeout(() => {
processingContainer.classList.add('hidden');
resultContainer.classList.remove('hidden');
// Set the generated result from processing
resultImage.src = "/generated-results/result.jpg";
resultImage.alt = "Generated wig try-on result";
}, 3000);
} else {
alert('Please upload a photo or take one with your camera first.');
}
});
// VIP modal
closeVipModal.addEventListener('click', () => {
vipModal.classList.add('hidden');
});
useCreditsBtn.addEventListener('click', () => {
// In a real app, would deduct credits and proceed
alert('VIP style unlocked with 3 credits!');
vipModal.classList.add('hidden');
// Find and select the VIP item
galleryItems.forEach(item => {
if (item.getAttribute('data-vip') === 'true' && item.classList.contains('selected')) {
const styleName = item.querySelector('div').textContent.trim();
selectedStyleName.textContent = styleName;
}
});
});
buyCreditsBtn.addEventListener('click', () => {
vipModal.classList.add('hidden');
creditsModal.classList.remove('hidden');
});
// Credits modal
creditsBtn.addEventListener('click', () => {
creditsModal.classList.remove('hidden');
});
closeCreditsModal.addEventListener('click', () => {
creditsModal.classList.add('hidden');
});
// Camera functionality
function initCamera() {
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: true })
.then(stream => {
cameraVideo.srcObject = stream;
})
.catch(error => {
console.error("Camera access error:", error);
alert("Could not access the camera. Please check permissions.");
});
}
}
function stopCamera() {
if (cameraVideo.srcObject) {
cameraVideo.srcObject.getTracks().forEach(track => track.stop());
cameraVideo.srcObject = null;
}
}
// Capture photo from camera
captureBtn.addEventListener('click', () => {
const context = capturedImage.getContext('2d');
capturedImage.width = cameraVideo.videoWidth;
capturedImage.height = cameraVideo.videoHeight;
context.drawImage(cameraVideo, 0, 0, capturedImage.width, capturedImage.height);
capturePreview.classList.remove('hidden');
});
// Retake photo
retakeBtn.addEventListener('click', () => {
capturePreview.classList.add('hidden');
});
// Simulate processing steps
function simulateProcessing() {
let progress = 0;
const interval = setInterval(() => {
progress += 5;
progressFill.style.width = `${progress}%`;
// Update active step
if (progress >= 20) processingSteps[1].classList.add('active');
if (progress >= 40) {
processingSteps[1].classList.remove('active');
processingSteps[1].classList.add('completed');
processingSteps[2].classList.add('active');
}
if (progress >= 60) {
processingSteps[2].classList.remove('active');
processingSteps[2].classList.add('completed');
processingSteps[3].classList.add('active');
}
if (progress >= 80) {
processingSteps[3].classList.remove('active');
processingSteps[3].classList.add('completed');
processingSteps[4].classList.add('active');
}
if (progress >= 100) {
processingSteps[4].classList.remove('active');
processingSteps[4].classList.add('completed');
clearInterval(interval);
}
}, 100);
}
// Initialize with first tab active
document.querySelector('.tab-btn').click();
document.querySelector('.style-tab-btn').click();
document.querySelector('.category-btn').click();
// Clean up camera on page unload
window.addEventListener('beforeunload', () => {
stopCamera();
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=savvysmith/wigapp" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>