From 35d9be9ba0edb52429de07a44c02826da9ffb51a Mon Sep 17 00:00:00 2001 From: ruv Date: Sat, 23 May 2026 10:25:08 -0400 Subject: [PATCH] =?UTF-8?q?fix(ui):=20unbreak=20viz.html=20=E2=80=94=20Orb?= =?UTF-8?q?itControls=20importmap,=20WS=20URL,=20toast=20NPE=20(#760)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three independent bugs were stacking to make ui/viz.html unusable from `main`: 1. Three.js r160 removed `examples/js/OrbitControls.js`, so the script-tag load 404'd and `new THREE.OrbitControls(...)` threw. Switch to an importmap that pulls the ES module build, then re-expose `window.THREE` and `THREE.OrbitControls` so the existing component modules (scene.js, body-model.js, …) keep working without a wider refactor. 2. The WebSocket client was hardcoded to `ws://localhost:8000/ws/pose`, but the sensing-server listens on `--ws-port` (8765 default, 3001 in the Docker image) at `/ws/sensing`. Reuse the existing `buildSensingWsUrl()` helper from `sensing.service.js` so port pairings are handled centrally, and add a `?ws=…` query-string override for non-standard setups. The websocket-client.js default is also updated to derive from `window.location` instead of the dead `:8000/ws/pose` literal. 3. `ToastManager.show()` called `this.container.appendChild(...)` even when `init()` had never been called, throwing a TypeError that killed the rest of page initialization. Auto-init the container lazily on first show (patch from issue reporter). Closes #760. Co-Authored-By: claude-flow --- ui/services/websocket-client.js | 14 ++++++++++++-- ui/utils/toast.js | 2 ++ ui/viz.html | 28 +++++++++++++++++++++++----- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/ui/services/websocket-client.js b/ui/services/websocket-client.js index 93428b87..208e0780 100644 --- a/ui/services/websocket-client.js +++ b/ui/services/websocket-client.js @@ -1,9 +1,19 @@ // WebSocket Client for Three.js Visualization - WiFi DensePose -// Connects to ws://localhost:8000/ws/pose and manages real-time data flow +// Default endpoint is `/ws/sensing` on the same host the page was served from. +// Callers (e.g. viz.html) usually pass an explicit `url` derived from +// `buildSensingWsUrl()` so HTTP/WS port pairings are handled centrally. + +function _defaultWsUrl() { + if (typeof window === 'undefined' || !window.location) { + return 'ws://localhost:8765/ws/sensing'; + } + const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; + return `${protocol}//${window.location.host}/ws/sensing`; +} export class WebSocketClient { constructor(options = {}) { - this.url = options.url || 'ws://localhost:8000/ws/pose'; + this.url = options.url || _defaultWsUrl(); this.ws = null; this.state = 'disconnected'; // disconnected, connecting, connected, error this.isRealData = false; diff --git a/ui/utils/toast.js b/ui/utils/toast.js index ec1a097e..219c713a 100644 --- a/ui/utils/toast.js +++ b/ui/utils/toast.js @@ -27,6 +27,8 @@ export class ToastManager { action = null } = options; + if (!this.container) this.init(); + const id = ++this.idCounter; const toast = document.createElement('div'); toast.className = `toast toast-${type}`; diff --git a/ui/viz.html b/ui/viz.html index 54fa0a5f..1029f985 100644 --- a/ui/viz.html +++ b/ui/viz.html @@ -84,9 +84,23 @@
- - - + + + @@ -100,6 +114,7 @@ import { DashboardHUD } from './components/dashboard-hud.js'; import { WebSocketClient } from './services/websocket-client.js'; import { DataProcessor } from './services/data-processor.js'; + import { buildSensingWsUrl } from './services/sensing.service.js'; // -- Application State -- const state = { @@ -175,9 +190,12 @@ state.stats = initStats(); setLoadingProgress(85, 'Connecting to server...'); - // 8. WebSocket client + // 8. WebSocket client — derive URL from window.location so the page + // works on both default (HTTP 8080 / WS 8765) and Docker (3000/3001) + // port pairings. `?ws=…` query overrides for advanced setups. + const wsOverride = new URLSearchParams(window.location.search).get('ws'); state.wsClient = new WebSocketClient({ - url: 'ws://localhost:8000/ws/pose', + url: wsOverride || buildSensingWsUrl(), onMessage: (msg) => handleWebSocketMessage(msg), onStateChange: (newState, oldState) => handleConnectionStateChange(newState, oldState), onError: (err) => console.error('[VIZ] WebSocket error:', err)