|
|
<!DOCTYPE html> |
|
|
<html lang="en"> |
|
|
|
|
|
<head> |
|
|
<meta charset="UTF-8"> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
|
<title>Sharp</title> |
|
|
<link rel="preconnect" href="https://fonts.googleapis.com"> |
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> |
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet"> |
|
|
<link rel="stylesheet" href="{{ url_for('static', path='css/styles.css') }}"> |
|
|
<script type="importmap"> |
|
|
{ |
|
|
"imports": { |
|
|
"three": "https://esm.sh/three@0.164.0", |
|
|
"@mkkellogg/gaussian-splats-3d": "https://esm.sh/@mkkellogg/gaussian-splats-3d@0.4.6" |
|
|
} |
|
|
} |
|
|
</script> |
|
|
</head> |
|
|
|
|
|
<body> |
|
|
<canvas id="particleCanvas"></canvas> |
|
|
|
|
|
<button class="theme-toggle" id="themeToggle" aria-label="Toggle theme"> |
|
|
<svg class="sun-icon" viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" |
|
|
stroke-linejoin="round"> |
|
|
<circle cx="12" cy="12" r="5" /> |
|
|
<line x1="12" y1="1" x2="12" y2="3" /> |
|
|
<line x1="12" y1="21" x2="12" y2="23" /> |
|
|
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" /> |
|
|
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" /> |
|
|
<line x1="1" y1="12" x2="3" y2="12" /> |
|
|
<line x1="21" y1="12" x2="23" y2="12" /> |
|
|
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" /> |
|
|
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" /> |
|
|
</svg> |
|
|
<svg class="moon-icon" viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" |
|
|
stroke-linejoin="round"> |
|
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" /> |
|
|
</svg> |
|
|
</button> |
|
|
|
|
|
<div class="app-container"> |
|
|
<header class="header"> |
|
|
<h1 class="logo">Sharp</h1> |
|
|
<p class="tagline">Transform images into Gaussian Splats</p> |
|
|
</header> |
|
|
|
|
|
<div class="card"> |
|
|
<form id="uploadForm"> |
|
|
<div class="upload-zone" id="dropZone"> |
|
|
<div class="upload-icon"> |
|
|
<svg viewBox="0 0 24 24" fill="none" stroke-width="1.5" stroke-linecap="round" |
|
|
stroke-linejoin="round"> |
|
|
<path d="M12 16V4m0 0l-4 4m4-4l4 4" /> |
|
|
<path d="M3 20h18" /> |
|
|
</svg> |
|
|
</div> |
|
|
<div class="upload-text"> |
|
|
<h3>Drop your image here</h3> |
|
|
<p>or click to browse</p> |
|
|
</div> |
|
|
<input type="file" id="fileInput" name="files" accept="image/*" style="display: none"> |
|
|
</div> |
|
|
|
|
|
<div class="file-list" id="fileList"></div> |
|
|
|
|
|
<button type="submit" class="submit-btn" id="submitBtn"> |
|
|
<span> |
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" |
|
|
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> |
|
|
<path d="M12 3v18M3 12l9 9 9-9" /> |
|
|
</svg> |
|
|
Generate |
|
|
</span> |
|
|
</button> |
|
|
</form> |
|
|
|
|
|
<div class="loader-container" id="loaderContainer"> |
|
|
<div class="loader"></div> |
|
|
<p class="loader-text">Generating Gaussian Splats...</p> |
|
|
<p class="loader-subtext">This may take a moment</p> |
|
|
</div> |
|
|
|
|
|
<div class="results" id="results"></div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="viewer-container" id="viewerContainer"> |
|
|
<button class="back-btn" id="backBtn"> |
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" |
|
|
stroke-linejoin="round"> |
|
|
<path d="M19 12H5M12 19l-7-7 7-7" /> |
|
|
</svg> |
|
|
Back to Upload |
|
|
</button> |
|
|
|
|
|
<div class="viewer-header"> |
|
|
<div class="viewer-title"> |
|
|
<h3>3D Gaussian Splat Viewer</h3> |
|
|
<span class="file-badge" id="viewerFilename">output.ply</span> |
|
|
</div> |
|
|
<div class="viewer-actions"> |
|
|
<button class="viewer-btn" id="resetViewBtn"> |
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" |
|
|
stroke-linecap="round" stroke-linejoin="round"> |
|
|
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" /> |
|
|
<path d="M3 3v5h5" /> |
|
|
</svg> |
|
|
Reset View |
|
|
</button> |
|
|
<button class="viewer-btn primary" id="downloadBtn"> |
|
|
<svg 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 PLY |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="viewer-canvas-container" id="viewerCanvasContainer"> |
|
|
<div class="viewer-controls-hint" id="controlsHint"> |
|
|
🖱️ Left click + drag to rotate • Scroll to zoom • Right click + drag to pan |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<div class="viewer-footer"> |
|
|
<span>Powered by <a href="https://threejs.org/" target="_blank" rel="noopener">Three.js</a> & <a |
|
|
href="https://github.com/mkkellogg/GaussianSplats3D" target="_blank" rel="noopener">Gaussian |
|
|
Splats 3D</a></span> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
<footer class="footer"> |
|
|
<p><a href="https://apple.github.io/ml-sharp/" target="_blank" rel="noopener">Mescheder et al., 2025</a> • |
|
|
Sharp: Monocular View Synthesis in Less Than a Second</p> |
|
|
</footer> |
|
|
</div> |
|
|
|
|
|
|
|
|
<script src="{{ url_for('static', path='js/main.js') }}"></script> |
|
|
|
|
|
|
|
|
<script type="module" src="{{ url_for('static', path='js/viewer.js') }}"></script> |
|
|
</body> |
|
|
|
|
|
</html> |