Download viewer/index.html from akashch1512/SingleViewHeigthEstimation: direct link, hf CLI and curl.
- Browser
- Download file 12 kB
-
https://huggingface.co/spaces/akashch1512/SingleViewHeigthEstimation/resolve/main/viewer/index.html
- Command line
-
hf download hf://spaces/akashch1512/SingleViewHeigthEstimation/viewer/index.html
-
curl -L -o index.html https://huggingface.co/spaces/akashch1512/SingleViewHeigthEstimation/resolve/main/viewer/index.html
12 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>DepthWizard — DSM viewer & 3D flythrough</title> | |
| <style> | |
| :root{ | |
| color-scheme: dark; | |
| --bg:#0d1013; --panel:#151a20; --line:#252c34; --ink:#e8ecf1; --dim:#8a949e; | |
| --accent:#2d6cdf; --warn:#e5793a; | |
| } | |
| *{box-sizing:border-box} | |
| html,body{height:100%} | |
| body{margin:0;background:var(--bg);color:var(--ink);overflow:hidden; | |
| font:13px/1.6 system-ui,-apple-system,"Segoe UI",sans-serif; | |
| display:grid;grid-template-columns:280px 1fr;} | |
| body.collapsed{grid-template-columns:0 1fr} | |
| body.collapsed aside{display:none} | |
| /* ---- sidebar ---- */ | |
| aside{background:var(--panel);border-right:1px solid var(--line); | |
| overflow-y:auto;padding:16px 16px 40px;position:relative} | |
| #collapseAside{position:absolute;top:10px;right:10px;flex:none; | |
| width:auto;padding:3px 7px} | |
| h1{font-size:16px;margin:0 0 2px;letter-spacing:.2px} | |
| .tag{color:var(--dim);font-size:12px;margin:0 0 16px} | |
| section{border-top:1px solid var(--line);padding:13px 0} | |
| section:first-of-type{border-top:0;padding-top:0} | |
| h2{font-size:12px;text-transform:uppercase;letter-spacing:.07em;color:var(--dim); | |
| margin:0 0 9px;font-weight:600} | |
| label{display:block;margin:9px 0 3px;color:#b8c2cc;font-size:13px;cursor:pointer} | |
| input[type=range]{width:100%;accent-color:var(--accent)} | |
| select,input[type=file]{width:100%;background:#0f1318;color:var(--ink); | |
| border:1px solid var(--line);border-radius:6px;padding:6px 8px;font:inherit;font-size:13px} | |
| .row{display:flex;gap:8px;align-items:center;margin-top:8px} | |
| .row.chk{color:#b8c2cc;font-size:13px} | |
| .row.chk label{display:inline;margin:0;cursor:pointer} | |
| .btns{display:flex;gap:6px;margin-top:10px;flex-wrap:wrap} | |
| button{flex:1 1 auto;padding:7px 9px;background:#242c35;color:var(--ink); | |
| border:1px solid var(--line);border-radius:6px;cursor:pointer;font:inherit;font-size:13px} | |
| button:hover{background:#2c3540} | |
| button.on{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600} | |
| button[aria-pressed=true]{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600} | |
| #info,#probe,#metrics{color:#b8c2cc;font-size:13px} | |
| #probe{min-height:44px} | |
| #metrics table{width:100%;border-collapse:collapse} | |
| #metrics td{padding:2px 0;font-variant-numeric:tabular-nums} | |
| #metrics td:last-child{text-align:right} | |
| .dim{color:var(--dim)} | |
| code{background:#0f1318;padding:1px 4px;border-radius:3px;font-size:12px} | |
| #warn{display:none;background:#2a1f14;border:1px solid #5a3d1e;border-left:3px solid var(--warn); | |
| border-radius:6px;padding:8px 10px;margin-top:10px;font-size:12.5px;color:#f0c9a0} | |
| #warn div{padding:2px 0} | |
| #profile{width:100%;height:76px;background:#0f1318;border:1px solid var(--line); | |
| border-radius:6px;margin-top:8px;display:block} | |
| /* ---- panes ---- */ | |
| main{display:grid;grid-template-columns:minmax(0,38%) minmax(0,1fr);min-width:0} | |
| body.only3d main{grid-template-columns:0 1fr} | |
| body.only3d #pane2d{display:none} | |
| .pane{position:relative;min-width:0;overflow:hidden} | |
| #pane2d{border-right:1px solid var(--line);display:flex;flex-direction:column;background:#0a0d10} | |
| .paneBar{height:34px;display:flex;align-items:center;gap:8px;padding:0 10px; | |
| border-bottom:1px solid var(--line);color:var(--dim);font-size:12px;flex:none} | |
| .paneBar select{width:auto;padding:3px 6px;font-size:12px} | |
| .paneBar label{display:flex;margin:0;font-size:12px} | |
| #map{flex:1;width:100%;min-height:0;touch-action:none} | |
| #pane3d canvas{display:block} | |
| #hud{position:absolute;top:10px;right:12px;display:flex;gap:8px; | |
| font-size:12px;color:var(--dim);background:rgba(13,16,19,.72); | |
| padding:5px 9px;border-radius:6px;border:1px solid var(--line); | |
| font-variant-numeric:tabular-nums} | |
| #hint{position:absolute;left:12px;bottom:10px;color:var(--dim);font-size:12px; | |
| background:rgba(13,16,19,.72);padding:5px 9px;border-radius:6px; | |
| border:1px solid var(--line);max-width:calc(100% - 24px)} | |
| /* embedded in the Space: the model has already run, so there is nothing to | |
| pick — drop the loader and promote the section that follows it. The host | |
| page already names the product, so the viewer's own header is redundant | |
| inside the frame (and previously disagreed with it). Validation and the | |
| reference-surface options are dead weight too: there is no file picker to | |
| load gt_ndsm_m.npy from. */ | |
| body.embedded h1, body.embedded .tag{display:none} | |
| body.embedded #loadSection{display:none} | |
| body.embedded #validationSection{display:none} | |
| body.embedded section:nth-of-type(2){border-top:0;padding-top:0} | |
| body.embedded #layer option[value=reference], body.embedded #layer option[value=error], | |
| body.embedded #layer2d option[value=reference], body.embedded #layer2d option[value=error]{ | |
| display:none} | |
| /* This query is evaluated against the *iframe's* own width, which in a 3:1 | |
| host column split is often well under 900px on an ordinary laptop even | |
| though the page itself is nowhere near mobile-sized — that reads as a | |
| bug, not a responsive layout. Lowered so only a genuinely narrow frame | |
| (phone-embed width, or the standalone page on a small window) triggers | |
| it; `app.py` also sets a `min_width` on the host column so the frame | |
| itself stays wide on desktop. */ | |
| @media (max-width:560px){ | |
| body{grid-template-columns:1fr;grid-template-rows:auto 1fr} | |
| aside{max-height:44vh} | |
| main{grid-template-columns:1fr} | |
| #pane2d{display:none} | |
| } | |
| button.on{position:relative} | |
| #warn{max-height:160px;overflow-y:auto} | |
| #warnDismiss{display:none;margin-top:6px;padding:3px 8px;font-size:11px;flex:none} | |
| #warn.show + #warnDismiss{display:inline-block} | |
| .colorbar-wrap{position:absolute;display:flex;flex-direction:column; | |
| align-items:center;font-size:10px;color:var(--dim); | |
| background:rgba(13,16,19,.72);padding:6px 4px;border-radius:6px; | |
| border:1px solid var(--line);pointer-events:none} | |
| #colorbar3d{right:12px;bottom:44px} | |
| #colorbar2d{right:8px;top:40px} | |
| #scalebar{position:absolute;left:10px;bottom:10px;pointer-events:none} | |
| #meshSpinner{display:none;position:absolute;inset:0;align-items:center; | |
| justify-content:center;flex-direction:column;gap:10px;font-size:13px; | |
| color:var(--ink);background:rgba(10,13,16,.55)} | |
| #meshSpinner.show{display:flex} | |
| .spin{width:26px;height:26px;border-radius:50%;border:3px solid var(--line); | |
| border-top-color:var(--accent);animation:spin .8s linear infinite} | |
| @keyframes spin{to{transform:rotate(360deg)}} | |
| </style> | |
| </head> | |
| <body> | |
| <aside> | |
| <button id="collapseAside" title="Hide sidebar" aria-label="Hide sidebar">◂</button> | |
| <h1>DepthWizard</h1> | |
| <p class="tag">single-view DSM · 3D flythrough · SIH 2026 PS 26175</p> | |
| <section id="loadSection"> | |
| <h2>Load a prediction</h2> | |
| <label for="files">Prediction folder</label> | |
| <input type="file" id="files" multiple | |
| accept=".png,.jpg,.json,.npy" | |
| title="select ndsm_m.npy, rgb.png, meta.json (and gt_ndsm_m.npy to validate)" /> | |
| <p class="dim" style="margin:8px 0 0;font-size:12px"> | |
| Pick the whole output folder of<br><code>python -m infer.predict …</code><br> | |
| <code>ndsm_m.npy</code> + <code>meta.json</code> is the minimum; | |
| add <code>rgb.png</code> to drape the optical image and | |
| <code>gt_ndsm_m.npy</code> to score it live. | |
| </p> | |
| <div id="warn" aria-live="polite"></div> | |
| <button id="warnDismiss">Dismiss</button> | |
| <div id="info" style="margin-top:10px">nothing loaded yet</div> | |
| </section> | |
| <section> | |
| <h2>Camera</h2> | |
| <div class="btns" role="group" aria-label="Camera mode"> | |
| <button data-mode="orbit" class="on" aria-pressed="true">Orbit</button> | |
| <button data-mode="fp" aria-pressed="false">First person</button> | |
| <button data-mode="fly" aria-pressed="false">Drone</button> | |
| </div> | |
| <div class="btns"> | |
| <button id="reset">Reset view</button> | |
| <button id="split">2D pane</button> | |
| <button id="fullscreen">Fullscreen</button> | |
| </div> | |
| </section> | |
| <section> | |
| <h2>Surface</h2> | |
| <label for="layer">3D drape</label> | |
| <select id="layer"> | |
| <option value="rgb">Optical RGB (projected)</option> | |
| <option value="height">Height colormap</option> | |
| <option value="hillshade">Hillshade</option> | |
| <option value="reference" disabled>Reference height</option> | |
| <option value="error" disabled>Error vs reference</option> | |
| </select> | |
| <label for="vex">Vertical exaggeration <span id="vexLabel">1.0×</span></label> | |
| <input type="range" id="vex" min="0.2" max="8" step="0.1" value="1" /> | |
| <label for="quality">Mesh detail</label> | |
| <select id="quality"> | |
| <option value="150000">Fast</option> | |
| <option value="500000" selected>Balanced</option> | |
| <option value="1500000">Full</option> | |
| </select> | |
| <div class="row chk"><input type="checkbox" id="wire" /> <label for="wire">wireframe</label></div> | |
| </section> | |
| <section> | |
| <h2>Sun</h2> | |
| <label for="sunAz">Azimuth <span class="dim">°</span></label> | |
| <input type="range" id="sunAz" min="0" max="360" step="1" value="315" /> | |
| <label for="sunEl">Elevation <span class="dim">°</span></label> | |
| <input type="range" id="sunEl" min="5" max="88" step="1" value="45" /> | |
| <div class="row chk"><input type="checkbox" id="shadows" checked /> <label for="shadows">cast shadows</label></div> | |
| </section> | |
| <section> | |
| <h2>Measure</h2> | |
| <div id="probe" aria-live="polite">click the terrain to probe a height; click again for slope and a profile</div> | |
| <canvas id="profile"></canvas> | |
| <div class="btns"><button id="clearProbe">Clear points</button></div> | |
| </section> | |
| <section id="validationSection"> | |
| <h2>Validation</h2> | |
| <div id="metrics"><span class="dim">load <code>gt_ndsm_m.npy</code> alongside to | |
| validate against a reference surface</span></div> | |
| </section> | |
| </aside> | |
| <main> | |
| <div class="pane" id="pane2d"> | |
| <div class="paneBar"> | |
| <label for="layer2d" style="margin:0">Map</label> | |
| <select id="layer2d"> | |
| <option value="height">Height</option> | |
| <option value="hillshade">Hillshade</option> | |
| <option value="rgb">Optical</option> | |
| <option value="reference" disabled>Reference</option> | |
| <option value="error" disabled>Error</option> | |
| </select> | |
| <label style="margin:0;display:flex;align-items:center;gap:5px;color:var(--dim)"> | |
| <input type="checkbox" id="contours" /> contours</label> | |
| </div> | |
| <canvas id="map"></canvas> | |
| <canvas id="scalebar"></canvas> | |
| <div class="colorbar-wrap" id="colorbar2d"><canvas width="14" height="120"></canvas></div> | |
| </div> | |
| <div class="pane" id="pane3d"> | |
| <div id="hud"><span id="fps">— fps</span><span id="vertCount">—</span></div> | |
| <div id="hint">click the scene to focus it, then: drag = orbit · scroll = zoom · | |
| click = probe · F = first person · R = reset<br> | |
| <span class="dim">touch: one finger = orbit · pinch = zoom · two-finger drag = pan</span></div> | |
| <div class="colorbar-wrap" id="colorbar3d"><canvas width="14" height="120"></canvas></div> | |
| <div id="meshSpinner"><div class="spin"></div>building mesh…</div> | |
| </div> | |
| </main> | |
| <script> | |
| /* Surface anything that dies before app.js can install its own reporting — | |
| inside an iframe there is no console the viewer's user will ever look at. */ | |
| window.addEventListener('error', (e) => { | |
| const el = document.getElementById('warn'); | |
| if (!el) return; | |
| el.style.display = 'block'; | |
| el.innerHTML += (el.innerHTML ? '<br>' : '') + 'viewer error: ' + | |
| String(e.message || e.type).replace(/[<>&]/g, ''); | |
| }); | |
| </script> | |
| <script src="vendor/three.min.js"></script> | |
| <script src="vendor/OrbitControls.js"></script> | |
| <script src="vendor/PointerLockControls.js"></script> | |
| <script src="app.js"></script> | |
| </body> | |
| </html> | |