* fix(ui): unbreak viz.html — OrbitControls importmap, WS URL, toast NPE (#760)
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 <ruv@ruv.net>
* fix(ui): single module script + mutable THREE — OrbitControls validated
Browser validation against the previous commit caught two stacked issues:
1. `import * as THREE from 'three'` returns a frozen Module Namespace
Object — assignment `THREE.OrbitControls = OrbitControls` silently
no-ops, so the global never gets the OrbitControls reference.
2. Two separate `<script type="module">` blocks (one installing the
THREE global, one consuming it via Scene) are independently
async-resolved. The second can finish dependency loading first and
call `new THREE.OrbitControls(...)` before the first script has run.
Fixed by spreading the namespace into a plain mutable object and merging
all initialization into a single module script with `await import()` for
component modules. Order is now strictly: import THREE → install
window.THREE → import components → run init().
Validated via agent-browser: page logs `[VIZ] Initialization complete`,
WebSocket targets the correct `ws://127.0.0.1:3001/ws/sensing` endpoint
(derived from buildSensingWsUrl), toast lazy-init confirmed via eval.
Co-Authored-By: claude-flow <ruv@ruv.net>
Add viz.html as the main entry point that loads Three.js from CDN and
orchestrates all visualization components (scene, body model, signal
viz, environment, HUD). Add data-processor.js that transforms API
WebSocket messages into geometry updates and provides demo mode with
pre-recorded pose cycling when the server is unavailable.
https://claude.ai/code/session_01Ki7pvEZtJDvqJkmyn6B714