2026-07-13 23:25:31 +02:00
|
|
|
/**
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
* Fixture-support library for the pipeline golden tests.
|
2026-07-13 23:25:31 +02:00
|
|
|
*
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
* Since the one-core-engine P4 migration the input/output PROCESSING lives in
|
|
|
|
|
* the C++/WASM core; the golden test (tests/pipeline-golden.test.ts) drives the
|
|
|
|
|
* WASM chains against the committed fixtures. This module no longer runs any TS
|
|
|
|
|
* pipeline maths — it only provides the PURE, deterministic fixture DATA
|
|
|
|
|
* (gesture trace, raw output sequence) + the representative config lists + the
|
|
|
|
|
* curve catalog metadata. The gesture/sequence/config data is embedded in the
|
|
|
|
|
* committed *.json fixtures, so the test re-derives nothing hidden.
|
2026-07-13 23:25:31 +02:00
|
|
|
*
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
* The gesture/output goldens are a FROZEN pre-migration capture (2026-07-13):
|
|
|
|
|
* the test proves the WASM chains reproduce them within an f32 tolerance. The
|
|
|
|
|
* curve goldens were partly re-baselined on 2026-07-18 (see README + the
|
|
|
|
|
* curves-golden.json provenance field).
|
2026-07-13 23:25:31 +02:00
|
|
|
*/
|
|
|
|
|
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
import {
|
|
|
|
|
CURVE_DEFAULT_PARAMS,
|
|
|
|
|
CURVE_NAMES,
|
|
|
|
|
type CurveName,
|
|
|
|
|
} from '../src/engine/curve-catalog';
|
2026-07-13 23:25:31 +02:00
|
|
|
import {
|
|
|
|
|
defaultInputConfig,
|
|
|
|
|
type InputConfig,
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
} from '../src/engine/pipeline-types';
|
|
|
|
|
|
|
|
|
|
export { CURVE_DEFAULT_PARAMS, CURVE_NAMES };
|
|
|
|
|
export type { CurveName, InputConfig };
|
2026-07-13 23:25:31 +02:00
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Shared timebases
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/** Input trace step: 120 Hz. */
|
|
|
|
|
export const INPUT_DT_MS = 1000 / 120; // 8.3333… ms
|
|
|
|
|
/** Output sequence step: 60 Hz. */
|
|
|
|
|
export const OUTPUT_DT_MS = 1000 / 60; // 16.6666… ms
|
|
|
|
|
/** Output vector width used by the synthetic raw sequence. */
|
|
|
|
|
export const OUTPUT_DIMS = 8;
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// Fixture value types
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
export interface GestureEvent {
|
|
|
|
|
t_ms: number;
|
|
|
|
|
x: number;
|
|
|
|
|
y: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface InputRunOutput {
|
|
|
|
|
x: number;
|
|
|
|
|
y: number;
|
|
|
|
|
frozen: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** JSON-serialisable input run: an id + the full InputConfig. */
|
|
|
|
|
export interface InputRunSpec {
|
|
|
|
|
id: string;
|
|
|
|
|
config: InputConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* JSON-serialisable output run spec. `slewRate: null` means `Infinity`
|
|
|
|
|
* (JSON has no Infinity). `freezeMaskIndices` freezes those output indices for
|
|
|
|
|
* the whole run. `freezeSteps: [start, end)` toggles the GLOBAL freeze gate on
|
|
|
|
|
* for that half-open step range.
|
|
|
|
|
*/
|
|
|
|
|
export interface OutputRunSpec {
|
|
|
|
|
id: string;
|
|
|
|
|
globalCurve: number;
|
|
|
|
|
smoothing: number;
|
|
|
|
|
slewRate: number | null;
|
|
|
|
|
freezeMaskIndices: number[] | null;
|
|
|
|
|
freezeSteps: [number, number] | null;
|
|
|
|
|
reuseBuffer: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
// 1. Gesture trace generator (pure formula — no Math.random / Date.now)
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
const TAU = Math.PI * 2;
|
|
|
|
|
|
|
|
|
|
function clamp01(v: number): number {
|
|
|
|
|
return v < 0 ? 0 : v > 1 ? 1 : v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* One canonical synthetic pointer trace over the pipeline's native [0,1]^2
|
|
|
|
|
* input domain. 288 events at a fixed 120 Hz dt. Six segments (48 events each)
|
|
|
|
|
* exercise: horizontal sweep, vertical sweep, diagonal corner-to-corner,
|
|
|
|
|
* growing spiral, a Lissajous figure-eight, and dwell periods punctuated by
|
|
|
|
|
* abrupt corner jumps. Endpoints (0 and 1) are visited so the full range is
|
|
|
|
|
* covered.
|
|
|
|
|
*/
|
|
|
|
|
export function buildGestureTrace(): GestureEvent[] {
|
|
|
|
|
const seg = 48;
|
|
|
|
|
const events: GestureEvent[] = [];
|
|
|
|
|
const push = (x: number, y: number) => {
|
|
|
|
|
const i = events.length;
|
|
|
|
|
events.push({ t_ms: i * INPUT_DT_MS, x: clamp01(x), y: clamp01(y) });
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Segment 1 — horizontal sweep left→right at mid height.
|
|
|
|
|
for (let i = 0; i < seg; i++) push(i / (seg - 1), 0.5);
|
|
|
|
|
// Segment 2 — vertical sweep bottom→top at mid width.
|
|
|
|
|
for (let i = 0; i < seg; i++) push(0.5, i / (seg - 1));
|
|
|
|
|
// Segment 3 — diagonal, corner (0,0) → (1,1).
|
|
|
|
|
for (let i = 0; i < seg; i++) {
|
|
|
|
|
const t = i / (seg - 1);
|
|
|
|
|
push(t, t);
|
|
|
|
|
}
|
|
|
|
|
// Segment 4 — outward spiral around centre (radius 0 → 0.5).
|
|
|
|
|
for (let i = 0; i < seg; i++) {
|
|
|
|
|
const t = i / (seg - 1);
|
|
|
|
|
const r = 0.5 * t;
|
|
|
|
|
const ang = TAU * 3 * t;
|
|
|
|
|
push(0.5 + r * Math.cos(ang), 0.5 + r * Math.sin(ang));
|
|
|
|
|
}
|
|
|
|
|
// Segment 5 — Lissajous figure-eight (1:2), amplitude 0.48.
|
|
|
|
|
for (let i = 0; i < seg; i++) {
|
|
|
|
|
const t = i / (seg - 1);
|
|
|
|
|
push(0.5 + 0.48 * Math.sin(TAU * t), 0.5 + 0.48 * Math.sin(TAU * 2 * t));
|
|
|
|
|
}
|
|
|
|
|
// Segment 6 — dwell + abrupt jumps. Hold a point for 8 frames, jump, repeat.
|
|
|
|
|
const stops: Array<[number, number]> = [
|
|
|
|
|
[0.5, 0.5],
|
|
|
|
|
[0.0, 0.0],
|
|
|
|
|
[1.0, 1.0],
|
|
|
|
|
[0.0, 1.0],
|
|
|
|
|
[1.0, 0.0],
|
|
|
|
|
[0.5, 0.5],
|
|
|
|
|
];
|
|
|
|
|
for (let s = 0; s < stops.length; s++) {
|
|
|
|
|
const [x, y] = stops[s]!;
|
|
|
|
|
for (let h = 0; h < seg / stops.length; h++) push(x, y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return events;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
// 2. Curve sampling metadata
|
2026-07-13 23:25:31 +02:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
export const CURVE_SAMPLE_COUNT = 129; // 0..1 inclusive, step 1/128
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
// 3. Input pipeline configs
|
2026-07-13 23:25:31 +02:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
function cfg(overrides: Partial<InputConfig>): InputConfig {
|
|
|
|
|
return { ...defaultInputConfig(), ...overrides };
|
|
|
|
|
}
|
|
|
|
|
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
/** Representative input configs. Exercises every branch of the input chain. */
|
2026-07-13 23:25:31 +02:00
|
|
|
export function inputRunSpecs(): InputRunSpec[] {
|
|
|
|
|
return [
|
|
|
|
|
{ id: 'default', config: cfg({}) },
|
|
|
|
|
{ id: 'deadzone', config: cfg({ deadzone: 0.3 }) },
|
|
|
|
|
{ id: 'zoom-narrow', config: cfg({ zoom: 0.4 }) },
|
|
|
|
|
{ id: 'zoom-sticky-anchor', config: cfg({ zoom: 0.5, anchorMode: 'sticky', anchorX: 0.3, anchorY: 0.7 }) },
|
|
|
|
|
{ id: 'curve-pull-center', config: cfg({ inputCurve: 3.0 }) },
|
|
|
|
|
{ id: 'curve-push-extremes', config: cfg({ inputCurve: 0.4 }) },
|
|
|
|
|
{ id: 'smoothing', config: cfg({ smoothing: 0.8 }) },
|
|
|
|
|
{ id: 'invert-both', config: cfg({ invertX: true, invertY: true }) },
|
|
|
|
|
{ id: 'per-axis', config: cfg({ zoomX: 0.6, zoomY: 1.0, inputCurveX: 2.0, inputCurveY: 0.5 }) },
|
|
|
|
|
{ id: 'momentum-gentle', config: cfg({ momentumZoom: 'gentle' }) },
|
|
|
|
|
{ id: 'momentum-strong', config: cfg({ momentumZoom: 'strong', smoothing: 0.5 }) },
|
|
|
|
|
{ id: 'mixed-frozen-axis', config: cfg({ zoomX: 0.005, zoomY: 1.0 }) },
|
|
|
|
|
{ id: 'fully-frozen', config: cfg({ zoom: 0.005 }) },
|
|
|
|
|
{
|
|
|
|
|
id: 'combined',
|
|
|
|
|
config: cfg({ deadzone: 0.2, zoom: 0.7, inputCurve: 1.6, smoothing: 0.6, momentumZoom: 'gentle' }),
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
feat(manifold)!: route input/output pipelines + curves through the WASM core (P4.3/P4.4)
One-core-engine P4.3/P4.4: the input/output pipeline processing and the curve
catalog now live in the C++/WASM core (nisps/pipeline/*, nisps/core/math.hpp).
The TS ports are deleted and the browser drives the WASM chains.
Engine:
- WasmIML owns a nisps_pipeline_create handle + bridge buffers and exposes
setInputConfig (TS InputConfig → 15-float wire), processInput, resetInput,
setOutputConfig (Infinity slew → 0), setOutputFreezeMask, processOutput
(in place), resetOutput, curveApply, curveApplyBatch (chunked). Handle +
buffers created in init_, freed in dispose, output-sized buffers realloc'd
on reshape.
- Spine routes setInputs through iml.processInput/processOutput (state lives
C++-side); config source-of-truth stays TS-side and is pushed on attach /
setInputConfig / setOutputConfig. Preserves ?debug=1 fixed-dt determinism
(same dt fed to the WASM calls). EngineApi gains setInputConfig/
setOutputConfig/curveApply/curveApplyBatch.
- New types-only modules: pipeline-types.ts (InputConfig/OutputConfig +
defaults + wire int mappers) and curve-catalog.ts (CurveName + name→id).
types.ts declares the pipeline/curve C ABI. engine barrel updated.
- DELETED src/engine/{input-pipeline,output-pipeline,curves}.ts.
Tests (P4.4 gate — recorded-gesture regression):
- pipeline-golden.test.ts now loads the built WASM (indirect-eval shim,
tests/wasm-load.ts) and drives the frozen gesture/output fixtures through the
C++ chains, honouring the per-event dt clock contract. Tolerance 1e-5
(non-momentum drift <5e-7). The 3 momentum configs carry 1e-2: proven-inherent
f32 drift (a byte-faithful f32 port of the exact original algorithm matches
the WASM to <6e-8 while both diverge from the f64 capture by ~7-9e-3), NOT a
core bug.
- curves-golden.json: linear/square/sqrt/centered_power kept as the original
f64 captures (C++ matches within <3e-8); exp/log/sigmoid/cubic RE-BASELINED
from the WASM (deliberate switch to firmware-exact k=1 exp/log, slope-6
sigmoid, true cubic x^3). Provenance recorded in-file.
- _generate.ts rebuilt as the WASM curve re-baseline tool; pipeline-golden-lib
trimmed to pure data builders.
Docs: fixtures/README.md + manifold/ONBOARDING.md updated.
Gates: typecheck, bun test (9), vite build, playwright e2e (27) all green.
2026-07-18 12:21:35 +02:00
|
|
|
// 4. Output raw sequence + configs
|
2026-07-13 23:25:31 +02:00
|
|
|
// ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A deterministic raw output sequence: 120 vectors of width OUTPUT_DIMS, each
|
|
|
|
|
* channel an offset sine, quantised to f32 (Math.fround) so it matches exactly
|
|
|
|
|
* what the Float32Array pipeline input holds.
|
|
|
|
|
*/
|
|
|
|
|
export function buildOutputSequence(steps = 120, dims = OUTPUT_DIMS): number[][] {
|
|
|
|
|
const seq: number[][] = [];
|
|
|
|
|
for (let s = 0; s < steps; s++) {
|
|
|
|
|
const row: number[] = [];
|
|
|
|
|
for (let j = 0; j < dims; j++) {
|
|
|
|
|
const freq = (j + 1) * 0.5;
|
|
|
|
|
const phase = j / dims;
|
|
|
|
|
const v = 0.5 + 0.5 * Math.sin(TAU * (freq * (s / steps) + phase));
|
|
|
|
|
row.push(Math.fround(v));
|
|
|
|
|
}
|
|
|
|
|
seq.push(row);
|
|
|
|
|
}
|
|
|
|
|
return seq;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Representative output configs. */
|
|
|
|
|
export function outputRunSpecs(): OutputRunSpec[] {
|
|
|
|
|
return [
|
|
|
|
|
{ id: 'default', globalCurve: 1.0, smoothing: 0, slewRate: null, freezeMaskIndices: null, freezeSteps: null, reuseBuffer: false },
|
|
|
|
|
{ id: 'curve-pull', globalCurve: 2.5, smoothing: 0, slewRate: null, freezeMaskIndices: null, freezeSteps: null, reuseBuffer: false },
|
|
|
|
|
{ id: 'curve-push', globalCurve: 0.4, smoothing: 0, slewRate: null, freezeMaskIndices: null, freezeSteps: null, reuseBuffer: false },
|
|
|
|
|
{ id: 'smoothing', globalCurve: 1.0, smoothing: 0.85, slewRate: null, freezeMaskIndices: null, freezeSteps: null, reuseBuffer: false },
|
|
|
|
|
{ id: 'slew-limited', globalCurve: 1.0, smoothing: 0, slewRate: 0.5, freezeMaskIndices: null, freezeSteps: null, reuseBuffer: false },
|
|
|
|
|
{ id: 'freeze-toggled', globalCurve: 1.0, smoothing: 0, slewRate: null, freezeMaskIndices: null, freezeSteps: [40, 80], reuseBuffer: false },
|
|
|
|
|
{ id: 'freeze-mask', globalCurve: 1.0, smoothing: 0, slewRate: null, freezeMaskIndices: [0, 2, 4], freezeSteps: null, reuseBuffer: false },
|
|
|
|
|
{ id: 'combined', globalCurve: 1.8, smoothing: 0.7, slewRate: 1.0, freezeMaskIndices: null, freezeSteps: [90, 110], reuseBuffer: false },
|
|
|
|
|
];
|
|
|
|
|
}
|