Spaces:
Sleeping
Sleeping
Host WebGL viewer through Gradio wrapper
Browse files- README.md +2 -2
- app.py +61 -8
- requirements.txt +1 -1
- src/main.js +3 -1
README.md
CHANGED
|
@@ -3,8 +3,8 @@ title: Gaussian Splat Walkthrough
|
|
| 3 |
emoji: 🌀
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: green
|
| 6 |
-
sdk:
|
| 7 |
-
app_file:
|
| 8 |
pinned: false
|
| 9 |
license: mit
|
| 10 |
---
|
|
|
|
| 3 |
emoji: 🌀
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: green
|
| 6 |
+
sdk: gradio
|
| 7 |
+
app_file: app.py
|
| 8 |
pinned: false
|
| 9 |
license: mit
|
| 10 |
---
|
app.py
CHANGED
|
@@ -1,13 +1,66 @@
|
|
| 1 |
-
from
|
|
|
|
| 2 |
|
|
|
|
| 3 |
|
| 4 |
-
class Handler(SimpleHTTPRequestHandler):
|
| 5 |
-
def end_headers(self):
|
| 6 |
-
self.send_header("Cross-Origin-Opener-Policy", "same-origin")
|
| 7 |
-
self.send_header("Cross-Origin-Embedder-Policy", "require-corp")
|
| 8 |
-
self.send_header("Cache-Control", "no-store")
|
| 9 |
-
super().end_headers()
|
| 10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
if __name__ == "__main__":
|
| 13 |
-
|
|
|
|
| 1 |
+
from pathlib import Path
|
| 2 |
+
import html
|
| 3 |
|
| 4 |
+
import gradio as gr
|
| 5 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
+
ROOT = Path(__file__).parent.resolve()
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
def build_iframe() -> str:
|
| 11 |
+
document = (ROOT / "index.html").read_text(encoding="utf-8")
|
| 12 |
+
document = document.replace('href="/src/styles.css"', 'href="/gradio_api/file=src/styles.css"')
|
| 13 |
+
document = document.replace('src="/src/main.js"', 'src="/gradio_api/file=src/main.js"')
|
| 14 |
+
srcdoc = html.escape(document, quote=True)
|
| 15 |
+
return f"""
|
| 16 |
+
<iframe
|
| 17 |
+
title="Gaussian Splat Walkthrough"
|
| 18 |
+
srcdoc="{srcdoc}"
|
| 19 |
+
allow="fullscreen; xr-spatial-tracking"
|
| 20 |
+
sandbox="allow-scripts allow-same-origin allow-pointer-lock allow-forms allow-popups"
|
| 21 |
+
style="position:fixed; inset:0; width:100vw; height:100vh; border:0; background:#030607;"
|
| 22 |
+
></iframe>
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
css = """
|
| 27 |
+
html, body, gradio-app, .gradio-container {
|
| 28 |
+
margin: 0 !important;
|
| 29 |
+
width: 100% !important;
|
| 30 |
+
min-width: 100% !important;
|
| 31 |
+
height: 100% !important;
|
| 32 |
+
min-height: 100vh !important;
|
| 33 |
+
overflow: hidden !important;
|
| 34 |
+
background: #030607 !important;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
.gradio-container {
|
| 38 |
+
max-width: none !important;
|
| 39 |
+
padding: 0 !important;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
footer,
|
| 43 |
+
.footer {
|
| 44 |
+
display: none !important;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
#splat-frame {
|
| 48 |
+
position: fixed !important;
|
| 49 |
+
inset: 0 !important;
|
| 50 |
+
width: 100vw !important;
|
| 51 |
+
height: 100vh !important;
|
| 52 |
+
padding: 0 !important;
|
| 53 |
+
margin: 0 !important;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
#splat-frame > div {
|
| 57 |
+
padding: 0 !important;
|
| 58 |
+
margin: 0 !important;
|
| 59 |
+
}
|
| 60 |
+
"""
|
| 61 |
+
|
| 62 |
+
with gr.Blocks(css=css, title="Gaussian Splat Walkthrough", fill_height=True) as demo:
|
| 63 |
+
gr.HTML(build_iframe(), elem_id="splat-frame")
|
| 64 |
|
| 65 |
if __name__ == "__main__":
|
| 66 |
+
demo.launch(allowed_paths=[str(ROOT)])
|
requirements.txt
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
|
|
|
|
| 1 |
+
gradio>=5.0,<6.0
|
src/main.js
CHANGED
|
@@ -129,6 +129,7 @@ let frameBucketStart = lastTime;
|
|
| 129 |
let frameCount = 0;
|
| 130 |
let isWalking = false;
|
| 131 |
let tourEnabled = true;
|
|
|
|
| 132 |
let yaw = 0;
|
| 133 |
let pitch = 0;
|
| 134 |
let basis;
|
|
@@ -200,12 +201,13 @@ function stopTour() {
|
|
| 200 |
|
| 201 |
function startTour() {
|
| 202 |
tourEnabled = true;
|
|
|
|
| 203 |
dom.tourButton.classList.add('active');
|
| 204 |
dom.tourButton.innerHTML = '<span class="button-icon">Ⅱ</span> Tour';
|
| 205 |
}
|
| 206 |
|
| 207 |
function updateTour(time) {
|
| 208 |
-
const t = time * 0.00009;
|
| 209 |
const radius = currentScene.tourRadius;
|
| 210 |
const side = basis.right.clone().multiplyScalar(Math.cos(t) * radius);
|
| 211 |
const forward = basis.forward.clone().multiplyScalar(Math.sin(t) * radius);
|
|
|
|
| 129 |
let frameCount = 0;
|
| 130 |
let isWalking = false;
|
| 131 |
let tourEnabled = true;
|
| 132 |
+
let tourStartTime = 0;
|
| 133 |
let yaw = 0;
|
| 134 |
let pitch = 0;
|
| 135 |
let basis;
|
|
|
|
| 201 |
|
| 202 |
function startTour() {
|
| 203 |
tourEnabled = true;
|
| 204 |
+
tourStartTime = performance.now();
|
| 205 |
dom.tourButton.classList.add('active');
|
| 206 |
dom.tourButton.innerHTML = '<span class="button-icon">Ⅱ</span> Tour';
|
| 207 |
}
|
| 208 |
|
| 209 |
function updateTour(time) {
|
| 210 |
+
const t = Math.max(0, time - tourStartTime) * 0.00009;
|
| 211 |
const radius = currentScene.tourRadius;
|
| 212 |
const side = basis.right.clone().multiplyScalar(Math.cos(t) * radius);
|
| 213 |
const forward = basis.forward.clone().multiplyScalar(Math.sin(t) * radius);
|