Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
e25087a
refactor(kmeans, RGBPixel): general cleanup for clarity
Ryan-Millard Jan 3, 2026
272e02d
Merge branch 'main' of https://github.com/Ryan-Millard/Img2Num into f…
Ryan-Millard Jan 8, 2026
c0c50a3
Merge branch 'main' of https://github.com/Ryan-Millard/Img2Num into f…
Ryan-Millard Jan 9, 2026
aa5d17f
feat(anti-contours): this labels every non-countour pixel - nice :'(
Ryan-Millard Jan 10, 2026
8f8094b
fix(find_contours): better labelling and border-following - very slow :(
Ryan-Millard Jan 10, 2026
ab83ef5
feat(contour visualization): add diff color borders and simple viewin…
Ryan-Millard Jan 10, 2026
b81809a
fix(contour tracing): never skip a contour pixel
Ryan-Millard Jan 10, 2026
98cf144
KMeans + graph based merging
Krasner Jan 12, 2026
a46c8e8
bug fixes
Krasner Jan 12, 2026
51e3b4a
Move Graph and Node to seperate .h and .cpp files
Krasner Jan 12, 2026
1a19dc1
suppress debug prints
Krasner Jan 12, 2026
315507d
Use each Node as binary image to compute contours from, then recombin…
Krasner Jan 13, 2026
96a457f
fix small edge bug
Krasner Jan 13, 2026
44dfaa9
address some PR review
Krasner Jan 14, 2026
00aaf90
Move bounding box and binary image creation to methods for Node
Krasner Jan 14, 2026
3c22c71
remove(find_contours files): old buggy contour tracing
Ryan-Millard Jan 14, 2026
fda539c
refactor(kmeans_clustering): new API style to preserve original data …
Ryan-Millard Jan 14, 2026
f1507ff
fix(kmeans out params): properly handle WASM boundary for int32
Ryan-Millard Jan 14, 2026
ade79f4
refactor(kmeans_graph): use updated kmeans function instead of kmeans…
Ryan-Millard Jan 14, 2026
ee5a61c
docs(JS-WASM interop): document entire process from function declarat…
Ryan-Millard Jan 14, 2026
bb81a67
Merge branch 'main' into feat/contour-tracing
Ryan-Millard Jan 15, 2026
6e5c3b9
chore(mergeSmallRegionsInPlace): remove legacy function - handled by …
Ryan-Millard Jan 15, 2026
fccd968
fix(node, graph): enforce const-correctness, use explicit types, fix …
Ryan-Millard Jan 15, 2026
f15868d
refactor(image): switch RGBXY to use RGBPixel for color + XY for posi…
Ryan-Millard Jan 15, 2026
0aecc33
refactor(kmeans): clean up dead code
Ryan-Millard Jan 15, 2026
f3f923b
chore(cleanup kmeans_graph, kmeans): remove debug prints & move heade…
Ryan-Millard Jan 17, 2026
5c1903a
refactor(kmeans_graph): split into visualize contours function & opti…
Ryan-Millard Jan 17, 2026
a2aca6f
fix(contours.cpp): Multiplication result converted to larger type
Ryan-Millard Jan 17, 2026
7466a46
fix(kmeans_graph.cpp): Multiplication result converted to larger type
Ryan-Millard Jan 17, 2026
d1be25a
style: lint & format code
Ryan-Millard Jan 17, 2026
3a006b7
fix(ipynb format error): remove ipynb file
Ryan-Millard Jan 17, 2026
84093ea
fix(node.cpp): Multiplication result converted to larger type
Ryan-Millard Jan 17, 2026
3e0a586
fix(worker): prevent prototype pollution from dynamic buffer keys
Ryan-Millard Jan 17, 2026
02dd5a1
docs(wasmWorker): update to match code changes
Ryan-Millard Jan 18, 2026
1701afa
fix(wasm,image)!: correct int sizes, prevent UB, and harden graph/kme…
Ryan-Millard Jan 18, 2026
fea31a2
Merge branch 'main' into feat/contour-tracing
Ryan-Millard Jan 18, 2026
9a7623f
Merge branch 'feat/contour-tracing' of https://github.com/Ryan-Millar…
Ryan-Millard Jan 18, 2026
ade7590
style: update to match repository reqs
Ryan-Millard Jan 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion docs/docs/reference/react/components/_category_.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"label": "Components",
"position": 3,
"link": {
"type": "generated-index",
"title": "React Components",
Expand Down
1 change: 0 additions & 1 deletion docs/docs/reference/react/css/_category_.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"label": "CSS - Styling",
"position": 4,
"link": {
"type": "generated-index",
"title": "React CSS - Styling",
Expand Down
1 change: 0 additions & 1 deletion docs/docs/reference/react/hooks/_category_.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"label": "Hooks",
"position": 2,
"link": {
"type": "generated-index",
"title": "React Hooks",
Expand Down
3 changes: 1 addition & 2 deletions docs/docs/reference/react/hooks/useTheme/_category_.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
{
"label": "useTheme",
"position": 1
"label": "useTheme"
}
168 changes: 168 additions & 0 deletions docs/docs/reference/react/hooks/useWasmWorker/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
id: use-wasm-worker
title: useWasmWorker
hide_title: false
description: A custom React hook for asynchronously calling functions exported by the Image WASM module via a web worker.
---

# useWasmWorker Hook

The `useWasmWorker` hook provides a **React-friendly interface** to the [**WASM Web Worker**](../../workers/wasm-worker) ([`wasmWorker.js`](https://github.com/Ryan-Millard/Img2Num/blob/main/src/workers/wasmWorker.js)).
It allows you to asynchronously invoke any **function exported by the WASM module** from your React components while keeping heavy computation off the main thread.

This hook abstracts:

- Posting messages to the worker.
- Allocating memory for `TypedArrays`.
- Calling WASM functions dynamically.
- Retrieving results.
- Cleaning up memory.

## How WASM Functions Are Exposed

All functions exported from the WASM module are available via the hook’s **generic `call` method**:

```js
const { call } = useWasmWorker();

const result = await call('myWasmFunction', { arg1, arg2 }, ['arg1', 'arg2']);
```

- `'myWasmFunction'` is the **exact name of the C++ function** (without the `_` prefix added by Emscripten internally).
- The **second argument** is an object mapping argument names to values.
- For TypedArrays (e.g., `Uint8ClampedArray`, `Int32Array`), the corresponding keys should be included in the **`bufferKeys` array** (third argument).

- The **order of arguments in the object must match the order in the C++ function signature**. WASM functions are strict about argument order.

### Example

C++ function:

```cpp
void add_arrays(int* a, int* b, int* out, int length);
```

Calling from React:

```js
const result = await call(
'add_arrays', // must match the function's name
{
a: arrayA, // must match the first argument
b: arrayB, // must match the second argument
out: outputArray, // must match the third argument
length: arrayA.length, // must match the last argument
},
['a', 'b', 'out'] // keys that are TypedArrays (pointers)
);
```

## Adding New WASM Functions

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

1. **Add the function in your C++ module** and ensure it is exported in the build:
<Tabs>
<TabItem value="img2num-method" label="Img2Num Method (EXPORTED Macro)">
:::tip This is the preferred method
Use this method instead of the Emscripten method because it reduces bloat in the CMake file and minimizes boilerplate code.
:::
Import and use the `EXPORTED` macro from `exported.h` in your header file (make sure the function is not in a namespace):

```cpp
#include "exported.h"

EXPORTED void add_arrays(int* a, int* b, int* out, int length);
```

</TabItem>

<TabItem value="emscripten-method" label="Emscripten Method">
:::caution Don't use this method in Img2Num!
This method leads to bloat in the CMake file, is difficult to maintain and tough to debug.

Use the Img2Num method instead because it provides convenience, reduces boilerplate, and saves you from numerous possible bugs.
:::
Add the function to the CMake file's `EXPORTED_FUNCTIONS` flag:
```cmake
"SHELL:-s EXPORTED_FUNCTIONS=['_malloc','_free','_add_arrays']"
```
Comment thread
Ryan-Millard marked this conversation as resolved.

</TabItem>
</Tabs>

2. **Call it via the hook** using the `call` method, providing:
- An object mapping argument names to values **in the same order as the C++ function signature**.
- A `bufferKeys` array for all `TypedArrays` (pointers) that need WASM memory allocation.

3. The hook will handle:
- Allocating WASM memory.
- Copying TypedArrays into WASM memory.
- Calling the function.
- Copying modified buffers back.
- Freeing WASM memory.

## Potential Pitfalls

### 1. Incorrect Argument Order

WASM functions **require arguments to be in the exact order declared in C++**.
Passing an object with keys in the wrong order may result in unexpected behavior or crashes.

```js title="❌ Wrong order"
await call('add_arrays', { b: arrayB, a: arrayA, out: outputArray, length: arrayA.length }, ['a', 'b', 'out']);
```

```js title="✅ Correct order"
await call('add_arrays', { a: arrayA, b: arrayB, out: outputArray, length: arrayA.length }, ['a', 'b', 'out']);
```

### 2. Missing TypedArray Keys

All TypedArrays that are modified by the WASM function **must be included in `bufferKeys`**.
Otherwise, the worker will treat them as simple values, and the function may crash or produce invalid output.

### 3. Worker Not Initialized

Always ensure the WASM worker is **fully initialized** before calling any function.
`useWasmWorker` handles this internally, but calling functions **immediately on render without waiting for the hook** may fail.

### 4. Adding New TypedArray Types

If you want to pass a new TypedArray type (e.g., `Float32Array`), you must:

1. Add support in `wasmWorker.js` for copying the new type into WASM memory.
2. Ensure the corresponding **HEAP view** is exported from the C++ module in `EXPORTED_RUNTIME_METHODS` in the CMake file.

:::tip
See the [documentation for `wasmWorker.js`](../../workers/wasm-worker/) before adding new types.
:::

### 5. Memory Management

- The hook and worker automatically allocate and free WASM memory for TypedArrays.
- Avoid manually managing WASM pointers outside this mechanism to prevent memory leaks or crashes.

## Diagram: React → Worker → WASM Flow

```mermaid
flowchart TD
A["React component calls hook function"] --> B["useWasmWorker posts message to wasmWorker"]
B --> C["Worker allocates WASM memory for TypedArrays"]
C --> D["Worker calls WASM function dynamically"]
D --> E["Worker reads back modified buffers"]
E --> F["Worker frees allocated memory"]
F --> G["Worker posts result back to hook"]
G --> H["Hook resolves promise and returns output to component"]
```

- Demonstrates the **end-to-end flow** of calling any WASM function via the hook.

## Summary

- `useWasmWorker` exposes **all WASM functions dynamically** through the generic `call` method.
- TypedArrays must be specified in `bufferKeys` and argument **order must match C++ signature**.
- New functions require both **C++ export** and proper handling in `wasmWorker.js`.
- Handles memory allocation, result copying, and cleanup automatically.
- Provides safe, asynchronous access to WASM from React.
Loading