Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <link rel="stylesheet" href="style.css"> | |
| <title>HEL Perception & Engagement Reasoner (Weapon-Grade Demo)</title> | |
| </head> | |
| <body> | |
| <div id="app"> | |
| <header> | |
| <div class="brand"> | |
| <div class="logo" aria-hidden="true"></div> | |
| <div> | |
| <h1>HEL Perception & Engagement Reasoner</h1> | |
| <div class="sub">Video → detection → expert features → aimpoint + Intensity@Target → HEL feasibility → | |
| closed-loop tracking & dwell control</div> | |
| </div> | |
| </div> | |
| <div class="status-row"> | |
| <div class="pill"> | |
| <span class="dot" id="sys-dot"></span> | |
| <span id="sys-status">STANDBY · No video loaded</span> | |
| </div> | |
| <div class="pill"> | |
| <span class="kbd">Reason</span> | |
| <span>Frame-1 inference</span> | |
| </div> | |
| <div class="pill"> | |
| <span class="kbd">Engage</span> | |
| <span>Closed-loop track + dwell</span> | |
| </div> | |
| </div> | |
| </header> | |
| <div class="workspace"> | |
| <aside> | |
| <div class="card"> | |
| <h2>Video Input</h2> | |
| <div class="hint">Upload one video. Tab 1 uses only the first frame. Tab 2 reuses the same video for tracking | |
| and engagement.</div> | |
| <div class="row mt-md"> | |
| <label for="videoFile">Video file</label> | |
| <span class="badge"><span id="videoMeta">No file</span></span> | |
| </div> | |
| <input id="videoFile" type="file" accept="video/*" /> | |
| <div class="mt-md"> | |
| <label>Mission Objective (optional · enables class filtering)</label> | |
| <textarea id="missionText" rows="3" | |
| placeholder="Optional: e.g., Detect people and vehicles; highlight hazards and key objects."></textarea> | |
| <div class="hint mt-sm"> | |
| Mission objective is <b>optional</b>. If provided, it will be used directly as input to the detector. | |
| If left blank, the detector will detect <b>all</b> objects without filtering. | |
| <div class="mini mt-xs" id="hfBackendStatus">HF Backend: STANDBY</div> | |
| </div> | |
| </div> | |
| <div class="btnrow"> | |
| <button id="btnLoadSample" class="btn secondary" title="Optional: wire up sample videos later" disabled>Load | |
| Sample</button> | |
| <button id="btnEject" class="btn danger" title="Unload video">Eject</button> | |
| </div> | |
| <div class="grid2"> | |
| <div> | |
| <label>Detector</label> | |
| <select id="detectorSelect"> | |
| <optgroup label="Object Detection Models"> | |
| <option value="hf_yolov8" data-kind="object" selected>Lite</option> | |
| <option value="detr_resnet50" data-kind="object">Big</option> | |
| <option value="grounding_dino" data-kind="object">Large</option> | |
| </optgroup> | |
| <optgroup label="Segmentation Models"> | |
| <option value="sam3" data-kind="segmentation">Segmentor</option> | |
| </optgroup> | |
| <optgroup label="Drone Detection Models"> | |
| <option value="drone_yolo" data-kind="drone">Drone</option> | |
| </optgroup> | |
| </select> | |
| </div> | |
| <div> | |
| <label>Tracking</label> | |
| <select id="trackerSelect"> | |
| <option value="iou">IOU + velocity (built-in)</option> | |
| <option value="external">External hook (user API)</option> | |
| </select> | |
| </div> | |
| <label class="checkbox-row" for="enableDepthToggle"> | |
| <input type="checkbox" id="enableDepthToggle"> | |
| <span>Enable Legacy Depth Map (Slow)</span> | |
| </label> | |
| <label class="checkbox-row" for="enableGPTToggle" style="margin-top: 4px;"> | |
| <input type="checkbox" id="enableGPTToggle"> | |
| <span style="color: var(--accent-light);">Enable GPT Reasoning</span> | |
| </label> | |
| <label class="checkbox-row" for="enableStreamToggle" style="margin-top: 4px;"> | |
| <input type="checkbox" id="enableStreamToggle" checked> | |
| <span>Enable Stream Processing</span> | |
| </label> | |
| </div> | |
| <div class="hint mt-sm" id="detectorHint"> | |
| If the browser model cannot load (offline), plug in your own detector in <span | |
| class="kbd">externalDetect()</span>. | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h2>Mission Intel Summary</h2> | |
| <div class="hint">Unbiased 2–3 sentence scene description computed from a few sampled frames + detected | |
| objects (no location inference).</div> | |
| <div class="intel"> | |
| <div class="intel-top"> | |
| <span class="badge"><span class="dot warn" id="intelDot" | |
| style="width:7px;height:7px;box-shadow:none"></span><span id="intelStamp">Idle</span></span> | |
| <button id="btnIntelRefresh" class="btn secondary" | |
| style="padding:8px 10px; border-radius:10px; font-weight:700">Refresh</button> | |
| </div> | |
| <div class="thumbrow" aria-label="sampled frames"> | |
| <img id="intelThumb0" alt="sample frame 1" /> | |
| <img id="intelThumb1" alt="sample frame 2" /> | |
| <img id="intelThumb2" alt="sample frame 3" /> | |
| </div> | |
| <div id="intelSummaryBox" class="intelbox">Upload a video, then click <b>Reason</b> to generate an unbiased | |
| scene summary.</div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h2>HEL & Director Knobs</h2> | |
| <div class="grid2"> | |
| <div> | |
| <label>Max output power (kW)</label> | |
| <input id="helPower" type="range" min="20" max="250" step="1" value="60" /> | |
| <div class="row"><small class="mini"><span id="helPowerVal">60</span> kW</small><small class="mini">turret | |
| output</small></div> | |
| </div> | |
| <div> | |
| <label>Aperture (m)</label> | |
| <input id="helAperture" type="range" min="0.05" max="0.6" step="0.01" value="0.25" /> | |
| <div class="row"><small class="mini"><span id="helApertureVal">0.25</span> m</small><small | |
| class="mini">beam director</small></div> | |
| </div> | |
| </div> | |
| <div class="grid2 mt-sm"> | |
| <div> | |
| <label>Beam quality (M²)</label> | |
| <input id="helM2" type="range" min="1.1" max="4.0" step="0.1" value="1.6" /> | |
| <div class="row"><small class="mini"><span id="helM2Val">1.6</span></small><small class="mini">lower is | |
| better</small></div> | |
| </div> | |
| <div> | |
| <label>Jitter (μrad RMS)</label> | |
| <input id="helJitter" type="range" min="0.5" max="15" step="0.1" value="3.2" /> | |
| <div class="row"><small class="mini"><span id="helJitterVal">3.2</span></small><small | |
| class="mini">director stability</small></div> | |
| </div> | |
| </div> | |
| <div class="grid2 mt-sm"> | |
| <div> | |
| <label>Mode</label> | |
| <select id="helMode"> | |
| <option value="cw">CW (continuous)</option> | |
| <option value="burst">Burst (duty-limited)</option> | |
| <option value="pulse">Pulsed (peak shaping)</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label>Duty cycle (%)</label> | |
| <input id="helDuty" type="range" min="10" max="100" step="1" value="85" /> | |
| <div class="row"><small class="mini"><span id="helDutyVal">85</span>%</small><small class="mini">thermal / | |
| power</small></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h2>Atmosphere & Maritime</h2> | |
| <div class="grid2"> | |
| <div> | |
| <label>Visibility (km)</label> | |
| <input id="atmVis" type="range" min="1" max="30" step="1" value="16" /> | |
| <div class="row"><small class="mini"><span id="atmVisVal">16</span> km</small><small | |
| class="mini">aerosol/haze</small></div> | |
| </div> | |
| <div> | |
| <label>Turbulence (Cn²)</label> | |
| <input id="atmCn2" type="range" min="1" max="10" step="1" value="5" /> | |
| <div class="row"><small class="mini"><span id="atmCn2Val">5</span>/10</small><small | |
| class="mini">wavefront</small></div> | |
| </div> | |
| </div> | |
| <div class="grid2 mt-sm"> | |
| <div> | |
| <label>Sea spray</label> | |
| <input id="seaSpray" type="range" min="0" max="10" step="1" value="2" /> | |
| <div class="row"><small class="mini"><span id="seaSprayVal">2</span>/10</small><small class="mini">salt | |
| attenuation</small></div> | |
| </div> | |
| <div> | |
| <label>Adaptive optics</label> | |
| <input id="aoQ" type="range" min="0" max="10" step="1" value="7" /> | |
| <div class="row"><small class="mini"><span id="aoQVal">7</span>/10</small><small class="mini">turbulence | |
| mitigation</small></div> | |
| </div> | |
| </div> | |
| <div class="grid2 mt-sm"> | |
| <div> | |
| <label>Baseline range (m)</label> | |
| <input id="rangeBase" type="range" min="200" max="6000" step="25" value="1500" /> | |
| <div class="row"><small class="mini"><span id="rangeBaseVal">1500</span> m</small><small | |
| class="mini">median target</small></div> | |
| </div> | |
| <div> | |
| <label>Update rate (Hz)</label> | |
| <input id="detHz" type="range" min="1" max="12" step="1" value="6" /> | |
| <div class="row"><small class="mini"><span id="detHzVal">6</span> Hz</small><small class="mini">tab 2 | |
| detection</small></div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <h2>Engagement Policy</h2> | |
| <div class="grid2"> | |
| <div> | |
| <label>Targeting</label> | |
| <select id="policyMode"> | |
| <option value="auto">Auto: highest lethality margin</option> | |
| <option value="manual">Manual: click target</option> | |
| </select> | |
| </div> | |
| <div> | |
| <label>Assess window (s)</label> | |
| <input id="assessWindow" type="range" min="0.3" max="3.0" step="0.1" value="1.0" /> | |
| <div class="row"><small class="mini"><span id="assessWindowVal">1.0</span> s</small><small | |
| class="mini">post-dwell</small></div> | |
| </div> | |
| </div> | |
| <div class="row"> | |
| <label>Show agent cursor</label> | |
| <select id="cursorMode"> | |
| <option value="on">On</option> | |
| <option value="off">Off</option> | |
| </select> | |
| </div> | |
| <div class="hint">The UI is wired for your APIs. Replace <span class="kbd">externalDetect()</span>, <span | |
| class="kbd">externalFeatures()</span>, and <span class="kbd">externalTrack()</span> when ready.</div> | |
| </div> | |
| <div class="card" style="flex:1; min-height:0"> | |
| <h2>System Log</h2> | |
| <div class="log" id="sysLog"></div> | |
| </div> | |
| </aside> | |
| <main> | |
| <div class="tabs"> | |
| <button class="tabbtn active" data-tab="frame">Tab 1 · Frame-1 Reason</button> | |
| <button class="tabbtn" data-tab="engage">Tab 2 · Video Engage</button> | |
| <button class="tabbtn" data-tab="trade">Trade Space</button> | |
| </div> | |
| <!-- ===== Tab 1 ===== --> | |
| <section class="tab active" id="tab-frame"> | |
| <div class="frame-grid"> | |
| <div class="panel panel-monitor"> | |
| <h3> | |
| <span>First Frame · Detection + Aimpoints</span> | |
| <span class="rightnote" id="frameNote">Awaiting video</span> | |
| </h3> | |
| <div class="viewbox" id="frameViewBox"> | |
| <canvas id="frameCanvas" width="1280" height="720"></canvas> | |
| <canvas id="frameOverlay" class="overlay" width="1280" height="720"></canvas> | |
| <div class="watermark">EO/IR · Track-ID · Aimpoint · Required Dwell</div> | |
| <div class="empty" id="frameEmpty"> | |
| <div class="big">Upload a video to begin</div> | |
| <div class="small">This demo performs first-frame perception and engagement reasoning. Then it replays | |
| the same video with closed-loop tracking and dynamic dwell updates.</div> | |
| <div style="display:flex; gap:10px; margin-top:6px; flex-wrap:wrap; justify-content:center;"> | |
| <span class="badge"><span class="dot"></span> If you are online, COCO-SSD loads automatically</span> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="btnrow" style="margin-top:10px"> | |
| <button id="btnReason" class="btn">Reason</button> | |
| <button id="btnCancelReason" class="btn danger" style="display: none;">Cancel</button> | |
| <button id="btnRecompute" class="btn secondary">Recompute HEL</button> | |
| <button id="btnClear" class="btn secondary">Clear</button> | |
| </div> | |
| <div class="strip mt-md"> | |
| <span class="chip" id="chipFrameDepth" | |
| title="Toggle depth view of first frame (if available)">VIEW:DEFAULT</span> | |
| </div> | |
| </div> | |
| <div class="panel panel-objects radar"> | |
| <h3> | |
| <span>Radar / Relative Geometry</span> | |
| <span class="rightnote" id="objCount">0</span> | |
| </h3> | |
| <canvas id="frameRadar" width="600" height="260" class="full-size"></canvas> | |
| </div> | |
| <div class="panel panel-features"> | |
| <h3> | |
| <span>Selected Target · Features</span> | |
| <span class="rightnote" id="selId">—</span> | |
| </h3> | |
| <table class="table" id="featureTable"> | |
| <thead> | |
| <tr> | |
| <th style="width:42%">Feature</th> | |
| <th>Value</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td class="k">—</td> | |
| <td class="mini">No target selected</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <div class="hint mt-sm">You can replace feature generation via <span | |
| class="kbd">externalFeatures()</span>. The UI will render whatever 10–12 key-value pairs you return. | |
| </div> | |
| </div> | |
| <div class="panel panel-summary" style="display:flex; flex-direction:column; min-height: 0;"> | |
| <h3> | |
| <span>Object Track Cards</span> | |
| <span class="rightnote" id="trackCount">0</span> | |
| </h3> | |
| <div class="list" id="frameTrackList" style="flex:1; overflow-y:auto; padding:8px;"> | |
| <!-- Cards injected here --> | |
| <div style="font-style:italic; color:var(--text-dim); text-align:center; margin-top:20px;"> | |
| No objects tracked. | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- ===== Tab 2 ===== --> | |
| <section class="tab" id="tab-engage"> | |
| <div class="engage-grid"> | |
| <div class="panel"> | |
| <h3> | |
| <span>Video Engage · Tracking + Dynamic Dwell</span> | |
| <div style="display: flex; gap: 8px; align-items: center;"> | |
| <button class="collapse-btn" id="btnToggleSidebar">◀ Hide Sidebar</button> | |
| <span class="rightnote" id="engageNote">Awaiting video</span> | |
| </div> | |
| </h3> | |
| <div class="viewbox" style="min-height: 420px;"> | |
| <video id="videoEngage" playsinline muted></video> | |
| <canvas id="engageOverlay" class="overlay"></canvas> | |
| <div class="watermark">LOCK · DIST · DWELL · AIMPOINT · FIRE/ASSESS</div> | |
| <div class="empty" id="engageEmpty"> | |
| <div class="big">No video loaded</div> | |
| <div class="small">Upload a video. Run <b>Reason</b> first to initialize aimpoints and baseline dwell. | |
| Then click <b>Engage</b>.</div> | |
| </div> | |
| </div> | |
| <div class="btnrow mt-md"> | |
| <button id="btnEngage" class="btn">Engage</button> | |
| <button id="btnPause" class="btn secondary">Pause</button> | |
| <button id="btnReset" class="btn secondary">Reset</button> | |
| </div> | |
| <div class="strip mt-md"> | |
| <span class="chip" id="chipPolicy">POLICY:AUTO</span> | |
| <span class="chip" id="chipTracks">TRACKS:0</span> | |
| <span class="chip" id="chipBeam">BEAM:OFF</span> | |
| <span class="chip" id="chipHz">DET:6Hz</span> | |
| <span class="chip" id="chipFeed" title="Toggle raw vs HF-processed feed (if available)">FEED:RAW</span> | |
| <span class="chip" id="chipDepth" title="Toggle depth view (if available)">VIEW:DEFAULT</span> | |
| </div> | |
| <div class="mt-md"> | |
| <div class="row"><label>Active dwell progress (selected)</label><small class="mini" | |
| id="dwellText">—</small> | |
| </div> | |
| <div class="bar"> | |
| <div id="dwellBar"></div> | |
| </div> | |
| </div> | |
| <div class="hint mt-md">Manual targeting: choose “Manual” in Engagement Policy, then | |
| click a target in the video. The “beam” will track its aimpoint and accumulate dwell.</div> | |
| </div> | |
| <div class="engage-right"> | |
| <div class="panel radar"> | |
| <h3> | |
| <span>Radar / Relative Geometry</span> | |
| <span class="rightnote">Dynamic</span> | |
| </h3> | |
| <canvas id="radarCanvas" width="600" height="260" class="full-size"></canvas> | |
| </div> | |
| <div class="panel" style="flex:1; min-height:0"> | |
| <h3> | |
| <span>Live Track Cards</span> | |
| <span class="rightnote" id="liveStamp">—</span> | |
| </h3> | |
| <div class="list" id="trackList" style="max-height:none"></div> | |
| <!-- Radar Controls --> | |
| <div class="mt-sm" style="padding: 10px; background: rgba(0,0,0,0.2); border-radius: 6px;"> | |
| <div class="row"> | |
| <label class="mini">History Trails</label> | |
| <input id="radarHistoryLen" type="range" min="0" max="100" value="30" style="flex:1; margin:0 8px"> | |
| <small class="mini" id="radarHistoryVal">30</small> | |
| </div> | |
| <div class="row mt-xs"> | |
| <label class="mini">Future Pred</label> | |
| <input id="radarFutureLen" type="range" min="0" max="100" value="30" style="flex:1; margin:0 8px"> | |
| <small class="mini" id="radarFutureVal">30</small> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- ===== Tab 3 ===== --> | |
| <section class="tab" id="tab-trade"> | |
| <div class="trade-grid"> | |
| <div class="panel plot"> | |
| <h3> | |
| <span>Range Sensitivity · Max vs Required Power · Dwell</span> | |
| <span class="rightnote">Interactive</span> | |
| </h3> | |
| <canvas id="tradeCanvas" width="1100" height="420" class="full-size"></canvas> | |
| </div> | |
| <div class="panel"> | |
| <h3> | |
| <span>Trade Controls</span> | |
| <span class="rightnote">What-if</span> | |
| </h3> | |
| <div class="hint">This plot is computed from your current HEL and atmosphere knobs. It uses the selected | |
| target’s baseline requirements (from Tab 1) as a reference curve.</div> | |
| <div class="mt-md"> | |
| <label>Selected target for curve</label> | |
| <select id="tradeTarget"></select> | |
| </div> | |
| <div class="grid2 mt-sm"> | |
| <div> | |
| <label>Range sweep min (m)</label> | |
| <input id="rMin" type="number" value="200" min="50" max="10000" step="50" /> | |
| </div> | |
| <div> | |
| <label>Range sweep max (m)</label> | |
| <input id="rMax" type="number" value="6000" min="100" max="20000" step="50" /> | |
| </div> | |
| </div> | |
| <div class="row mt-md"> | |
| <label>Show P(kill)</label> | |
| <select id="showPk"> | |
| <option value="on">On</option> | |
| <option value="off">Off</option> | |
| </select> | |
| </div> | |
| <div class="btnrow"> | |
| <button class="btn secondary" id="btnReplot">Replot</button> | |
| <button class="btn secondary" id="btnSnap">Snapshot (log)</button> | |
| </div> | |
| <div class="hint">This tab is designed to look like a weapon trade-space console: propagation, lethality | |
| margin, and dwell inflation with range and atmosphere.</div> | |
| </div> | |
| </div> | |
| </section> | |
| </main> | |
| </div> | |
| <footer> | |
| <div>Demo mode · Unclassified visuals · Integrate your APIs where marked</div> | |
| <div class="mono" id="telemetry">HEL=60kW · VIS=16km · Cn²=5/10 · AO=7/10 · DET=6Hz</div> | |
| </footer> | |
| <!-- Hidden video used only for first-frame capture --> | |
| <video id="videoHidden" playsinline muted style="display:none"></video> | |
| </div> | |
| <script> | |
| window.API_CONFIG = { | |
| BACKEND_BASE: "https://biaslab2025-perception.hf.space" | |
| }; | |
| </script> | |
| <script src="./js/init.js"></script> | |
| <script src="./js/core/config.js"></script> | |
| <script src="./js/core/utils.js"></script> | |
| <script src="./js/core/state.js"></script> | |
| <script src="./js/core/physics.js"></script> | |
| <script src="./js/core/video.js"></script> | |
| <script src="./js/core/hel.js"></script> | |
| <script src="./js/ui/logging.js"></script> | |
| <script src="./js/core/tracker.js"></script> | |
| <script src="./js/api/client.js"></script> | |
| <script src="./js/ui/overlays.js"></script> | |
| <script src="./js/ui/radar.js"></script> | |
| <script src="./js/ui/cards.js"></script> | |
| <script src="./js/ui/features.js"></script> | |
| <script src="./js/ui/intel.js"></script> | |
| <script src="./js/ui/cursor.js"></script> | |
| <script src="./js/ui/trade.js"></script> | |
| <script src="./data/helicopter_demo_data.js"></script> | |
| <script src="./js/core/demo.js"></script> | |
| <script src="./js/main.js"></script> | |
| </body> | |
| </html> |