w4nn4b3M4ST3R's picture
new version
bbcd7db
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Intelligent Image Deduplicator</title>
<link
rel="icon"
href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='20' fill='%230c0211'/><circle cx='50' cy='50' r='30' fill='%23fcd34d' opacity='0.5'/><path d='M50 20 L75 50 L50 80 L25 50 Z' fill='%23ffffff' stroke='%23fcd34d' stroke-width='2'/></svg>"
/>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.160.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
}
}
</script>
<link
href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="/static/styles.css" />
</head>
<body class="h-screen flex flex-col m-0 p-0 bg-[#121212]">
<header
class="h-14 bg-[#181818] border-b border-[#333] flex items-center justify-between px-6 z-50 relative select-none shrink-0"
>
<div class="absolute left-1/2 transform -translate-x-1/2">
<h1
class="flex items-center gap-1 text-lg font-bold text-gray-200 tracking-wide"
>
Image<span class="font-light text-gray-400">Deduplicator</span>
</h1>
</div>
<button
id="toggle-config-btn"
class="flex items-center gap-2 text-xs text-gray-400 hover:text-white bg-[#252526] hover:bg-[#333] px-3 py-1.5 rounded transition border border-[#333]"
>
<span id="config-status-text">Hide Config</span>
<svg
id="config-arrow"
class="w-3 h-3 transform transition-transform duration-300"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
></path>
</svg>
</button>
</header>
<div
id="control-panel"
class="bg-[#1c1c1c] border-b border-[#333] shadow-2xl relative z-40 shrink-0"
>
<div class="max-w-full px-6 py-4">
<div class="flex flex-col md:flex-row gap-6 items-stretch">
<div
id="step-upload"
class="flex-1 bg-[#252526] p-4 rounded-xl border border-[#333] flex flex-col justify-center transition-all duration-300"
>
<div class="flex items-center gap-2 mb-3">
<span
class="bg-violet-600/20 text-violet-400 text-[10px] font-bold px-2 py-0.5 rounded border border-violet-600/30"
>STEP 01</span
>
<h3
class="text-xs font-bold text-gray-300 tracking-widest uppercase"
>
Upload Images
</h3>
</div>
<div class="flex gap-3 items-center">
<input
type="file"
id="image-folder-input"
class="hidden"
multiple
webkitdirectory
directory
/>
<label
for="image-folder-input"
class="cursor-pointer bg-[#333] hover:bg-[#444] text-white h-10 px-4 rounded-lg border border-[#555] text-xs font-bold flex items-center gap-2 transition shrink-0 whitespace-nowrap"
>
<svg
class="w-4 h-4 text-violet-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z"
></path>
</svg>
BROWSE FOLDER
</label>
<div class="flex-1 min-w-0 flex flex-col justify-center h-10">
<div
id="upload-status"
class="text-[11px] text-gray-500 font-mono truncate leading-tight"
>
No folder selected
</div>
<div
class="w-full bg-[#1a1a1a] h-1.5 rounded-full overflow-hidden border border-[#333] mt-1.5"
>
<div
id="upload-bar"
class="bg-gradient-to-r from-violet-600 to-fuchsia-500 h-full w-0 transition-all duration-300"
></div>
</div>
</div>
<button
id="btn-upload"
class="bg-white hover:bg-gray-200 text-black font-extrabold text-[10px] h-10 px-5 rounded-lg transition shadow-lg tracking-wider shrink-0 uppercase"
>
Upload
</button>
</div>
</div>
<div
class="hidden md:block w-px bg-gradient-to-b from-transparent via-[#444] to-transparent"
></div>
<div
id="step-process"
class="flex-1 bg-[#252526] p-4 rounded-xl border border-[#333] flex flex-col justify-center transition-all duration-300 opacity-40 pointer-events-none grayscale"
>
<div class="flex items-center gap-2 mb-3">
<span
class="bg-emerald-600/20 text-emerald-400 text-[10px] font-bold px-2 py-0.5 rounded border border-emerald-600/30"
>STEP 02</span
>
<h3
class="text-xs font-bold text-gray-300 tracking-widest uppercase"
>
Analyze & Deduplicate
</h3>
</div>
<div class="flex gap-3 items-end h-10">
<div class="flex-1 relative">
<select
id="algorithm"
class="w-full h-10 bg-[#1a1a1a] border border-[#444] text-gray-200 text-xs rounded-lg px-3 outline-none focus:border-emerald-500 appearance-none font-mono"
>
<option value="SimHash">SimHash</option>
<option value="HashTable">HashTable</option>
<option value="MinHash">MinHash</option>
<option value="BloomFilter">BloomFilter</option>
</select>
<div
class="absolute inset-y-0 right-0 flex items-center px-2 pointer-events-none"
>
<svg
class="w-3 h-3 text-gray-500"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
></path>
</svg>
</div>
</div>
<button
id="start-clustering-btn"
class="bg-gradient-to-r from-emerald-600 to-teal-600 hover:from-emerald-500 hover:to-teal-500 text-white font-bold text-xs h-10 px-6 rounded-lg shadow-lg transition transform active:scale-95 flex items-center gap-2 shrink-0"
>
START PROCESS
</button>
</div>
</div>
</div>
</div>
</div>
<div class="flex-1 flex flex-col min-h-0 relative">
<div
class="flex justify-center bg-[#181818] border-b border-[#333] shrink-0 z-20 relative"
>
<button
class="tab-button px-8 py-3 text-sm text-gray-400 hover:text-gray-200 font-medium"
data-tab="summary"
>
Summary
</button>
<button
class="tab-button px-8 py-3 text-sm text-gray-400 hover:text-gray-200 font-medium"
data-tab="browser"
>
Cluster Browser
</button>
<button
class="tab-button px-8 py-3 text-sm text-gray-400 hover:text-gray-200 font-medium"
data-tab="stats"
>
Statistics
</button>
<button
class="tab-button px-8 py-3 text-sm text-gray-400 hover:text-gray-200 font-medium flex items-center gap-2"
data-tab="universe"
>
Universe Map
<span
class="text-[10px] bg-violet-500/20 text-violet-300 px-1.5 py-0.5 rounded font-bold tracking-wide"
>3D</span
>
</button>
</div>
<div class="flex-1 relative bg-[#121212] overflow-hidden">
<div
id="hero-landing"
class="absolute inset-0 flex flex-col items-center justify-center z-10 overflow-hidden pointer-events-none"
>
<div
class="absolute inset-0 bg-[radial-gradient(ellipse_at_center,_#1B0F2E_0%,_#000000_100%)] z-0"
></div>
<div class="absolute inset-0 hero-bg-animated z-0 opacity-60"></div>
<div class="star-layer stars-tiny" style="z-index: 0"></div>
<div
class="star-layer stars-small opacity-80"
style="z-index: 0"
></div>
<div
class="star-layer stars-medium opacity-80"
style="z-index: 0"
></div>
<div class="relative z-10 w-[1000px] max-w-[90vmin] hero-floating">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 400">
<defs>
<radialGradient
id="goldCore"
cx="50%"
cy="50%"
r="50%"
fx="50%"
fy="50%"
>
<stop
offset="0%"
style="stop-color: #ffffff; stop-opacity: 1"
/>
<stop
offset="30%"
style="stop-color: #fcd34d; stop-opacity: 1"
/>
<stop
offset="70%"
style="stop-color: #d97706; stop-opacity: 0.8"
/>
<stop
offset="100%"
style="stop-color: #7c2d12; stop-opacity: 0"
/>
</radialGradient>
<linearGradient
id="dupeEnergy"
x1="0%"
y1="0%"
x2="100%"
y2="0%"
>
<stop
offset="0%"
class="text-glow-anim"
style="stop-color: #6a0dad; stop-opacity: 0.6"
/>
<stop
offset="100%"
style="stop-color: #3b82f6; stop-opacity: 0.6"
/>
</linearGradient>
<filter
id="intenseGlow"
x="-100%"
y="-100%"
width="300%"
height="300%"
>
<feGaussianBlur stdDeviation="6" result="coloredBlur" />
<feMerge>
<feMergeNode in="coloredBlur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<g transform="translate(300, 180)">
<g opacity="0.6" class="spin-cinematic-reverse">
<circle
cx="-45"
cy="0"
r="50"
fill="url(#dupeEnergy)"
filter="url(#intenseGlow)"
opacity="0.5"
style="mix-blend-mode: screen"
/>
<circle
cx="45"
cy="0"
r="50"
fill="url(#dupeEnergy)"
filter="url(#intenseGlow)"
opacity="0.5"
transform="scale(-1,1)"
style="mix-blend-mode: screen"
/>
</g>
<g class="spin-cinematic" opacity="0.4">
<path
d="M-150,20 C-80,20 -50,0 0,0"
stroke="#6a0dad"
stroke-width="2"
fill="none"
/>
<path
d="M150,-20 C80,-20 50,0 0,0"
stroke="#3b82f6"
stroke-width="2"
fill="none"
/>
<circle
cx="-120"
cy="20"
r="3"
fill="#fff"
filter="url(#intenseGlow)"
/>
<circle
cx="120"
cy="-20"
r="3"
fill="#fff"
filter="url(#intenseGlow)"
/>
</g>
<g class="pulse-core" filter="url(#intenseGlow)">
<circle
cx="0"
cy="0"
r="28"
fill="url(#goldCore)"
opacity="0.7"
/>
<circle cx="0" cy="0" r="12" fill="#ffffff" opacity="0.9" />
<g
stroke="#fcd34d"
stroke-width="2"
stroke-linecap="round"
opacity="0.9"
>
<line x1="-65" y1="0" x2="65" y2="0" />
<line x1="0" y1="-65" x2="0" y2="65" />
<line
x1="-30"
y1="-30"
x2="30"
y2="30"
stroke-width="1"
opacity="0.5"
/>
<line
x1="-30"
y1="30"
x2="30"
y2="-30"
stroke-width="1"
opacity="0.5"
/>
</g>
</g>
</g>
<text
x="300"
y="330"
text-anchor="middle"
font-family="'Outfit', sans-serif"
font-size="36"
font-weight="700"
fill="#ffffff"
letter-spacing="8"
filter="url(#intenseGlow)"
opacity="0.9"
>
IMAGE
<tspan fill="#fcd34d">DEDUPLICATOR</tspan>
</text>
<text
x="300"
y="360"
text-anchor="middle"
font-family="'JetBrains Mono', monospace"
font-size="10"
font-weight="400"
fill="#a78bfa"
letter-spacing="4"
opacity="0.6"
>
A.I PERCEPTUAL HASHING SYSTEM
</text>
</svg>
</div>
</div>
<div
id="tab-summary"
class="tab-content h-full p-8 overflow-auto hidden"
>
<div class="max-w-6xl mx-auto animate-fade-in">
<div
class="flex flex-col md:flex-row justify-between items-end mb-8 border-b border-[#333] pb-6"
>
<div>
<h2 class="text-3xl font-bold text-white mb-2 tracking-tight">
Mission Report
</h2>
<p class="text-gray-400 text-sm font-mono">
Session ID:
<span id="summary-session-id" class="text-violet-400"
>WAITING...</span
>
</p>
</div>
<div
id="summary-impact-badge"
class="hidden px-4 py-2 bg-emerald-500/10 border border-emerald-500/20 rounded-lg"
>
<span
class="text-xs text-emerald-400 font-mono font-bold tracking-widest uppercase"
>Potential Savings</span
>
<div
class="text-xl font-bold text-white"
id="summary-savings-text"
>
0%
</div>
</div>
</div>
<div
id="summary-content"
class="text-gray-500 text-center py-20 italic bg-[#1e1e1e]/50 rounded-xl border border-dashed border-[#333]"
>
<div class="text-4xl mb-4">waiting_for_data...</div>
<p class="font-mono text-sm">
Upload images and start processing to generate highlights.
</p>
</div>
<div id="summary-visuals" class="hidden">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6 mb-10">
<div
class="p-6 rounded-xl bg-gradient-to-br from-[#1e1e1e] to-[#161616] border border-[#333]"
>
<div
class="text-xs text-gray-500 font-bold uppercase tracking-wider mb-2"
>
Scanned Assets
</div>
<div id="sum-total-img" class="text-3xl font-bold text-white">
0
</div>
</div>
<div
class="p-6 rounded-xl bg-gradient-to-br from-[#1e1e1e] to-[#161616] border border-[#333]"
>
<div
class="text-xs text-gray-500 font-bold uppercase tracking-wider mb-2"
>
Redundant Copies
</div>
<div
id="sum-dupes-img"
class="text-3xl font-bold text-red-400"
>
0
</div>
</div>
<div
class="p-6 rounded-xl bg-gradient-to-br from-[#1e1e1e] to-[#161616] border border-[#333]"
>
<div
class="text-xs text-gray-500 font-bold uppercase tracking-wider mb-2"
>
Detected Clusters
</div>
<div
id="sum-clusters-img"
class="text-3xl font-bold text-violet-400"
>
0
</div>
</div>
</div>
<div class="flex items-center gap-3 mb-6">
<div
class="h-px bg-gradient-to-r from-violet-500 to-transparent flex-1"
></div>
<h3
class="text-lg font-bold text-gray-200 flex items-center gap-2"
>
<span class="text-violet-500"></span> PRIORITY TARGETS
</h3>
<div
class="h-px bg-gradient-to-l from-violet-500 to-transparent flex-1"
></div>
</div>
<p class="text-gray-400 text-sm mb-6 text-center">
The following groups consume the most space. Click any card to
review and clean up immediately.
</p>
<div
id="priority-grid"
class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"
></div>
</div>
</div>
</div>
<div id="tab-browser" class="tab-content hidden absolute inset-0">
<div
class="w-72 bg-[#181818] border-r border-[#333] flex flex-col shrink-0"
>
<div class="p-4 border-b border-[#333] shrink-0">
<input
type="text"
id="cluster-search"
class="w-full bg-[#252526] border border-[#444] rounded px-3 py-2 text-xs text-white focus:border-violet-500 outline-none transition placeholder-gray-600"
placeholder="Filter clusters..."
/>
</div>
<div
id="cluster-list"
class="flex-1 overflow-y-auto p-2 space-y-1 min-h-0"
></div>
<div
class="p-4 border-t border-[#333] flex flex-col gap-2 shrink-0"
>
<button
id="download-btn"
class="hidden w-full bg-[#252526] hover:bg-[#333] text-gray-300 text-xs font-medium py-2.5 rounded border border-[#444] transition"
>
Download Results (.ZIP)
</button>
<button
id="delete-group-btn"
class="hidden w-full bg-red-900/20 hover:bg-red-900/40 text-red-400 text-xs font-medium py-2.5 rounded border border-red-900/30 transition"
>
Delete Entire Group
</button>
</div>
</div>
<div class="flex-1 flex flex-col min-w-0">
<div
class="h-14 border-b border-[#333] flex items-center justify-between px-6 bg-[#181818] shrink-0"
>
<h3
id="thumbnail-header"
class="font-semibold text-gray-200 text-sm"
>
Select a cluster
</h3>
<div class="flex gap-2">
<button
id="select-all-btn"
class="text-xs bg-[#252526] hover:bg-[#333] text-gray-300 border border-[#444] px-3 py-1.5 rounded font-medium transition"
>
All
</button>
<button
id="deselect-all-btn"
class="text-xs bg-[#252526] hover:bg-[#333] text-gray-300 border border-[#444] px-3 py-1.5 rounded font-medium transition"
>
None
</button>
<button
id="keep-best-btn"
class="text-xs bg-emerald-600/20 hover:bg-emerald-600/30 text-emerald-400 border border-emerald-600/30 px-4 py-1.5 rounded font-bold tracking-wide transition shadow-sm flex items-center gap-2"
>
<svg
class="w-3 h-3"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M5 13l4 4L19 7"
></path>
</svg>
Keep Best
</button>
</div>
</div>
<div
id="thumbnail-gallery"
class="flex-1 overflow-y-auto bg-[#121212] p-6 min-h-0"
></div>
<div
class="h-16 border-t border-[#333] bg-[#181818] flex items-center justify-end px-6 gap-3 shrink-0"
>
<button
id="delete-btn"
class="bg-red-500/10 hover:bg-red-500/20 text-red-400 border border-red-500/20 text-xs font-bold py-2.5 px-5 rounded disabled:opacity-30 disabled:cursor-not-allowed transition uppercase tracking-wide"
disabled
>
Delete Selected
</button>
<button
id="move-btn"
class="bg-amber-500/10 hover:bg-amber-500/20 text-amber-400 border border-amber-500/20 text-xs font-bold py-2.5 px-5 rounded disabled:opacity-30 disabled:cursor-not-allowed transition uppercase tracking-wide"
disabled
>
Move
</button>
<button
id="smart-cleanup-btn"
class="bg-violet-600 hover:bg-violet-500 text-white text-xs font-bold py-2.5 px-5 rounded disabled:opacity-50 disabled:cursor-not-allowed transition shadow-lg shadow-violet-500/20 uppercase tracking-wide"
>
Keep Selected & Delete Rest
</button>
</div>
</div>
</div>
<div
id="tab-stats"
class="tab-content h-full p-8 overflow-auto hidden bg-[#121212]"
>
<div id="stats-empty" class="text-center text-gray-600 mt-20 italic">
Run processing to view statistics.
</div>
<div id="stats-content" class="hidden w-full space-y-6">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
<div class="bg-[#1e1e1e] border border-[#333] rounded-xl p-5 relative h-80 flex flex-col">
<h4 class="text-lg font-bold text-gray-200 mb-2 shrink-0">
Cluster Size Distribution
</h4>
<div class="relative flex-1 min-h-0 w-full">
<canvas id="chart-dist-new"></canvas>
</div>
</div>
<div class="bg-[#1e1e1e] border border-[#333] rounded-xl p-5 relative h-80 flex flex-col">
<h4 class="text-lg font-bold text-gray-200 mb-2 shrink-0">
Deduplication Ratio
</h4>
<div class="relative flex-1 min-h-0 w-full flex justify-center">
<canvas id="chart-ratio-new"></canvas>
</div>
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<div class="bg-[#1e1e1e] border border-[#333] rounded-xl p-6 h-96 flex flex-col">
<h4 class="text-lg font-bold text-gray-200 mb-4 shrink-0">
Pipeline Timeline
</h4>
<div id="pipeline-steps" class="space-y-4 overflow-y-auto pr-2 custom-scrollbar flex-1">
</div>
</div>
<div class="lg:col-span-2 bg-[#1e1e1e] border border-[#333] rounded-xl p-6 flex flex-col h-96">
<div class="flex justify-between items-center mb-4 shrink-0">
<h4 class="text-lg font-bold text-gray-200">
Performance Metrics
</h4>
<div class="flex gap-4">
<span class="flex items-center gap-2 text-xs text-gray-400 font-medium">
<span class="w-2.5 h-2.5 rounded-full bg-violet-500"></span> Current
</span>
<span class="flex items-center gap-2 text-xs text-gray-400 font-medium">
<span class="w-2.5 h-2.5 rounded-full bg-[#333] border border-gray-600"></span> Benchmark
</span>
</div>
</div>
<div class="relative flex-1 min-h-0 w-full flex justify-center items-center">
<canvas id="chart-ai-radar"></canvas>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="tab-universe" class="tab-content hidden">
<div class="star-layer stars-tiny"></div>
<div class="star-layer stars-small"></div>
<div class="star-layer stars-medium"></div>
<div
id="universe-empty"
class="absolute inset-0 flex flex-col items-center justify-center z-20 pointer-events-none"
>
<div
class="w-24 h-24 mb-4 rounded-full bg-violet-600/20 animate-pulse blur-2xl"
></div>
<p class="text-gray-500 font-mono text-xs tracking-[0.2em]">
WAITING FOR DATA...
</p>
</div>
<div id="plotly-div"></div>
<div id="map-controls" class="bottom-controls glass-panel-ui hidden">
<label class="switch-label">
<input
type="checkbox"
id="toggle-rotate"
class="toggle-switch"
checked
/>
<span>Orbit</span>
</label>
<div class="w-px h-4 bg-white/20"></div>
<label class="switch-label">
<input type="checkbox" id="toggle-lines" class="toggle-switch" />
<span>Constellations</span>
</label>
</div>
<div
id="universe-tooltip"
class="absolute hidden bg-[#09090b]/95 border border-white/10 backdrop-blur-xl rounded-xl p-3 shadow-2xl flex flex-col items-center gap-2 w-48 z-[100] pointer-events-none transition-opacity"
>
<div
class="relative w-40 h-40 bg-black/50 rounded-lg overflow-hidden border border-white/5"
>
<img id="tooltip-img" class="w-full h-full object-contain" />
</div>
<div class="text-center w-full">
<div class="flex justify-center gap-2 mb-1">
<span
id="tooltip-cluster"
class="text-[9px] bg-white/10 px-1.5 py-0.5 rounded text-gray-300"
></span>
<span
id="tooltip-score"
class="text-[9px] bg-emerald-500/20 text-emerald-400 px-1.5 py-0.5 rounded font-bold"
></span>
</div>
<p
id="tooltip-name"
class="text-[10px] font-mono text-gray-400 truncate w-full"
></p>
</div>
</div>
</div>
</div>
</div>
<div
id="loading-overlay"
class="hidden fixed inset-0 bg-[#05010a]/95 z-[9999] flex items-center justify-center overflow-hidden"
>
<div class="loading-bg-logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400">
<defs>
<radialGradient
id="goldCoreBg"
cx="50%"
cy="50%"
r="50%"
fx="50%"
fy="50%"
>
<stop offset="0%" style="stop-color: #ffffff; stop-opacity: 1" />
<stop offset="30%" style="stop-color: #fcd34d; stop-opacity: 1" />
<stop
offset="70%"
style="stop-color: #d97706; stop-opacity: 0.8"
/>
<stop
offset="100%"
style="stop-color: #7c2d12; stop-opacity: 0"
/>
</radialGradient>
<linearGradient id="dupeEnergyBg" x1="0%" y1="0%" x2="100%" y2="0%">
<stop
offset="0%"
style="stop-color: #6a0dad; stop-opacity: 0.6"
/>
<stop
offset="100%"
style="stop-color: #3b82f6; stop-opacity: 0.6"
/>
</linearGradient>
<filter
id="intenseGlowBg"
x="-100%"
y="-100%"
width="300%"
height="300%"
>
<feGaussianBlur stdDeviation="8" result="coloredBlur" />
<feMerge>
<feMergeNode in="coloredBlur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<g transform="translate(200, 200)">
<g opacity="0.3">
<circle
cx="-40"
cy="0"
r="100"
fill="url(#dupeEnergyBg)"
filter="url(#intenseGlowBg)"
opacity="0.5"
style="mix-blend-mode: screen"
/>
<circle
cx="40"
cy="0"
r="100"
fill="url(#dupeEnergyBg)"
filter="url(#intenseGlowBg)"
opacity="0.5"
transform="scale(-1,1)"
style="mix-blend-mode: screen"
/>
</g>
<g filter="url(#intenseGlowBg)">
<circle
cx="0"
cy="0"
r="50"
fill="url(#goldCoreBg)"
opacity="0.7"
/>
<line
x1="-150"
y1="0"
x2="150"
y2="0"
stroke="#fcd34d"
stroke-width="4"
opacity="0.5"
stroke-linecap="round"
/>
<line
x1="0"
y1="-150"
x2="0"
y2="150"
stroke="#fcd34d"
stroke-width="4"
opacity="0.5"
stroke-linecap="round"
/>
</g>
</g>
</svg>
</div>
<div
class="bg-[#1c1c1c] rounded-2xl p-8 max-w-md w-full shadow-2xl relative overflow-hidden flex flex-col items-center"
>
<div class="loading-fg-logo-container">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="100 50 400 300"
class="w-full h-full"
>
<defs>
<radialGradient
id="goldCoreFg"
cx="50%"
cy="50%"
r="50%"
fx="50%"
fy="50%"
>
<stop
offset="0%"
style="stop-color: #ffffff; stop-opacity: 1"
/>
<stop
offset="30%"
style="stop-color: #fcd34d; stop-opacity: 1"
/>
<stop
offset="70%"
style="stop-color: #d97706; stop-opacity: 0.8"
/>
<stop
offset="100%"
style="stop-color: #7c2d12; stop-opacity: 0"
/>
</radialGradient>
<linearGradient
id="dupeEnergyFg"
x1="0%"
y1="0%"
x2="100%"
y2="0%"
>
<stop
offset="0%"
style="stop-color: #6a0dad; stop-opacity: 0.6"
/>
<stop
offset="100%"
style="stop-color: #3b82f6; stop-opacity: 0.6"
/>
</linearGradient>
<filter
id="intenseGlowFg"
x="-100%"
y="-100%"
width="300%"
height="300%"
>
<feGaussianBlur stdDeviation="5" result="coloredBlur" />
<feMerge>
<feMergeNode in="coloredBlur" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
</defs>
<g transform="translate(300, 180)">
<g opacity="0.8">
<circle
cx="-40"
cy="0"
r="45"
fill="url(#dupeEnergyFg)"
filter="url(#intenseGlowFg)"
opacity="0.5"
style="mix-blend-mode: screen"
/>
<circle
cx="40"
cy="0"
r="45"
fill="url(#dupeEnergyFg)"
filter="url(#intenseGlowFg)"
opacity="0.5"
transform="scale(-1,1)"
style="mix-blend-mode: screen"
/>
</g>
<g class="pulse-core" filter="url(#intenseGlowFg)">
<circle
cx="0"
cy="0"
r="28"
fill="url(#goldCoreFg)"
opacity="0.8"
/>
<line
x1="-60"
y1="0"
x2="60"
y2="0"
stroke="#fcd34d"
stroke-width="2"
opacity="0.9"
stroke-linecap="round"
/>
<line
x1="0"
y1="-60"
x2="0"
y2="60"
stroke="#fcd34d"
stroke-width="2"
opacity="0.9"
stroke-linecap="round"
/>
<path
d="M0,-22 L18,0 L0,22 L-18,0 Z"
fill="#ffffff"
stroke="#fcd34d"
stroke-width="1"
/>
</g>
</g>
</svg>
</div>
<h3
class="text-xl font-bold text-white mb-2 text-center tracking-wide uppercase"
>
Processing...
</h3>
<p
id="loading-text"
class="text-sm text-gray-400 mb-6 text-center font-mono"
>
Initializing pipeline & analyzing assets...
</p>
<div class="w-full bg-[#333] rounded-full h-2 overflow-hidden relative">
<div class="absolute inset-0 bg-violet-900/30 animate-pulse"></div>
<div
id="loading-bar"
class="bg-gradient-to-r from-violet-600 via-fuchsia-500 to-indigo-600 h-full transition-all duration-300 relative relative"
style="width: 0%; box-shadow: 0 0 20px rgba(139, 92, 246, 0.5)"
>
<div
class="absolute top-0 right-0 bottom-0 w-20 bg-gradient-to-r from-transparent to-white/30 animate-shimmer"
style="transform: skewX(-20deg) translateX(-100%)"
></div>
</div>
</div>
</div>
</div>
<div
id="image-modal"
class="hidden fixed inset-0 bg-black/95 z-[10000] flex items-center justify-center p-8 backdrop-blur-sm group"
onclick="this.classList.add('hidden')"
>
<div
class="absolute inset-0 pointer-events-none z-10 bg-scanline opacity-20"
></div>
<div
class="absolute inset-0 pointer-events-none z-20 border-[1px] border-white/10 m-10 rounded-lg"
>
<div
class="absolute top-0 left-0 w-4 h-4 border-t-2 border-l-2 border-violet-500"
></div>
<div
class="absolute top-0 right-0 w-4 h-4 border-t-2 border-r-2 border-violet-500"
></div>
<div
class="absolute bottom-0 left-0 w-4 h-4 border-b-2 border-l-2 border-violet-500"
></div>
<div
class="absolute bottom-0 right-0 w-4 h-4 border-b-2 border-r-2 border-violet-500"
></div>
</div>
<img
id="modal-image"
class="max-w-full max-h-full object-contain rounded shadow-2xl border border-white/10 transition-transform duration-500 scale-95 opacity-0 modal-img-anim"
/>
</div>
<div
id="move-modal"
class="hidden fixed inset-0 bg-black/80 z-[10000] flex items-center justify-center backdrop-blur-sm"
>
<div
class="bg-[#1c1c1c] border border-[#333] rounded-xl p-6 w-96 shadow-2xl"
>
<h3 class="text-lg font-bold text-white mb-4">Move Images</h3>
<div class="mb-4">
<label class="block text-xs text-gray-400 mb-1 uppercase font-bold"
>Destination Cluster</label
>
<select
id="move-cluster-select"
class="w-full bg-[#252526] border border-[#444] rounded px-3 py-2.5 text-sm text-white outline-none focus:border-violet-500"
></select>
</div>
<div id="move-new-cluster-input-group" class="mb-6 hidden">
<label class="block text-xs text-gray-400 mb-1 uppercase font-bold"
>New Name</label
>
<input
id="move-new-cluster-name"
type="text"
class="w-full bg-[#252526] border border-[#444] rounded px-3 py-2.5 text-sm text-white outline-none focus:border-violet-500"
placeholder="e.g., group_favorites"
/>
</div>
<div class="flex justify-end gap-3">
<button
id="move-cancel-btn"
class="px-4 py-2 rounded text-xs font-bold text-gray-400 hover:bg-[#333] transition"
>
CANCEL
</button>
<button
id="move-confirm-btn"
class="px-4 py-2 rounded text-xs font-bold bg-violet-600 hover:bg-violet-500 text-white shadow-lg transition"
>
CONFIRM MOVE
</button>
</div>
</div>
</div>
<script type="module" src="/static/script.js"></script>
</body>
</html>