watermark-remover / static /index.html
the-adrianator's picture
Initial commit: AI watermark remover
b2c1b6b
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Watermark Remover</title>
<link rel="stylesheet" href="/static/style.css" />
</head>
<body>
<div class="app">
<!-- Header -->
<header>
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="#6366f1" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="3" width="18" height="18" rx="2"/>
<path d="M3 9h18M9 21V9"/>
</svg>
<h1>Watermark Remover</h1>
<div id="caps-bar"></div>
</header>
<!-- Workspace -->
<div class="workspace">
<!-- Main area (left) -->
<div class="canvas-area">
<!-- 1. Drop zone -->
<div class="drop-zone" id="drop-zone">
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
<polyline points="17 8 12 3 7 8"/>
<line x1="12" y1="3" x2="12" y2="15"/>
</svg>
<p>Drop an image or video here</p>
<button class="btn btn-secondary btn-sm" id="choose-btn">Choose file</button>
<input type="file" id="file-input" accept="image/*,video/mp4,video/quicktime,video/x-msvideo,video/x-matroska,video/webm" hidden />
</div>
<!-- 2. Mask panel — canvas + optional video player -->
<div class="mask-panel hidden" id="mask-panel">
<!-- Video source player (videos only) -->
<div class="source-video-bar hidden" id="source-video-bar">
<video id="source-video" controls preload="metadata"></video>
<p class="hint" style="text-align:center;margin-top:4px">Watch original · draw mask on the frame below</p>
</div>
<!-- Canvas for mask drawing -->
<div class="canvas-scroll" id="canvas-scroll">
<div class="canvas-wrap" id="canvas-wrap">
<canvas id="img-canvas"></canvas>
<canvas id="overlay-canvas"></canvas>
</div>
</div>
<!-- Toolbar -->
<div class="toolbar" id="toolbar">
<label>
Brush
<input type="range" id="brush-size" min="4" max="120" value="24" />
<span id="brush-label">24px</span>
</label>
<div class="toolbar-sep"></div>
<button class="tool-btn active" id="brush-btn">Brush</button>
<button class="tool-btn" id="box-btn">Box</button>
<button class="tool-btn" id="eraser-btn">Eraser</button>
<button class="tool-btn" id="sam-btn" title="Click on the watermark — AI segments it automatically">SAM ✦</button>
<button class="tool-btn" id="clear-btn">Clear mask</button>
<div class="toolbar-sep"></div>
<span class="file-name-label" id="file-name-label"></span>
<button class="tool-btn btn-sm" id="change-file-btn" style="margin-left:auto">Change file</button>
</div>
</div><!-- /mask-panel -->
<!-- 3. Compare panel — before/after slider -->
<div class="compare-panel hidden" id="compare-panel">
<div class="compare-wrap" id="compare-wrap">
<!-- After layer (result) — always fully visible -->
<div class="compare-layer compare-after" id="compare-after">
<img id="cmp-after-img" alt="After" />
<video id="cmp-after-video" preload="metadata" loop playsinline></video>
</div>
<!-- Before layer (original) — clipped by handle -->
<div class="compare-layer compare-before" id="compare-before">
<img id="cmp-before-img" alt="Before" />
<video id="cmp-before-video" preload="metadata" loop playsinline muted></video>
</div>
<!-- Divider handle -->
<div class="compare-handle" id="compare-handle">
<div class="compare-line"></div>
<div class="compare-knob">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<polyline points="15 18 9 12 15 6"/>
</svg>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<polyline points="9 18 15 12 9 6"/>
</svg>
</div>
</div>
<!-- Labels -->
<span class="cmp-label cmp-label-before">Before</span>
<span class="cmp-label cmp-label-after">After</span>
</div>
<!-- Video controls bar (videos only) -->
<div class="compare-video-bar hidden" id="compare-video-bar">
<button class="tool-btn" id="cmp-play-btn">
<svg id="cmp-play-icon" width="13" height="13" viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>
Play
</button>
<input type="range" id="cmp-seek" min="0" max="100" value="0" step="0.1" style="flex:1" />
<span id="cmp-time" style="font-size:11px;color:var(--muted);white-space:nowrap">0:00 / 0:00</span>
</div>
<!-- Back to mask / new file -->
<div class="compare-toolbar">
<button class="tool-btn" id="back-to-mask-btn">← Edit mask</button>
<span class="file-name-label" id="cmp-file-label"></span>
<button class="tool-btn btn-sm" id="new-file-btn" style="margin-left:auto">Load new file</button>
</div>
</div><!-- /compare-panel -->
</div><!-- /canvas-area -->
<!-- Sidebar (right) -->
<div class="sidebar">
<!-- Method -->
<div>
<h2>Method</h2>
<div class="control-group" style="margin-top:10px">
<label>Inpainting engine</label>
<div class="segmented" id="method-seg">
<button class="active" data-val="opencv">OpenCV <span style="opacity:.5;font-size:10px">Fast</span></button>
<button data-val="lama" id="lama-btn">LaMa <span style="opacity:.5;font-size:10px">Quality</span></button>
<button data-val="sd" id="sd-btn">SD <span style="opacity:.5;font-size:10px">Best</span></button>
</div>
<p class="hint">OpenCV: instant. LaMa: ML quality. SD: Stable Diffusion — near-invisible results, ~20s on M4.</p>
</div>
</div>
<hr class="divider" />
<!-- Video options -->
<div id="video-opts" class="hidden">
<h2>Video</h2>
<div class="control-group" style="margin-top:10px">
<label>Processing mode</label>
<div class="segmented" id="mode-seg">
<button class="active" data-val="fast">Fast</button>
<button data-val="thorough">Thorough</button>
</div>
<p class="hint"><b>Fast:</b> one inpaint, applied to all frames. <b>Thorough:</b> inpaints every frame — handles moving watermarks, much slower.</p>
</div>
<hr class="divider" style="margin-top:16px"/>
</div>
<!-- Actions -->
<div>
<h2>Actions</h2>
<div class="sidebar-actions" style="margin-top:10px">
<button class="btn btn-secondary" id="detect-btn" disabled>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>
Auto Detect
</button>
<button class="btn btn-primary" id="process-btn" disabled>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
Remove Watermark
</button>
</div>
</div>
<!-- Status -->
<div class="status-block hidden" id="status-block">
<div class="spinner hidden" id="status-spinner"></div>
<div class="status-body">
<span id="status-text">Processing…</span>
<div class="progress-wrap hidden" id="progress-wrap">
<div class="progress-track">
<div class="progress-fill" id="progress-fill"></div>
</div>
<span class="progress-label" id="progress-label">0%</span>
</div>
</div>
</div>
<hr class="divider" />
<!-- Result -->
<div id="result-section" class="hidden">
<h2>Result</h2>
<div class="sidebar-actions" style="margin-top:10px">
<a class="btn btn-primary hidden" id="download-btn" download>
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
Download
</a>
</div>
</div>
</div><!-- /sidebar -->
</div><!-- /workspace -->
</div>
<script src="/static/app.js"></script>
</body>
</html>