chore(build): P0 plumbing — WASM build/parity retarget to manifold/public
- build-wasm.sh emits to manifold/public/ (transitional copy to playground/public/ until P1 retires the playground) - parity-check.sh + parity_wasm.mjs read the manifold artifact - fix stale MLP<2,...> arity in AGENT-REFERENCE.md + nisps/wasm/README.md - gitignore .claude/worktrees/ - plan one-core-engine-refactor.md: P0 marked landed Gate: run-all-tests green; parity PASS from manifold artifact (2.4e-7); manifold builds against freshly-built nisps.wasm.
This commit is contained in:
parent
c936bf75c9
commit
29dc88be3a
10 changed files with 43 additions and 28 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -50,3 +50,6 @@ node_modules/
|
|||
bun.lock
|
||||
playwright-report/
|
||||
test-results/
|
||||
|
||||
# Agent worktrees
|
||||
.claude/worktrees/
|
||||
|
|
|
|||
4
MAP.md
4
MAP.md
|
|
@ -40,7 +40,7 @@ MEMLNaut-NISPS — Neural Interactive Shaping of Parameter Spaces. One C++20 cod
|
|||
- `playground/src/input/pipeline.ts`, `playground/src/output/pipeline.ts`, `playground/src/output/curves.ts` — pure-fn pipelines (deadzone→zoom→curve→smoothing→momentum, then global curve→smoothing→slew→freeze).
|
||||
- `playground/src/features/` — additional feature modules (heatmap sampling, snapshot stack, A/B compare, region pin, param pin, trail, weight health, etc.).
|
||||
- `playground/src/debug/probe.ts` — synchronous `window.__nisps` debug probe for Playwright.
|
||||
- `playground/public/nisps.{wasm,js}`, `c15.wasm`, `c15-glue.js` — compiled WASM artifacts (built by `scripts/build-wasm.sh`).
|
||||
- `playground/public/nisps.{wasm,js}`, `c15.wasm`, `c15-glue.js` — WASM artifacts. `nisps.*` are a transitional copy from `scripts/build-wasm.sh` (canonical output is `manifold/public/`; copy dies with playground at P1).
|
||||
- `playground/tests/e2e/` — Playwright specs (`ml-engine`, `modes`, `persistence`, `ui-interactions`) + `helpers.ts`.
|
||||
- `playground/playwright.config.ts` — Vite preview server setup.
|
||||
|
||||
|
|
@ -113,7 +113,7 @@ the "BUILD DELTAS" block at the top of `docs/specs/vcv-module.md`). `src/MEMLNau
|
|||
|
||||
### `scripts/` — build + verify entry points
|
||||
- `build-firmware.sh`, `flash-firmware.sh`, `build-and-flash-firmware.sh`, `firmware-common.sh` — Arduino-CLI wrapper for RP2350 target with C++20 flag.
|
||||
- `build-wasm.sh` — Emscripten compile producing `playground/public/nisps.{wasm,js}`.
|
||||
- `build-wasm.sh` — Emscripten compile producing `manifold/public/nisps.{wasm,js}` (+ transitional copy to `playground/public/` until P1).
|
||||
- `build-cpp-tests.sh` — CMake configure + build + ctest (Ninja).
|
||||
- `parity-check.sh` — runs native + WASM and diffs binary outputs.
|
||||
- `lint-cpp.sh` — `.f` literal warn + heap/`Arduino.h` violation fail.
|
||||
|
|
|
|||
|
|
@ -124,9 +124,9 @@ Two WASM instances at runtime:
|
|||
1. **Main thread** (`playground/src/ml/wasm-iml.ts`): ML inference + sync training + RL primitives. Update store after each call. Async training via disposable Web Worker (`wasm-worker.ts`).
|
||||
2. **AudioWorklet** (`playground/src/audio/worklet/nisps-processor.ts`): runs engine `process_block` per audio block. Loads `nisps.wasm` directly via `WebAssembly.compile` (no Emscripten glue in worklet). Bytes posted from main thread.
|
||||
|
||||
C API is in `nisps/wasm/bindings.cpp`. Build: `bash scripts/build-wasm.sh` (~94KB output to `playground/public/`).
|
||||
C API is in `nisps/wasm/bindings.cpp`. Build: `bash scripts/build-wasm.sh` (~94KB output to `manifold/public/`, transitional copy to `playground/public/` until P1).
|
||||
|
||||
The WASM target is fixed at `MLP<2, 10, 14, 18, 126>`. Modes with smaller `output_size` use the first N outputs only.
|
||||
The WASM target is fixed at `MLP<32u, 10u, 14u, 18u, 126u>` (`nisps_ml_create` ignores requested dims — see `docs/specs/plans/one-core-engine-refactor.md` P2). Modes with smaller `input_size`/`output_size` use a slice.
|
||||
|
||||
### Known limitations
|
||||
|
||||
|
|
|
|||
|
|
@ -74,13 +74,13 @@ skin) still applies inside manifold; this plan adds the vertical one.
|
|||
Each phase ends green on its test gate and is independently landable. File phases as **ergo** tasks
|
||||
(one per phase, sub-tasks per bullet); do not start a phase before its predecessor's gate is green.
|
||||
|
||||
### P0 — Plumbing hygiene (hours, no behaviour change)
|
||||
### P0 — Plumbing hygiene (hours, no behaviour change) — ✅ landed 2026-07-13
|
||||
|
||||
- `scripts/build-wasm.sh` emits to `manifold/public/` (keep `playground/public/` copy only until P1 lands).
|
||||
- `scripts/parity-check.sh` reads the manifold artifact.
|
||||
- Fix stale doc: `MAP.md` §WASM still says `MLP<2,…>`; code is `MLP<32u,10u,14u,18u,126u>`.
|
||||
- Delete `ml-debug.log`, `graphify-out/` from tree root; gitignore `.claude/worktrees/`.
|
||||
- **Gate:** `run-all-tests.sh` green; manifold builds against a freshly-built (not copied) `nisps.wasm`.
|
||||
- ✅ `scripts/build-wasm.sh` emits to `manifold/public/` (keep `playground/public/` copy only until P1 lands).
|
||||
- ✅ `scripts/parity-check.sh` (and `tests/cpp/parity_wasm.mjs`) read the manifold artifact.
|
||||
- ✅ Fix stale doc: the `MLP<2,…>` line was in `docs/AGENT-REFERENCE.md` + `nisps/wasm/README.md` (MAP.md was already correct); both now say `MLP<32u,10u,14u,18u,126u>`.
|
||||
- ✅ `ml-debug.log`/`graphify-out/` were already absent from the tree; `.claude/worktrees/` gitignored.
|
||||
- **Gate met:** `run-all-tests.sh` green (Playwright leg via the BUILD-PLAN non-snap-node VPS runner); parity PASS reading `manifold/public/` (max delta 2.4e-7); manifold typecheck+build green against the freshly-built artifact.
|
||||
|
||||
### P1 — Retire playground, single TS home (≈1 day)
|
||||
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,11 +1,13 @@
|
|||
# nisps/wasm
|
||||
|
||||
Emscripten target that exposes `nisps/ml` (MLP) and `nisps/engines` (audio
|
||||
engines) to the SolidJS playground via a flat C ABI.
|
||||
engines) to the browser apps via a flat C ABI.
|
||||
|
||||
This directory is a leaf — it does not export headers for inclusion by
|
||||
other C++ code. The only artifact is `bindings.cpp` plus the build script
|
||||
that turns it into `playground/public/nisps.{wasm,js}`.
|
||||
that turns it into `manifold/public/nisps.{wasm,js}` (with a transitional
|
||||
copy to `playground/public/` until P1 of
|
||||
`docs/specs/plans/one-core-engine-refactor.md` retires the playground).
|
||||
|
||||
## Building
|
||||
|
||||
|
|
@ -18,11 +20,11 @@ Requires `emcc` (Emscripten). The script defaults to
|
|||
|
||||
Output:
|
||||
|
||||
- `playground/public/nisps.wasm` — the compiled module.
|
||||
- `playground/public/nisps.js` — Emscripten glue (factory function
|
||||
- `manifold/public/nisps.wasm` — the compiled module.
|
||||
- `manifold/public/nisps.js` — Emscripten glue (factory function
|
||||
`createNispsModule`, MODULARIZE=1).
|
||||
|
||||
Both files are committed (so the playground works from a fresh clone
|
||||
Both files are committed (so the browser apps work from a fresh clone
|
||||
without a C++ toolchain). Re-run `build-wasm.sh` after changes to
|
||||
`nisps/{core,ml,engines,wasm}`.
|
||||
|
||||
|
|
@ -32,9 +34,9 @@ The MLP class template is parametrised on `(input_size, hidden1, hidden2,
|
|||
hidden3, output_size)`. WASM cannot recompile templates at runtime, so
|
||||
this build instantiates exactly ONE configuration:
|
||||
|
||||
nisps::ml::MLP<2, 10, 14, 18, 126>
|
||||
nisps::ml::MLP<32, 10, 14, 18, 126>
|
||||
|
||||
That serves the playground use case (2-D joystick → up to 126 synth
|
||||
That serves the browser use case (up to 32 input axes → up to 126 synth
|
||||
parameters). `nisps_ml_create()` accepts caller-supplied dimensions for
|
||||
forward compatibility but currently ignores them — see comment at the top
|
||||
of `bindings.cpp`. The schemas in `schemas/modes/*.json` use up to
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env bash
|
||||
# scripts/build-wasm.sh — compile nisps/wasm/bindings.cpp via Emscripten and
|
||||
# write the result to playground/public/.
|
||||
# write the result to manifold/public/.
|
||||
#
|
||||
# Requires emcc. Defaults to /usr/lib/emscripten/emcc; override via the EMCC
|
||||
# env var. Sample invocation:
|
||||
|
|
@ -8,14 +8,17 @@
|
|||
# EMCC=$(which emcc) scripts/build-wasm.sh
|
||||
#
|
||||
# Output:
|
||||
# playground/public/nisps.js — Emscripten glue, MODULARIZE factory
|
||||
# playground/public/nisps.wasm — the compiled module
|
||||
# manifold/public/nisps.js — Emscripten glue, MODULARIZE factory
|
||||
# manifold/public/nisps.wasm — the compiled module
|
||||
#
|
||||
# A copy is also written to playground/public/ until P1 of
|
||||
# docs/specs/plans/one-core-engine-refactor.md retires the playground.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
EMCC="${EMCC:-$(command -v emcc || echo /usr/lib/emscripten/emcc)}"
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
OUT="$ROOT/playground/public"
|
||||
OUT="$ROOT/manifold/public"
|
||||
SRC="$ROOT/nisps/wasm/bindings.cpp"
|
||||
|
||||
if [[ ! -x "$EMCC" && ! -f "$EMCC" ]]; then
|
||||
|
|
@ -82,3 +85,10 @@ set -x
|
|||
|
||||
echo "[build-wasm] wrote $OUT/nisps.js + $OUT/nisps.wasm"
|
||||
ls -lh "$OUT/nisps.js" "$OUT/nisps.wasm"
|
||||
|
||||
# Transitional copy for the playground; removed when P1 deletes playground/.
|
||||
PLAYGROUND_OUT="$ROOT/playground/public"
|
||||
if [[ -d "$PLAYGROUND_OUT" ]]; then
|
||||
command cp -f "$OUT/nisps.js" "$OUT/nisps.wasm" "$PLAYGROUND_OUT/"
|
||||
echo "[build-wasm] copied artifacts to $PLAYGROUND_OUT (transitional, until P1)"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
# Prerequisites:
|
||||
# 1. scripts/build-cpp-tests.sh has run (need nisps_parity_check binary).
|
||||
# 2. scripts/build-wasm.sh has run (need playground/public/nisps.{js,wasm}).
|
||||
# 2. scripts/build-wasm.sh has run (need manifold/public/nisps.{js,wasm}).
|
||||
#
|
||||
# This script can run either step on demand if the artifacts are missing.
|
||||
# Skip auto-build with NISPS_PARITY_NO_BUILD=1.
|
||||
|
|
@ -21,8 +21,8 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|||
TESTS_DIR="$ROOT/tests/cpp"
|
||||
BUILD_DIR="${NISPS_BUILD_DIR:-$ROOT/nisps/build}"
|
||||
NATIVE_BIN="$BUILD_DIR/nisps_parity_check"
|
||||
WASM_GLUE="$ROOT/playground/public/nisps.js"
|
||||
WASM_MOD="$ROOT/playground/public/nisps.wasm"
|
||||
WASM_GLUE="$ROOT/manifold/public/nisps.js"
|
||||
WASM_MOD="$ROOT/manifold/public/nisps.wasm"
|
||||
NATIVE_OUT="$TESTS_DIR/parity_native.bin"
|
||||
WASM_OUT="$TESTS_DIR/parity_wasm.bin"
|
||||
TOL="${NISPS_PARITY_TOL:-1e-5}"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* parity_check.cpp against the WASM build of nisps and writes a binary blob
|
||||
* with identical layout. The shell wrapper compares the two blobs.
|
||||
*
|
||||
* The WASM module is loaded from playground/public/nisps.{js,wasm} —
|
||||
* The WASM module is loaded from manifold/public/nisps.{js,wasm} —
|
||||
* scripts/build-wasm.sh must have run first.
|
||||
*
|
||||
* Output blob format matches parity_check.cpp:
|
||||
|
|
@ -48,7 +48,7 @@ const SYNTH_FRAMES = 128;
|
|||
const PROBE_IDX = [0, 5, 19, 31, 73, 137, 251, 491, 999, 1583, 2401, 3289];
|
||||
|
||||
async function loadWasm() {
|
||||
const wasmGluePath = resolve(repoRoot, 'playground', 'public', 'nisps.js');
|
||||
const wasmGluePath = resolve(repoRoot, 'manifold', 'public', 'nisps.js');
|
||||
try {
|
||||
await access(wasmGluePath, fsConstants.R_OK);
|
||||
} catch {
|
||||
|
|
@ -59,7 +59,7 @@ async function loadWasm() {
|
|||
// The Emscripten glue is generated with MODULARIZE=1, which writes
|
||||
// var createNispsModule = (() => ...)();
|
||||
// if (typeof exports==='object' && typeof module==='object') module.exports = ...;
|
||||
// It lives in playground/public/, which is a sub-package with
|
||||
// It lives in manifold/public/, which is a sub-package with
|
||||
// "type":"module" in its parent package.json — so neither `require()` nor
|
||||
// `import()` can extract the factory cleanly. We work around this by
|
||||
// reading the file as text and evaluating it inside a thin shim that
|
||||
|
|
@ -77,7 +77,7 @@ async function loadWasm() {
|
|||
console.error('[parity_wasm] could not locate createNispsModule in glue');
|
||||
process.exit(2);
|
||||
}
|
||||
const wasmBinaryPath = resolve(repoRoot, 'playground', 'public', 'nisps.wasm');
|
||||
const wasmBinaryPath = resolve(repoRoot, 'manifold', 'public', 'nisps.wasm');
|
||||
const wasmBinary = await readFile(wasmBinaryPath);
|
||||
const Module = await factory({ wasmBinary });
|
||||
return Module;
|
||||
|
|
|
|||
Loading…
Reference in a new issue