Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
930275e
fix: improve Windows support for npm scripts
dougwithseismic Dec 14, 2025
2fe9b25
feat: migrate WASM build system from Make to CMake for Windows support
dougwithseismic Dec 14, 2025
fc60c4e
fix: improve error handling in build script and remove legacy Makefiles
dougwithseismic Dec 14, 2025
b9408f7
fix(setup-and-dependencies.md): better styles
Ryan-Millard Dec 15, 2025
53c9ef5
remove(pnpm file): Not relevant in this PR
Ryan-Millard Dec 16, 2025
785c3ed
update(CMakeLists.txt files): Ensure consistency & clarity
Ryan-Millard Dec 18, 2025
2e5fa81
feat(docker compose): Set up basic docker usage with CLI script
Ryan-Millard Dec 19, 2025
c4f1696
feat(img2num CLI): Add bat & ps1 scripts for windows users
Ryan-Millard Dec 19, 2025
f84c076
feat(img2num script): Add disclaimer comment for Windows users
Ryan-Millard Dec 19, 2025
26a0832
fix(img2num scripts): Handle args to npm scripts properly
Ryan-Millard Dec 19, 2025
7689a9f
fix(img2num bash script, docs): Forward ports properly & add disclaimer
Ryan-Millard Dec 20, 2025
9776dde
fix(img2num windows scripts): align with bash counterpart, fix commen…
Ryan-Millard Dec 20, 2025
98544a5
fix(img2num bash script): Make executable & add to tracking
Ryan-Millard Dec 20, 2025
1a65ab6
fix(Dockerfile): switch to node:22-bullseye, the latest stable release
Ryan-Millard Dec 20, 2025
c83644c
docs(Makefile references): Switch to CMake where appropriate
Ryan-Millard Dec 20, 2025
eb8584f
docs(setup & dependencies): Update node version to most accurate for …
Ryan-Millard Dec 20, 2025
c71f672
fix(img2num scripts): Duplicate clean arg removed
Ryan-Millard Dec 20, 2025
b5498e0
fix(imng2num scripts): Provide proper exit codes for success and fail…
Ryan-Millard Dec 20, 2025
09695ca
docs(setup & deps): Fix header & code block - use ## instead of #, sp…
Ryan-Millard Dec 20, 2025
1248d8d
chore(img2num.bat): remove duplicate comment
Ryan-Millard Dec 20, 2025
a051603
chore(build-wasm.js): Add helpful log regarding rm -rf
Ryan-Millard Dec 20, 2025
bdda9a0
chore(img2num sh script): Fix wording
Ryan-Millard Dec 20, 2025
2ee0b07
fix(img2num scripts): stop hiding docker errors - allows users to tro…
Ryan-Millard Dec 20, 2025
caff168
refactor(img2num scripts): add purge arg, better container management
Ryan-Millard Dec 20, 2025
49891ef
feat(.editorconfig): Add bash, batch, powershell support
Ryan-Millard Dec 20, 2025
5ea0721
feat(docker-compose.yml): add remote image ryanmillard/img2num-dev:la…
Ryan-Millard Dec 20, 2025
0b745d8
docs(getting-started): update comprehensive installation and first-ru…
Ryan-Millard Dec 21, 2025
0de2ac7
docs(getting-started): add tip on help args for img2num script
Ryan-Millard Dec 21, 2025
9c30b94
docs(getting-started): add tip on help npm script for local users
Ryan-Millard Dec 21, 2025
002802b
docs(intro page): fix grammatical error
Ryan-Millard Dec 21, 2025
0e9fae5
Merge remote-tracking branch 'origin/main' into feat/docker-docker-co…
Ryan-Millard Dec 22, 2025
80ac27e
docs(README.md): update README.md disclaimer comment for better PR re…
Ryan-Millard Dec 22, 2025
9a24995
docs(fix intro links): remove redundant, use HTTPS for Blank Issue link
Ryan-Millard Dec 22, 2025
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
12 changes: 12 additions & 0 deletions .devcontainer/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -euo pipefail

# Source emsdk environment
if [ -f "${EMSDK_ROOT}/emsdk_env.sh" ]; then
source "${EMSDK_ROOT}/emsdk_env.sh"
fi

# Go to workdir
cd /usr/src/app

exec "$@"
8 changes: 8 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
node_modules/*
dist/*
build/*
docs/build/*
.vscode
.git
.gitignore
.DS_Store
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ dist-ssr
*:Zone.Identifier

src/data/contributor-credits.json

# CMake build artifacts
src/wasm/cmake-build/
src/wasm/**/CMakeCache.txt
src/wasm/**/CMakeFiles/
42 changes: 42 additions & 0 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# ------------------------
# Img2Num Dockerfile.dev
# ------------------------
FROM node:23-bullseye

ENV EMSDK_VERSION=4.0.10
Comment thread
Ryan-Millard marked this conversation as resolved.
Resolved
ENV EMSDK_DIR=/opt/emsdk

RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
cmake \
python3 \
git \
curl \
unzip \
pkg-config \
bash \
ca-certificates \
libvips-dev \
&& rm -rf /var/lib/apt/lists/*

# Install EMSDK once, cached by Docker layers
RUN git clone --depth 1 https://github.com/emscripten-core/emsdk.git $EMSDK_DIR \
&& cd $EMSDK_DIR \
&& git fetch --tags \
&& git checkout $EMSDK_VERSION \
&& ./emsdk install $EMSDK_VERSION \
&& ./emsdk activate $EMSDK_VERSION

ENV PATH=$EMSDK_DIR:$EMSDK_DIR/upstream/emscripten:$PATH
ENV EMSDK=$EMSDK_DIR

RUN npm install -g npm@11

WORKDIR /usr/src/app

ENV CHOKIDAR_USEPOLLING=true
ENV CHOKIDAR_INTERVAL=100

EXPOSE 5173 3000

CMD ["bash"]
24 changes: 24 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
services:
dev:
build:
context: .
dockerfile: Dockerfile.dev
container_name: img2num-dev
working_dir: /usr/src/app
volumes:
- .:/usr/src/app:cached
- node_modules:/usr/src/app/node_modules
- docs_node_modules:/usr/src/app/docs/node_modules
environment:
CHOKIDAR_USEPOLLING: "true"
CHOKIDAR_INTERVAL: "100"
ports:
- "5173:5173" # Vite dev
- "4173:4173" # Vite preview
- "3000:3000" # Docusaurus dev
stdin_open: true
tty: true

volumes:
node_modules:
docs_node_modules:
117 changes: 99 additions & 18 deletions docs/docs/reference/wasm/how-to-add-a-module.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,35 +7,116 @@ sidebar_position: 6
# Step-by-step: add a new module

1. Create a new directory: `src/wasm/modules/<module-name>/`.
- Don't be daft - make sure to replace `<module-name>` with the actual name your module should be given.
2. Add `src/`, `include/` and a `Makefile` that obeys the root Makefile contract (targets: `build`, `debug`, `clean`).
3. Make sure the module's `Makefile` writes output to `build/` with `index.js` and `index.wasm` (the repo's alias generator expects `modules/{name}/build`).
- Replace `<module-name>` with your actual module name (lowercase, e.g., `audio`, `filters`).
2. Add `src/`, `include/` directories and a `CMakeLists.txt` file.
3. Make sure the module's `CMakeLists.txt` writes output to `build/` with `index.js` and `index.wasm` (the repo's alias generator expects `modules/{name}/build`).
4. `vite.config.js` will automatically find the module and create an alias `@wasm-<module-name>` on next `vite` start (or rebuild of the config). Example usage:

```js
import init from '@wasm-<module-name>/index.js';
await init();
```

5. Commit the `Makefile` and source files; do not commit `build/` artifacts unless you want to vendor the WASM for static hosting without building.
5. Commit the `CMakeLists.txt` and source files; do not commit `build/` artifacts unless you want to vendor the WASM for static hosting without building.

# Minimal module Makefile (copy/paste)
# Minimal module CMakeLists.txt (copy/paste)
Comment thread
Ryan-Millard marked this conversation as resolved.
Resolved

```makefile
EMCC ?= emcc
SRC = $(wildcard src/*.cpp)
OUT_DIR = build
```cmake
# =============================================
# <Module Name> WASM Module - CMake Build Configuration
# =============================================

.PHONY: build debug clean
# Get module name from directory
get_filename_component(MODULE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)

build:
mkdir -p $(OUT_DIR)
$(EMCC) $(SRC) -o $(OUT_DIR)/index.js -O3 -s WASM=1 --bind
# Capitalize first letter for export name (e.g., "audio" -> "Audio")
string(SUBSTRING ${MODULE_NAME} 0 1 FIRST_LETTER)
string(TOUPPER ${FIRST_LETTER} FIRST_LETTER_UPPER)
string(SUBSTRING ${MODULE_NAME} 1 -1 REST_OF_NAME)
set(CAP_MODULE_NAME "${FIRST_LETTER_UPPER}${REST_OF_NAME}")

debug:
mkdir -p $(OUT_DIR)
$(EMCC) $(SRC) -o $(OUT_DIR)/index.js -g -O0 -s ASSERTIONS=1 --bind
# Collect source files
file(GLOB_RECURSE SRC_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
)

clean:
rm -rf $(OUT_DIR)
# Output directory
set(BUILD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/build")

# Create executable target (Emscripten produces .js + .wasm)
add_executable(${MODULE_NAME}_wasm ${SRC_FILES})

# Include directories
target_include_directories(${MODULE_NAME}_wasm PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
)

# Shared Emscripten options
# Adjust INITIAL_MEMORY and MAXIMUM_MEMORY based on your module's needs
set(COMMON_FLAGS
"SHELL:-s MODULARIZE=1"
"SHELL:-s EXPORT_ES6=1"
"SHELL:-s EXIT_RUNTIME=1"
"SHELL:-s ENVIRONMENT=web"
"SHELL:-s EXPORTED_FUNCTIONS=['_malloc','_free']"
"SHELL:-s EXPORTED_RUNTIME_METHODS=['ccall','cwrap','getValue','setValue','HEAPU8']"
"SHELL:-s INITIAL_MEMORY=256MB"
"SHELL:-s MAXIMUM_MEMORY=512MB"
"SHELL:-s ALLOW_MEMORY_GROWTH=1"
"SHELL:-s EXPORT_NAME=create${CAP_MODULE_NAME}Module"
)

# Apply common flags
target_link_options(${MODULE_NAME}_wasm PRIVATE ${COMMON_FLAGS})

# Build-type specific flags
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options(${MODULE_NAME}_wasm PRIVATE -O0 -g4)
target_link_options(${MODULE_NAME}_wasm PRIVATE
"SHELL:-s ASSERTIONS=2"
-g4
)
else()
target_compile_options(${MODULE_NAME}_wasm PRIVATE -O3)
target_link_options(${MODULE_NAME}_wasm PRIVATE
"SHELL:-s SINGLE_FILE=0"
)
endif()

# Set output location and name
set_target_properties(${MODULE_NAME}_wasm PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${BUILD_DIR}"
OUTPUT_NAME "index"
SUFFIX ".js"
)

message(STATUS "Module '${MODULE_NAME}' configured (export: create${CAP_MODULE_NAME}Module)")
```

# Directory structure

Your new module should look like:

```
src/wasm/modules/<module-name>/
β”œβ”€β”€ CMakeLists.txt
β”œβ”€β”€ include/
β”‚ └── your_header.h
β”œβ”€β”€ src/
β”‚ └── main.cpp
└── build/ # Generated (gitignored)
β”œβ”€β”€ index.js
└── index.wasm
```

# Building

Once added, the module is automatically discovered by the root `CMakeLists.txt`. Simply run:

```bash
npm run build-wasm # Release build
npm run build-wasm:debug # Debug build with source maps
npm run clean-wasm # Clean all build artifacts
```

The build system works identically on Windows, macOS, and Linux.
140 changes: 123 additions & 17 deletions docs/docs/reference/wasm/setup-and-dependencies.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,148 @@
---
id: wasm-setup-depencenciess
id: wasm-setup-dependencies
title: Setup & Dependencies
sidebar_position: 2
---

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

# Prerequisites

To build the WASM modules you will need a working Emscripten toolchain (emsdk) available on your `PATH` and a Unix-y shell environment (bash / WSL / macOS). Steps in brief:
### Frontend-Only Development

Comment thread
Ryan-Millard marked this conversation as resolved.
Resolved
If you are working on the React/TypeScript frontend, documentation, or any non-WASM features, simply install Node.js and run `npm install` or `pnpm install`. The following npm scripts work cross-platform:

- **Development**: `dev`, `dev:all`, `preview`
- **Building**: `build-js` (JavaScript/React build only)
- **Code Quality**: `lint`, `lint:fix`, `lint:style`, `format`, `format-js`, `format-wasm`
- **Documentation**: `docs` (all docs scripts)
- **Utilities**: `help`, `clean-js`, `release`

### Full Development (Including WASM)

WASM development now works natively on **all platforms** including Windows. You need:

1. **Node.js** (v18+)
2. **CMake** (v3.16+)
3. **Emscripten SDK** (emsdk)
Comment thread
Ryan-Millard marked this conversation as resolved.
Resolved

**WASM scripts** (cross-platform):

- `build-wasm`, `build-wasm:debug`
- `clean-wasm`
- `build`, `clean` (these chain WASM builds)
- `dev:debug`, `dev:all:debug`

## WASM Build Setup

### Step 1: Install CMake

<Tabs groupId="operating-systems" queryString>
<TabItem value="windows" label="Windows" default>
```cmd
winget install Kitware.CMake
```
</TabItem>
<TabItem value="linux" label="Linux">
```bash
sudo apt install cmake
```
</TabItem>
<TabItem value="macos" label="macOS">
```bash
brew install cmake
```
</TabItem>
</Tabs>

### Step 2: Install Emscripten

```bash
# Clone emsdk
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk

# Install and activate latest
./emsdk install latest
./emsdk activate latest

1. Install Emscripten (emsdk) β€” follow the official Emscripten docs for your OS.
2. Activate emsdk and ensure `emcc`/`em++` are available in the shell used by `npm`/`make`.
3. Optionally install `clang-format` and `cmake` if module Makefiles rely on them.

```

<Tabs groupId="operating-systems" queryString>
<TabItem value="windows" label="Windows" default>
```cmd title="CMD"
emsdk_env.bat
```
```PowerShell title="PowerShell"
./emsdk_env.ps1
```
</TabItem>
<TabItem value="linux" label="Linux">
```bash title="Add to PATH (run this in each new terminal, or add to your shell profile)"
source ./emsdk_env.sh
```
</TabItem>
<TabItem value="macos" label="macOS">
```bash title="Add to PATH (run this in each new terminal, or add to your shell profile)"
source ./emsdk_env.sh
```
</TabItem>
</Tabs>

:::tip
For Windows development we recommend WSL2 + Ubuntu and activating emsdk inside WSL for consistent results.
Add the emsdk environment script to your shell profile (`.bashrc`, `.zshrc`, or Windows equivalent) so `emcc` is always available.
:::

:::danger Help Wanted!
The support for developers on Windows for this repository is not great. Thus, we need **your help**!
[Issue #80](https://github.com/Ryan-Millard/Img2Num/issues/80) is up for grabs for anyone will to take on this task.
:::
### Step 3: Verify Installation

```bash
cmake --version # Should show 3.16+
emcc --version # Should show Emscripten version
```

## How package.json ties into builds

The repo ships npm scripts that call `make` in the `src/wasm` directory. Example snippets from `package.json`:
The repo ships npm scripts that use a cross-platform Node.js build script with CMake:

```json
"scripts": {
"build-wasm": "make -C src/wasm build",
"build-wasm:debug": "make -C src/wasm debug",
"clean-wasm": "make -C src/wasm clean"
"build-wasm": "node scripts/build-wasm.js",
"build-wasm:debug": "node scripts/build-wasm.js --debug",
"clean-wasm": "node scripts/build-wasm.js --clean"
}
```

Use the `npm` scripts when developing locally or in CI; they make the JS side independent from the exact make command.
The build script:
1. Verifies Emscripten is installed
2. Runs `emcmake cmake` to configure the build
3. Runs `cmake --build` to compile all WASM modules
4. Outputs to each module's `build/` directory

:::note
Use the `npm` scripts when developing locally or in CI; they abstract away the build system details.
:::

## Environment variables

* `NODE_ENV=production` β€” some parts of `vite.config.js` only trigger a WASM build when building for production; during dev the plugin also triggers builds but only as configured.
* `EMSDK` / `EMCC` β€” if you maintain multiple SDK installs, ensure the correct one is on `PATH` when running `npm run build-wasm`.
- `NODE_ENV=production` β€” some parts of `vite.config.js` only trigger a WASM build when building for production; during dev the plugin also triggers builds but only as configured.
- `EMSDK` / `EMCC` β€” if you maintain multiple SDK installs, ensure the correct one is on `PATH` when running `npm run build-wasm`.

## Build System Architecture

The WASM modules use CMake for cross-platform compatibility:

```
src/wasm/
β”œβ”€β”€ CMakeLists.txt # Root orchestrator (auto-discovers modules)
β”œβ”€β”€ cmake-build/ # CMake build artifacts (gitignored)
└── modules/
└── image/
β”œβ”€β”€ CMakeLists.txt # Module build configuration
β”œβ”€β”€ src/ # C++ source files
β”œβ”€β”€ include/ # Header files
└── build/ # Output (index.js + index.wasm)
```
Comment thread
Ryan-Millard marked this conversation as resolved.
Resolved

This replaces the previous Makefile-based system (before [#93](https://github.com/Ryan-Millard/Img2Num/pull/93)) and works identically on Windows, macOS, and Linux.
Loading