Records canonical gesture trace, curve catalog samples, and input/output pipeline outputs from the current TS implementations, plus a bun-test drift guard that re-runs them against the fixtures within 1e-9. Serves the P4 one-core-engine gate: same pointer trace -> same routed output pre/post the C++/WASM migration. |
||
|---|---|---|
| .. | ||
| _generate.ts | ||
| curves-golden.json | ||
| gesture-trace.json | ||
| input-pipeline-golden.json | ||
| output-pipeline-golden.json | ||
| README.md | ||
Pipeline golden fixtures
Captured 2026-07-13 from the current TypeScript engine implementations,
before the P4 "one core engine" migration
(docs/specs/plans/one-core-engine-refactor.md §P4) replaces the TS
curve/input/output code with calls into the C++/WASM core.
P4's own gate reads: "recorded-gesture regression: same pointer trace → same routed output pre/post migration (capture fixture before starting)." These files are that capture.
What is here
| File | What it pins | Source under test |
|---|---|---|
gesture-trace.json |
One canonical synthetic pointer trace (288 events, fixed 120 Hz dt) over the input pipeline's native [0,1]² domain: h/v sweeps, diagonal, spiral, figure-eight, dwell + abrupt corner jumps. Pure formula — no Math.random, no Date.now. |
(input to the input pipeline) |
curves-golden.json |
applyCurve(name, x) for every curve id in curves.ts, 129 samples of x ∈ [0,1] inclusive, at each curve's default param. |
src/engine/curves.ts |
input-pipeline-golden.json |
The gesture trace run through processInput under 14 representative configs (default, deadzone, zoom, sticky anchor, per-axis, curves, smoothing, invert, momentum gentle/strong, frozen axis, fully frozen, combined). Records {x, y, frozen} per event. Configs embedded. |
src/engine/input-pipeline.ts |
output-pipeline-golden.json |
A deterministic raw-output sequence (120 vectors × 8 channels of offset sines, quantised to f32) run through processOutput under 8 configs (default, curves, smoothing, slew limiting, global-freeze toggled mid-sequence, per-output freeze mask, combined). Records the processed vector per step. Configs embedded. |
src/engine/output-pipeline.ts |
The drift guard
../pipeline-golden.test.ts (bun test) re-runs the current TS
implementations against these fixtures and asserts equality within 1e-9. It
reads the trace, raw sequence, and configs from the JSON — the fixtures are
authoritative, so editing pipeline-golden-lib.ts config lists cannot mask a
regression. Any change to curves.ts / input-pipeline.ts / output-pipeline.ts
that alters numeric behaviour breaks this test until the goldens are
deliberately re-captured.
To re-capture (only when intended): cd manifold && bun tests/fixtures/_generate.ts.
Contracts you must reproduce to consume these
State contract (both pipelines are stateful)
- Input: EMA-smoothed x/y, a velocity ring, and a momentum-zoom multiplier.
- Output:
prev+smoothedbuffers driving slew/freeze.
Each config run resets state (defaultInputState() / defaultOutputState())
at step 0. Runs are independent; do not carry state between them.
Clock contract (input pipeline only)
input-pipeline.ts's momentum-zoom path reads performance.now() (wall clock)
for its 150 ms velocity window. To make the momentum configs reproducible, the
capture pins performance.now() to each event's t_ms before processing it, so
the velocity window slides over the gesture's own timescale. dt passed to
processInput is the per-event t_ms delta in seconds (fixed 1000/120 ms).
A future consumer that ports this to C++ must feed the same per-event timestamps
(the trace's t_ms) into whatever owns the velocity ring, or the momentum runs
will not match. The output pipeline uses no wall clock; its dtMs is a fixed
1000/60.
JSON encodings
slewRate: nullin an output spec meansInfinity(JSON has noInfinity).- Output raw values are pre-quantised with
Math.froundso they equal exactly what aFloat32Arrayholds.
How P4 should consume these
After the input/output/curve logic moves into the C++/WASM core, flip
pipeline-golden.test.ts to drive the WASM implementations (via the
main-thread nisps instance) instead of the TS run* helpers, keeping the same
fixtures as the expected values. That proves same pointer trace → same routed
output across the migration.
Tolerance: these goldens were produced in TS f64. The WASM core computes in f32 for many paths, so exact 1e-9 equality will not hold post-migration — relax the comparison to about 1e-5 (and expect the sigmoid/exp/log curve tails and long smoothing/slew accumulations to be the widest-drifting points). If any value drifts materially beyond that, it is a real behavioural divergence, not float noise, and must be reconciled in the core rather than by widening tolerance.