From 04c6d1a595228fb36af673ec9990f66d51443fb5 Mon Sep 17 00:00:00 2001 From: ruv Date: Thu, 12 Mar 2026 17:42:29 -0400 Subject: [PATCH] deploy: update pose fusion demo with live ESP32 WebSocket auto-connect Co-Authored-By: claude-flow --- ui/pose-fusion.html | 160 ++++ ui/pose-fusion/build.sh | 30 + ui/pose-fusion/js/main.js | 12 + .../pkg/ruvector_cnn_wasm/package.json | 26 + .../ruvector_cnn_wasm/ruvector_cnn_wasm.js | 802 ++++++++++++++++++ .../ruvector_cnn_wasm_bg.wasm | Bin 0 -> 51748 bytes 6 files changed, 1030 insertions(+) create mode 100644 ui/pose-fusion.html create mode 100644 ui/pose-fusion/build.sh create mode 100644 ui/pose-fusion/pkg/ruvector_cnn_wasm/package.json create mode 100644 ui/pose-fusion/pkg/ruvector_cnn_wasm/ruvector_cnn_wasm.js create mode 100644 ui/pose-fusion/pkg/ruvector_cnn_wasm/ruvector_cnn_wasm_bg.wasm diff --git a/ui/pose-fusion.html b/ui/pose-fusion.html new file mode 100644 index 00000000..2b023c6f --- /dev/null +++ b/ui/pose-fusion.html @@ -0,0 +1,160 @@ + + + + + + WiFi-DensePose — Dual-Modal Pose Estimation + + + + + +
+
+ +
Dual-Modal Pose Estimation — Live Video + WiFi CSI Fusion
+
+
+ +
+ + READY +
+ -- FPS + ← Dashboard + Observatory → +
+
+ + +
+ + +
+ + +
DUAL FUSION
+ +
+

Enable your webcam for live video pose estimation.
+ Or switch to CSI Only mode for WiFi-based sensing.

+ +
+
+ + +
+ + +
+
◆ Fusion Confidence
+
+
+ Video +
+ 0% +
+
+ CSI +
+ 0% +
+
+ Fused +
+ 0% +
+
+
+ Cross-modal: 0.000 +
+
+ + +
+
◆ CSI Amplitude Heatmap
+
+ +
+
+ + +
+
◆ Embedding Space (2D Projection)
+
+ +
+
+ + +
+
◆ Pipeline Latency
+
+
+
--
+
Video CNN
+
+
+
--
+
CSI CNN
+
+
+
--
+
Fusion
+
+
+
--
+
Total
+
+
+
+ + +
+
◆ Controls
+
+ +
+ +
+ + + 0.30 +
+ +
+
◆ Live CSI Source
+
+ + +
+
+
+ +
+ + +
+
+ WiFi-DensePose · Dual-Modal Pose Estimation · + Architecture: MobileNet-V3 × 2 → Attention Fusion → 17-Keypoint COCO +
+
+ GitHub · + CNN: ruvector-cnn (JS fallback) · + Observatory +
+
+ +
+ + + + diff --git a/ui/pose-fusion/build.sh b/ui/pose-fusion/build.sh new file mode 100644 index 00000000..4d76eba2 --- /dev/null +++ b/ui/pose-fusion/build.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Build WASM packages for the dual-modal pose estimation demo. +# Requires: wasm-pack (cargo install wasm-pack) +# +# Usage: ./build.sh +# +# Output: pkg/ruvector_cnn_wasm/ — WASM CNN embedder for browser + +set -e + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +VENDOR_DIR="$SCRIPT_DIR/../../vendor/ruvector" +OUT_DIR="$SCRIPT_DIR/pkg/ruvector_cnn_wasm" + +echo "Building ruvector-cnn-wasm..." +wasm-pack build "$VENDOR_DIR/crates/ruvector-cnn-wasm" \ + --target web \ + --out-dir "$OUT_DIR" \ + --no-typescript + +# Remove .gitignore so we can commit the build output for GitHub Pages +rm -f "$OUT_DIR/.gitignore" + +echo "" +echo "Build complete!" +echo " WASM: $(du -sh "$OUT_DIR/ruvector_cnn_wasm_bg.wasm" | cut -f1)" +echo " JS: $(du -sh "$OUT_DIR/ruvector_cnn_wasm.js" | cut -f1)" +echo "" +echo "Serve the demo: cd $SCRIPT_DIR/.. && python3 -m http.server 8080" +echo "Open: http://localhost:8080/pose-fusion.html" diff --git a/ui/pose-fusion/js/main.js b/ui/pose-fusion/js/main.js index 29f283f4..db045922 100644 --- a/ui/pose-fusion/js/main.js +++ b/ui/pose-fusion/js/main.js @@ -116,6 +116,18 @@ function init() { visualCnn.tryLoadWasm(wasmBase); csiCnn.tryLoadWasm(wasmBase); + // Auto-connect to local sensing server WebSocket if available + const defaultWsUrl = 'ws://localhost:8765/ws/sensing'; + if (wsUrlInput) wsUrlInput.value = defaultWsUrl; + csiSimulator.connectLive(defaultWsUrl).then(ok => { + if (ok && connectWsBtn) { + connectWsBtn.textContent = '✓ Live ESP32'; + connectWsBtn.classList.add('active'); + statusLabel.textContent = 'LIVE CSI'; + statusDot.classList.remove('offline'); + } + }); + // Auto-start camera for video/dual modes updateModeUI(); startTime = performance.now() / 1000; diff --git a/ui/pose-fusion/pkg/ruvector_cnn_wasm/package.json b/ui/pose-fusion/pkg/ruvector_cnn_wasm/package.json new file mode 100644 index 00000000..f1e17faf --- /dev/null +++ b/ui/pose-fusion/pkg/ruvector_cnn_wasm/package.json @@ -0,0 +1,26 @@ +{ + "name": "ruvector-cnn-wasm", + "type": "module", + "description": "WASM bindings for ruvector-cnn - CNN feature extraction for image embeddings", + "version": "0.1.0", + "license": "MIT OR Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/ruvnet/ruvector" + }, + "files": [ + "ruvector_cnn_wasm_bg.wasm", + "ruvector_cnn_wasm.js" + ], + "main": "ruvector_cnn_wasm.js", + "sideEffects": [ + "./snippets/*" + ], + "keywords": [ + "cnn", + "embeddings", + "wasm", + "simd", + "machine-learning" + ] +} \ No newline at end of file diff --git a/ui/pose-fusion/pkg/ruvector_cnn_wasm/ruvector_cnn_wasm.js b/ui/pose-fusion/pkg/ruvector_cnn_wasm/ruvector_cnn_wasm.js new file mode 100644 index 00000000..f899cf7b --- /dev/null +++ b/ui/pose-fusion/pkg/ruvector_cnn_wasm/ruvector_cnn_wasm.js @@ -0,0 +1,802 @@ +/** + * Configuration for CNN embedder + */ +export class EmbedderConfig { + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + EmbedderConfigFinalization.unregister(this); + return ptr; + } + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_embedderconfig_free(ptr, 0); + } + constructor() { + const ret = wasm.embedderconfig_new(); + this.__wbg_ptr = ret >>> 0; + EmbedderConfigFinalization.register(this, this.__wbg_ptr, this); + return this; + } + /** + * Output embedding dimension + * @returns {number} + */ + get embedding_dim() { + const ret = wasm.__wbg_get_embedderconfig_embedding_dim(this.__wbg_ptr); + return ret >>> 0; + } + /** + * Input image size (square) + * @returns {number} + */ + get input_size() { + const ret = wasm.__wbg_get_embedderconfig_input_size(this.__wbg_ptr); + return ret >>> 0; + } + /** + * Whether to L2 normalize embeddings + * @returns {boolean} + */ + get normalize() { + const ret = wasm.__wbg_get_embedderconfig_normalize(this.__wbg_ptr); + return ret !== 0; + } + /** + * Output embedding dimension + * @param {number} arg0 + */ + set embedding_dim(arg0) { + wasm.__wbg_set_embedderconfig_embedding_dim(this.__wbg_ptr, arg0); + } + /** + * Input image size (square) + * @param {number} arg0 + */ + set input_size(arg0) { + wasm.__wbg_set_embedderconfig_input_size(this.__wbg_ptr, arg0); + } + /** + * Whether to L2 normalize embeddings + * @param {boolean} arg0 + */ + set normalize(arg0) { + wasm.__wbg_set_embedderconfig_normalize(this.__wbg_ptr, arg0); + } +} +if (Symbol.dispose) EmbedderConfig.prototype[Symbol.dispose] = EmbedderConfig.prototype.free; + +/** + * Layer operations for building custom networks + */ +export class LayerOps { + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + LayerOpsFinalization.unregister(this); + return ptr; + } + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_layerops_free(ptr, 0); + } + /** + * Apply batch normalization (returns new array) + * @param {Float32Array} input + * @param {Float32Array} gamma + * @param {Float32Array} beta + * @param {Float32Array} mean + * @param {Float32Array} _var + * @param {number} epsilon + * @returns {Float32Array} + */ + static batch_norm(input, gamma, beta, mean, _var, epsilon) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArrayF32ToWasm0(input, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArrayF32ToWasm0(gamma, wasm.__wbindgen_export2); + const len1 = WASM_VECTOR_LEN; + const ptr2 = passArrayF32ToWasm0(beta, wasm.__wbindgen_export2); + const len2 = WASM_VECTOR_LEN; + const ptr3 = passArrayF32ToWasm0(mean, wasm.__wbindgen_export2); + const len3 = WASM_VECTOR_LEN; + const ptr4 = passArrayF32ToWasm0(_var, wasm.__wbindgen_export2); + const len4 = WASM_VECTOR_LEN; + wasm.layerops_batch_norm(retptr, ptr0, len0, ptr1, len1, ptr2, len2, ptr3, len3, ptr4, len4, epsilon); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var v6 = getArrayF32FromWasm0(r0, r1).slice(); + wasm.__wbindgen_export(r0, r1 * 4, 4); + return v6; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * Apply global average pooling + * Returns one value per channel + * @param {Float32Array} input + * @param {number} height + * @param {number} width + * @param {number} channels + * @returns {Float32Array} + */ + static global_avg_pool(input, height, width, channels) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArrayF32ToWasm0(input, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + wasm.layerops_global_avg_pool(retptr, ptr0, len0, height, width, channels); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var v2 = getArrayF32FromWasm0(r0, r1).slice(); + wasm.__wbindgen_export(r0, r1 * 4, 4); + return v2; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } +} +if (Symbol.dispose) LayerOps.prototype[Symbol.dispose] = LayerOps.prototype.free; + +/** + * SIMD-optimized operations + */ +export class SimdOps { + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + SimdOpsFinalization.unregister(this); + return ptr; + } + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_simdops_free(ptr, 0); + } + /** + * Dot product of two vectors + * @param {Float32Array} a + * @param {Float32Array} b + * @returns {number} + */ + static dot_product(a, b) { + const ptr0 = passArrayF32ToWasm0(a, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArrayF32ToWasm0(b, wasm.__wbindgen_export2); + const len1 = WASM_VECTOR_LEN; + const ret = wasm.simdops_dot_product(ptr0, len0, ptr1, len1); + return ret; + } + /** + * L2 normalize a vector (returns new array) + * @param {Float32Array} data + * @returns {Float32Array} + */ + static l2_normalize(data) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArrayF32ToWasm0(data, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + wasm.simdops_l2_normalize(retptr, ptr0, len0); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var v2 = getArrayF32FromWasm0(r0, r1).slice(); + wasm.__wbindgen_export(r0, r1 * 4, 4); + return v2; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * ReLU activation (returns new array) + * @param {Float32Array} data + * @returns {Float32Array} + */ + static relu(data) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArrayF32ToWasm0(data, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + wasm.simdops_relu(retptr, ptr0, len0); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var v2 = getArrayF32FromWasm0(r0, r1).slice(); + wasm.__wbindgen_export(r0, r1 * 4, 4); + return v2; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * ReLU6 activation (returns new array) + * @param {Float32Array} data + * @returns {Float32Array} + */ + static relu6(data) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArrayF32ToWasm0(data, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + wasm.simdops_relu6(retptr, ptr0, len0); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var v2 = getArrayF32FromWasm0(r0, r1).slice(); + wasm.__wbindgen_export(r0, r1 * 4, 4); + return v2; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } +} +if (Symbol.dispose) SimdOps.prototype[Symbol.dispose] = SimdOps.prototype.free; + +/** + * WASM CNN Embedder for image feature extraction + */ +export class WasmCnnEmbedder { + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + WasmCnnEmbedderFinalization.unregister(this); + return ptr; + } + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_wasmcnnembedder_free(ptr, 0); + } + /** + * Compute cosine similarity between two embeddings + * @param {Float32Array} a + * @param {Float32Array} b + * @returns {number} + */ + cosine_similarity(a, b) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArrayF32ToWasm0(a, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArrayF32ToWasm0(b, wasm.__wbindgen_export2); + const len1 = WASM_VECTOR_LEN; + wasm.wasmcnnembedder_cosine_similarity(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1); + var r0 = getDataViewMemory0().getFloat32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); + if (r2) { + throw takeObject(r1); + } + return r0; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * Get the embedding dimension + * @returns {number} + */ + get embedding_dim() { + const ret = wasm.wasmcnnembedder_embedding_dim(this.__wbg_ptr); + return ret >>> 0; + } + /** + * Extract embedding from image data (RGB format, row-major) + * @param {Uint8Array} image_data + * @param {number} width + * @param {number} height + * @returns {Float32Array} + */ + extract(image_data, width, height) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArray8ToWasm0(image_data, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + wasm.wasmcnnembedder_extract(retptr, this.__wbg_ptr, ptr0, len0, width, height); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); + var r3 = getDataViewMemory0().getInt32(retptr + 4 * 3, true); + if (r3) { + throw takeObject(r2); + } + var v2 = getArrayF32FromWasm0(r0, r1).slice(); + wasm.__wbindgen_export(r0, r1 * 4, 4); + return v2; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * Create a new CNN embedder + * @param {EmbedderConfig | null} [config] + */ + constructor(config) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + let ptr0 = 0; + if (!isLikeNone(config)) { + _assertClass(config, EmbedderConfig); + ptr0 = config.__destroy_into_raw(); + } + wasm.wasmcnnembedder_new(retptr, ptr0); + var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); + if (r2) { + throw takeObject(r1); + } + this.__wbg_ptr = r0 >>> 0; + WasmCnnEmbedderFinalization.register(this, this.__wbg_ptr, this); + return this; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } +} +if (Symbol.dispose) WasmCnnEmbedder.prototype[Symbol.dispose] = WasmCnnEmbedder.prototype.free; + +/** + * InfoNCE loss for contrastive learning (SimCLR style) + */ +export class WasmInfoNCELoss { + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + WasmInfoNCELossFinalization.unregister(this); + return ptr; + } + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_wasminfonceloss_free(ptr, 0); + } + /** + * Compute loss for a batch of embedding pairs + * embeddings: [2N, D] flattened where (i, i+N) are positive pairs + * @param {Float32Array} embeddings + * @param {number} batch_size + * @param {number} dim + * @returns {number} + */ + forward(embeddings, batch_size, dim) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArrayF32ToWasm0(embeddings, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + wasm.wasminfonceloss_forward(retptr, this.__wbg_ptr, ptr0, len0, batch_size, dim); + var r0 = getDataViewMemory0().getFloat32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); + if (r2) { + throw takeObject(r1); + } + return r0; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * Create new InfoNCE loss with temperature parameter + * @param {number} temperature + */ + constructor(temperature) { + const ret = wasm.wasminfonceloss_new(temperature); + this.__wbg_ptr = ret >>> 0; + WasmInfoNCELossFinalization.register(this, this.__wbg_ptr, this); + return this; + } + /** + * Get the temperature parameter + * @returns {number} + */ + get temperature() { + const ret = wasm.wasminfonceloss_temperature(this.__wbg_ptr); + return ret; + } +} +if (Symbol.dispose) WasmInfoNCELoss.prototype[Symbol.dispose] = WasmInfoNCELoss.prototype.free; + +/** + * Triplet loss for metric learning + */ +export class WasmTripletLoss { + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; + WasmTripletLossFinalization.unregister(this); + return ptr; + } + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_wasmtripletloss_free(ptr, 0); + } + /** + * Compute loss for a batch of triplets + * @param {Float32Array} anchors + * @param {Float32Array} positives + * @param {Float32Array} negatives + * @param {number} dim + * @returns {number} + */ + forward(anchors, positives, negatives, dim) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArrayF32ToWasm0(anchors, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArrayF32ToWasm0(positives, wasm.__wbindgen_export2); + const len1 = WASM_VECTOR_LEN; + const ptr2 = passArrayF32ToWasm0(negatives, wasm.__wbindgen_export2); + const len2 = WASM_VECTOR_LEN; + wasm.wasmtripletloss_forward(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2, dim); + var r0 = getDataViewMemory0().getFloat32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); + if (r2) { + throw takeObject(r1); + } + return r0; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * Compute loss for a single triplet + * @param {Float32Array} anchor + * @param {Float32Array} positive + * @param {Float32Array} negative + * @returns {number} + */ + forward_single(anchor, positive, negative) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passArrayF32ToWasm0(anchor, wasm.__wbindgen_export2); + const len0 = WASM_VECTOR_LEN; + const ptr1 = passArrayF32ToWasm0(positive, wasm.__wbindgen_export2); + const len1 = WASM_VECTOR_LEN; + const ptr2 = passArrayF32ToWasm0(negative, wasm.__wbindgen_export2); + const len2 = WASM_VECTOR_LEN; + wasm.wasmtripletloss_forward_single(retptr, this.__wbg_ptr, ptr0, len0, ptr1, len1, ptr2, len2); + var r0 = getDataViewMemory0().getFloat32(retptr + 4 * 0, true); + var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true); + var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true); + if (r2) { + throw takeObject(r1); + } + return r0; + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } + } + /** + * Get the margin parameter + * @returns {number} + */ + get margin() { + const ret = wasm.wasmtripletloss_margin(this.__wbg_ptr); + return ret; + } + /** + * Create new triplet loss with margin + * @param {number} margin + */ + constructor(margin) { + const ret = wasm.wasmtripletloss_new(margin); + this.__wbg_ptr = ret >>> 0; + WasmTripletLossFinalization.register(this, this.__wbg_ptr, this); + return this; + } +} +if (Symbol.dispose) WasmTripletLoss.prototype[Symbol.dispose] = WasmTripletLoss.prototype.free; + +/** + * Initialize panic hook for better error messages + */ +export function init() { + wasm.init(); +} + +function __wbg_get_imports() { + const import0 = { + __proto__: null, + __wbg___wbindgen_throw_39bc967c0e5a9b58: function(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }, + __wbg_error_a6fa202b58aa1cd3: function(arg0, arg1) { + let deferred0_0; + let deferred0_1; + try { + deferred0_0 = arg0; + deferred0_1 = arg1; + console.error(getStringFromWasm0(arg0, arg1)); + } finally { + wasm.__wbindgen_export(deferred0_0, deferred0_1, 1); + } + }, + __wbg_new_227d7c05414eb861: function() { + const ret = new Error(); + return addHeapObject(ret); + }, + __wbg_stack_3b0d974bbf31e44f: function(arg0, arg1) { + const ret = getObject(arg1).stack; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export2, wasm.__wbindgen_export3); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }, + __wbindgen_cast_0000000000000001: function(arg0, arg1) { + // Cast intrinsic for `Ref(String) -> Externref`. + const ret = getStringFromWasm0(arg0, arg1); + return addHeapObject(ret); + }, + __wbindgen_object_drop_ref: function(arg0) { + takeObject(arg0); + }, + }; + return { + __proto__: null, + "./ruvector_cnn_wasm_bg.js": import0, + }; +} + +const EmbedderConfigFinalization = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(ptr => wasm.__wbg_embedderconfig_free(ptr >>> 0, 1)); +const LayerOpsFinalization = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(ptr => wasm.__wbg_layerops_free(ptr >>> 0, 1)); +const SimdOpsFinalization = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(ptr => wasm.__wbg_simdops_free(ptr >>> 0, 1)); +const WasmCnnEmbedderFinalization = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(ptr => wasm.__wbg_wasmcnnembedder_free(ptr >>> 0, 1)); +const WasmInfoNCELossFinalization = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(ptr => wasm.__wbg_wasminfonceloss_free(ptr >>> 0, 1)); +const WasmTripletLossFinalization = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(ptr => wasm.__wbg_wasmtripletloss_free(ptr >>> 0, 1)); + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +function _assertClass(instance, klass) { + if (!(instance instanceof klass)) { + throw new Error(`expected instance of ${klass.name}`); + } +} + +function dropObject(idx) { + if (idx < 1028) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function getArrayF32FromWasm0(ptr, len) { + ptr = ptr >>> 0; + return getFloat32ArrayMemory0().subarray(ptr / 4, ptr / 4 + len); +} + +let cachedDataViewMemory0 = null; +function getDataViewMemory0() { + if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) { + cachedDataViewMemory0 = new DataView(wasm.memory.buffer); + } + return cachedDataViewMemory0; +} + +let cachedFloat32ArrayMemory0 = null; +function getFloat32ArrayMemory0() { + if (cachedFloat32ArrayMemory0 === null || cachedFloat32ArrayMemory0.byteLength === 0) { + cachedFloat32ArrayMemory0 = new Float32Array(wasm.memory.buffer); + } + return cachedFloat32ArrayMemory0; +} + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return decodeText(ptr, len); +} + +let cachedUint8ArrayMemory0 = null; +function getUint8ArrayMemory0() { + if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8ArrayMemory0; +} + +function getObject(idx) { return heap[idx]; } + +let heap = new Array(1024).fill(undefined); +heap.push(undefined, null, true, false); + +let heap_next = heap.length; + +function isLikeNone(x) { + return x === undefined || x === null; +} + +function passArray8ToWasm0(arg, malloc) { + const ptr = malloc(arg.length * 1, 1) >>> 0; + getUint8ArrayMemory0().set(arg, ptr / 1); + WASM_VECTOR_LEN = arg.length; + return ptr; +} + +function passArrayF32ToWasm0(arg, malloc) { + const ptr = malloc(arg.length * 4, 4) >>> 0; + getFloat32ArrayMemory0().set(arg, ptr / 4); + WASM_VECTOR_LEN = arg.length; + return ptr; +} + +function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8ArrayMemory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); + const ret = cachedTextEncoder.encodeInto(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); +cachedTextDecoder.decode(); +const MAX_SAFARI_DECODE_BYTES = 2146435072; +let numBytesDecoded = 0; +function decodeText(ptr, len) { + numBytesDecoded += len; + if (numBytesDecoded >= MAX_SAFARI_DECODE_BYTES) { + cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); + cachedTextDecoder.decode(); + numBytesDecoded = len; + } + return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); +} + +const cachedTextEncoder = new TextEncoder(); + +if (!('encodeInto' in cachedTextEncoder)) { + cachedTextEncoder.encodeInto = function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; + }; +} + +let WASM_VECTOR_LEN = 0; + +let wasmModule, wasm; +function __wbg_finalize_init(instance, module) { + wasm = instance.exports; + wasmModule = module; + cachedDataViewMemory0 = null; + cachedFloat32ArrayMemory0 = null; + cachedUint8ArrayMemory0 = null; + wasm.__wbindgen_start(); + return wasm; +} + +async function __wbg_load(module, imports) { + if (typeof Response === 'function' && module instanceof Response) { + if (typeof WebAssembly.instantiateStreaming === 'function') { + try { + return await WebAssembly.instantiateStreaming(module, imports); + } catch (e) { + const validResponse = module.ok && expectedResponseType(module.type); + + if (validResponse && module.headers.get('Content-Type') !== 'application/wasm') { + console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); + + } else { throw e; } + } + } + + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + } else { + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; + } else { + return instance; + } + } + + function expectedResponseType(type) { + switch (type) { + case 'basic': case 'cors': case 'default': return true; + } + return false; + } +} + +function initSync(module) { + if (wasm !== undefined) return wasm; + + + if (module !== undefined) { + if (Object.getPrototypeOf(module) === Object.prototype) { + ({module} = module) + } else { + console.warn('using deprecated parameters for `initSync()`; pass a single object instead') + } + } + + const imports = __wbg_get_imports(); + if (!(module instanceof WebAssembly.Module)) { + module = new WebAssembly.Module(module); + } + const instance = new WebAssembly.Instance(module, imports); + return __wbg_finalize_init(instance, module); +} + +async function __wbg_init(module_or_path) { + if (wasm !== undefined) return wasm; + + + if (module_or_path !== undefined) { + if (Object.getPrototypeOf(module_or_path) === Object.prototype) { + ({module_or_path} = module_or_path) + } else { + console.warn('using deprecated parameters for the initialization function; pass a single object instead') + } + } + + if (module_or_path === undefined) { + module_or_path = new URL('ruvector_cnn_wasm_bg.wasm', import.meta.url); + } + const imports = __wbg_get_imports(); + + if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) { + module_or_path = fetch(module_or_path); + } + + const { instance, module } = await __wbg_load(await module_or_path, imports); + + return __wbg_finalize_init(instance, module); +} + +export { initSync, __wbg_init as default }; diff --git a/ui/pose-fusion/pkg/ruvector_cnn_wasm/ruvector_cnn_wasm_bg.wasm b/ui/pose-fusion/pkg/ruvector_cnn_wasm/ruvector_cnn_wasm_bg.wasm new file mode 100644 index 0000000000000000000000000000000000000000..a1a54ee24c0587a56c54b2cf96fe62d51941ee6a GIT binary patch literal 51748 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