even more

This commit is contained in:
Andras Schmelczer 2026-08-23 10:27:55 +01:00
commit 8f50ebdb97
8 changed files with 1842 additions and 3095 deletions

View file

@ -1,185 +1,150 @@
// Regression net for backend defects — drives the real classes.
import { describe, it, expect, beforeEach } from 'vitest';
import { createRequire } from 'node:module';
import { PhysicalContainer } from '../backend/src/physics/containers/physical-container';
import { BoundingBox } from '../backend/src/physics/bounding-boxes/bounding-box';
import { PhysicalContainer } from '../backend/src/physics/physical-container';
import { BoundingBox } from '../backend/src/physics/bounding-box';
import { ProjectilePhysical } from '../backend/src/objects/projectile-physical';
import { CharacterPhysical } from '../backend/src/objects/character-physical';
import { StepCommand, GeneratePointsCommand } from '../backend/src/commands/commands';
const require = createRequire(import.meta.url);
const shared = require('../shared/lib/main.js');
const { vec2 } = require('../shared/node_modules/gl-matrix');
const { applyArrayPlugins, Random, settings, CharacterTeam } = shared;
applyArrayPlugins();
const { Random, settings, CharacterTeam } = shared;
const step = settings.targetPhysicsDeltaTimeInSeconds;
class PointsSpy {
public blue = 0;
public red = 0;
public handleCommand(command: unknown) {
if (command instanceof GeneratePointsCommand) {
this.blue += command.blue;
this.red += command.red;
}
public addPoints(blue: number, red: number) {
this.blue += blue;
this.red += red;
}
public announce() {}
}
const boxAround = (center: number[], radius: number) => {
const box = new BoundingBox();
box.xMin = center[0] - radius;
box.xMax = center[0] + radius;
box.yMin = center[1] - radius;
box.yMax = center[1] + radius;
return box;
const makeWorld = () => {
const game = new PointsSpy();
return { game, container: new PhysicalContainer(game) };
};
const spawnProjectile = (container: PhysicalContainer) =>
new ProjectilePhysical(
vec2.fromValues(0, 0),
20,
40,
CharacterTeam.blue,
vec2.fromValues(3000, 0),
{ team: CharacterTeam.blue } as never,
container,
0,
);
const spawnCharacter = (container: PhysicalContainer) => {
const character = new CharacterPhysical(
'tester',
0,
0,
CharacterTeam.blue,
container,
vec2.fromValues(0, 0),
);
container.addObject(character);
return character;
};
const projectilesIn = (container: PhysicalContainer) =>
container
.findIntersecting(BoundingBox.ofCircle([0, 0], 5000))
.filter((o) => o.gameObject instanceof ProjectilePhysical)
.map((o) => o.gameObject as ProjectilePhysical);
beforeEach(() => {
Random.seed = 1;
});
describe('projectile broadphase registration', () => {
it('follows the projectile instead of staying at the muzzle', () => {
const container = new PhysicalContainer();
container.initialize();
const projectile = new ProjectilePhysical(
vec2.fromValues(0, 0),
20,
40,
CharacterTeam.blue,
vec2.fromValues(3000, 0),
{ team: CharacterTeam.blue } as never,
container,
0,
);
const { container } = makeWorld();
const projectile = spawnProjectile(container);
container.addObject(projectile);
for (let i = 0; i < 40; i++) {
container.handleCommand(new StepCommand(step, new PointsSpy() as never));
container.step(step);
}
expect(projectile.center[0]).toBeGreaterThan(400);
expect(container.findIntersecting(boxAround(projectile.center, 100))).toContain(
expect(
container.findIntersecting(BoundingBox.ofCircle(projectile.center, 100)),
).toContain(projectile);
expect(container.findIntersecting(BoundingBox.ofCircle([0, 0], 100))).not.toContain(
projectile,
);
expect(container.findIntersecting(boxAround([0, 0], 100))).not.toContain(projectile);
});
it('spawns a shot just clear of the shooter, not a jump downrange', () => {
const container = new PhysicalContainer();
container.initialize();
const projectile = new ProjectilePhysical(
vec2.fromValues(0, 0),
20,
40,
CharacterTeam.blue,
vec2.fromValues(3000, 0),
{ team: CharacterTeam.blue } as never,
container,
0,
);
const { container } = makeWorld();
const projectile = spawnProjectile(container);
expect(projectile.center[0]).toBeLessThanOrEqual(15);
});
});
describe('scoring', () => {
const spawnCharacter = (container: PhysicalContainer) => {
const character = new CharacterPhysical(
'tester',
0,
0,
CharacterTeam.blue,
container,
vec2.fromValues(0, 0),
);
container.addObject(character);
return character;
};
it('awards nothing for an administrative death', () => {
const container = new PhysicalContainer();
container.initialize();
const { game, container } = makeWorld();
const character = spawnCharacter(container);
const game = new PointsSpy();
character.onDie(); // what PlayerBase.destroy() does on a socket drop
container.handleCommand(new StepCommand(step, game as never));
character.onDie();
container.step(step);
expect(game.blue).toBe(0);
expect(game.red).toBe(0);
});
it('still awards a kill for a combat death', () => {
const container = new PhysicalContainer();
container.initialize();
const { game, container } = makeWorld();
const character = spawnCharacter(container);
const game = new PointsSpy();
character.onDie(true);
container.handleCommand(new StepCommand(step, game as never));
container.step(step);
expect(game.red).toBe(settings.playerKillPoint);
expect(game.blue).toBe(0);
});
it('awards a combat death only once', () => {
const { game, container } = makeWorld();
const character = spawnCharacter(container);
character.onDie(true);
character.onDie(true);
expect(game.red).toBe(settings.playerKillPoint);
});
});
describe('charged shots', () => {
it('scales the shot by the strength actually paid, not the requested charge', () => {
const container = new PhysicalContainer();
container.initialize();
const character = new CharacterPhysical(
'tester',
0,
0,
CharacterTeam.blue,
container,
vec2.fromValues(0, 0),
);
container.addObject(character);
const { container } = makeWorld();
const character = spawnCharacter(container);
(character as unknown as { projectileStrength: number }).projectileStrength =
settings.chargeShotStrengthMin;
const before = container.findIntersecting(boxAround([0, 0], 5000)).length;
character.shootTowards(vec2.fromValues(1000, 0), 1);
const spawned = container
.findIntersecting(boxAround([0, 0], 5000))
.filter((o) => o.gameObject instanceof ProjectilePhysical)
.map((o) => o.gameObject as ProjectilePhysical);
const [spawned] = projectilesIn(container);
expect(container.findIntersecting(boxAround([0, 0], 5000)).length).toBeGreaterThan(
before,
);
expect(spawned[0].charge).toBeCloseTo(0, 5);
expect(spawned[0].radius).toBeCloseTo(settings.chargeShotRadiusMin, 5);
expect(spawned).toBeDefined();
expect(spawned.charge).toBeCloseTo(0, 5);
expect(spawned.radius).toBeCloseTo(settings.chargeShotRadiusMin, 5);
});
it('ignores a shot aimed at the shooter itself', () => {
const container = new PhysicalContainer();
container.initialize();
const character = new CharacterPhysical(
'tester',
0,
0,
CharacterTeam.blue,
container,
vec2.fromValues(0, 0),
);
container.addObject(character);
const { container } = makeWorld();
const character = spawnCharacter(container);
const projectilesBefore = container
.findIntersecting(boxAround([0, 0], 5000))
.filter((o) => o.gameObject instanceof ProjectilePhysical).length;
character.shootTowards(vec2.clone(character.center), 1);
const projectilesAfter = container
.findIntersecting(boxAround([0, 0], 5000))
.filter((o) => o.gameObject instanceof ProjectilePhysical).length;
expect(projectilesAfter).toBe(projectilesBefore);
expect(projectilesIn(container)).toHaveLength(0);
});
});

View file

@ -1,15 +1,13 @@
// Slow-client backpressure: what a Player sheds when its socket stops draining.
import { describe, it, expect, beforeEach } from 'vitest';
import { createRequire } from 'node:module';
import { PhysicalContainer } from '../backend/src/physics/containers/physical-container';
import { PhysicalContainer } from '../backend/src/physics/physical-container';
import { PlayerContainer } from '../backend/src/players/player-container';
import { createWorld } from '../backend/src/create-world';
const require = createRequire(import.meta.url);
const shared = require('../shared/lib/main.js');
const {
applyArrayPlugins,
Random,
settings,
TransportEvents,
@ -21,9 +19,6 @@ const {
ServerAnnouncement,
} = shared;
applyArrayPlugins();
// Shaped like engine.io: the byte count lives on the ws socket under the transport.
class FakeSocket {
public readonly sent: Array<{ event: string; payload: unknown }> = [];
public readonly conn = { transport: { socket: { bufferedAmount: 0 } } };
@ -48,9 +43,8 @@ class FakeSocket {
const makePlayer = () => {
Random.seed = 3;
const objects = new PhysicalContainer();
const objects = new PhysicalContainer({ addPoints() {}, announce() {} });
createWorld(objects);
objects.initialize();
const players = new PlayerContainer(objects, 4, 0);
const socket = new FakeSocket();
const player = players.createPlayer({ name: 'player' }, socket as never);

View file

@ -1,4 +1,3 @@
// Client outbound send cadence vs. server inbound allowance.
import { describe, it, expect } from 'vitest';
import { createRequire } from 'node:module';
@ -8,9 +7,7 @@ import { setFrameTimeMs } from '../frontend/src/scripts/helper/prediction/local-
const require = createRequire(import.meta.url);
const shared = require('../shared/lib/main.js');
const { vec2 } = require('../shared/node_modules/gl-matrix');
const { applyArrayPlugins, settings, MoveActionCommand, ClientHeartbeatCommand } = shared;
applyArrayPlugins();
const { settings, MoveActionCommand, ClientHeartbeatCommand } = shared;
const drive = (
frameRate: number,
@ -57,7 +54,7 @@ describe('client send cadence', () => {
let sentOn = -1;
const batches = drive(144, 0.1, (commandSocket) => {
if (sentOn === -1) {
commandSocket.handleCommand(new MoveActionCommand(vec2.fromValues(1, 0), 0));
commandSocket.queue(new MoveActionCommand(vec2.fromValues(1, 0), 0));
sentOn = 0;
}
});
@ -73,15 +70,12 @@ describe('client send cadence', () => {
expect(batches.every((b) => b.includes(ClientHeartbeatCommand.name))).toBe(true);
});
// socket.io-client buffers emits made while disconnected in an uncapped
// sendBuffer and flushes them on reconnect, ahead of the re-join — so every
// one of them is both a leak and wasted bandwidth.
it('sends nothing at all while the transport is down', () => {
const batches = drive(
60,
30,
(commandSocket) =>
commandSocket.handleCommand(new MoveActionCommand(vec2.fromValues(1, 0), 0)),
commandSocket.queue(new MoveActionCommand(vec2.fromValues(1, 0), 0)),
false,
);

View file

@ -1,4 +1,3 @@
// Connection lifecycle: join guard, refusal reasons, reconnect — driven through a fake socket.io.
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { createRequire } from 'node:module';
@ -7,10 +6,7 @@ import { defaultOptions } from '../backend/src/options';
const require = createRequire(import.meta.url);
const shared = require('../shared/lib/main.js');
const { applyArrayPlugins, Random, TransportEvents, JoinRejectionReason, settings } =
shared;
applyArrayPlugins();
const { Random, TransportEvents, JoinRejectionReason, settings } = shared;
class FakeSocket {
public readonly sent: Array<{ event: string; payload: unknown }> = [];
@ -40,7 +36,6 @@ class FakeSocket {
this.disconnected = true;
}
/** Number of listeners the server has attached for an event. */
public listenerCount(event: string): number {
return (this.handlers.get(event) ?? []).length;
}
@ -142,9 +137,6 @@ describe('hostile payloads', () => {
expect(server.serverInfo.playerCount).toBe(4);
});
// socket.io dispatches listeners with no try/catch of its own, so anything
// thrown out of a connection-scoped handler is an uncaught exception: the
// process exits and every player in the match is dropped with it.
it.each([
['no payload at all', undefined],
['null', null],
@ -190,7 +182,6 @@ describe('reconnect', () => {
expect(server.serverInfo.playerCount).toBe(1);
expect(second.disconnected).toBe(false);
expect(second.lastPayloadFor(TransportEvents.JoinRejected)).toBeUndefined();
// Fresh token: the old one cannot be replayed.
expect(second.lastPayloadFor(TransportEvents.PlayerJoined)).not.toBe(token);
});
@ -251,9 +242,6 @@ describe('inbound rate limiting', () => {
});
describe('pre-join rate limiting', () => {
// These listeners exist before any join, so the limiter inside
// onPlayerToServer never sees them: unmetered, each one is a reply or an
// allocation an unauthenticated client can ask for at line rate.
it('clamps a flood of joins on an already-joined connection', () => {
const { attach } = startServer({ playerLimit: 4, npcCount: 0 });
const socket = attach();
@ -312,7 +300,6 @@ describe('reconnect tokens', () => {
});
describe('reconnect while the dropped socket is still live', () => {
// engine.io needs ~45 s to notice a transport drop; the client is back in ~1 s.
it('retires the ghost so the returning player keeps its slot, team and score', () => {
const { server, attach } = startServer({ playerLimit: 1, npcCount: 0 });
@ -321,7 +308,6 @@ describe('reconnect while the dropped socket is still live', () => {
const token = first.lastPayloadFor(TransportEvents.PlayerJoined) as string;
expect(server.serverInfo.playerCount).toBe(1);
// No 'disconnect' fired: the server still holds the dead socket's player.
const second = attach();
second.fire(TransportEvents.PlayerJoining, { name: 'flaky', reconnectToken: token });

View file

@ -1,10 +1,7 @@
// Determinism guard: client predictor and server run the same stepCharacterMovement.
import { describe, it, expect } from 'vitest';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
// Numerics match production because test/setup.mjs has already applied
// glMatrix.setMatrixArrayType(Array) — without it this would pin f32.
const shared = require('../shared/lib/main.js');
const { vec2 } = require('../shared/node_modules/gl-matrix');
@ -12,8 +9,6 @@ const {
stepCharacterMovement,
tickPlanetDetachment,
resolveCircleMovement,
planetDistance,
planetGravity,
PlanetBase,
Random,
headRadius,
@ -23,6 +18,8 @@ const {
rightFootOffset,
} = shared;
const stepSeconds = 1 / 200;
const makeBody = (center, radius) => ({
center: vec2.clone(center),
radius,
@ -31,113 +28,73 @@ const makeBody = (center, radius) => ({
restitution: 0,
});
// Free-space world (no planets): exercises the deterministic core without planet SDF geometry.
const emptyWorld = {
groundsNear: () => [],
const makeState = (start) => ({
head: makeBody(vec2.add(vec2.create(), start, headOffset), headRadius),
leftFoot: makeBody(vec2.add(vec2.create(), start, leftFootOffset), feetRadius),
rightFoot: makeBody(vec2.add(vec2.create(), start, rightFootOffset), feetRadius),
direction: 0,
currentPlanet: undefined,
secondsSinceOnSurface: 1,
bodyVelocity: vec2.create(),
});
const makeWorld = (grounds) => ({
groundsNear: () => grounds,
stepBody: (body, dt) => {
resolveCircleMovement(body, dt, []);
return undefined;
const hit = resolveCircleMovement(body, dt, grounds);
return hit && hit.isGround ? hit : undefined;
},
};
});
const stepSeconds = 1 / 200;
// A spinning planet, built the way create-world builds one, so the SDF/gravity/on-surface branches have a pin too.
const makeSpinningPlanetWorld = () => {
Random.seed = 20;
const vertices = PlanetBase.createPlanetVertices(
vec2.fromValues(0, -900),
1700,
1900,
70,
);
const base = new PlanetBase(1, vertices);
let rotation = 0;
const surface = {
canCollide: true,
isGround: true,
center: base.center,
angularVelocity: 0.09,
advance: (dt) => (rotation += surface.angularVelocity * dt),
distance: (target) =>
planetDistance(
target,
vertices,
base.center,
Math.cos(rotation),
Math.sin(rotation),
),
gravityAt: (target) => planetGravity(base.center, base.radius, target),
};
const grounds = [surface];
return {
surface,
world: {
groundsNear: () => grounds,
stepBody: (body, dt) => {
const { hitObject } = resolveCircleMovement(body, dt, grounds);
return hitObject && hitObject.isGround ? hitObject : undefined;
},
},
};
};
const runPlanetSimulation = () => {
const { surface, world } = makeSpinningPlanetWorld();
const start = vec2.fromValues(0, 250);
const state = {
head: makeBody(vec2.add(vec2.create(), start, headOffset), headRadius),
leftFoot: makeBody(vec2.add(vec2.create(), start, leftFootOffset), feetRadius),
rightFoot: makeBody(vec2.add(vec2.create(), start, rightFootOffset), feetRadius),
direction: 0,
currentPlanet: undefined,
secondsSinceOnSurface: 1,
bodyVelocity: vec2.create(),
};
for (let i = 0; i < 900; i++) {
// Fall in, then walk right, then left.
const input = i < 200 ? vec2.create() : vec2.fromValues(i < 600 ? 1 : -1, 0);
tickPlanetDetachment(state, stepSeconds);
stepCharacterMovement(state, world, input, stepSeconds);
surface.advance(stepSeconds);
}
const round = (v) => Math.round(v * 1000) / 1000;
return JSON.stringify({
head: [round(state.head.center[0]), round(state.head.center[1])],
leftFoot: [round(state.leftFoot.center[0]), round(state.leftFoot.center[1])],
rightFoot: [round(state.rightFoot.center[0]), round(state.rightFoot.center[1])],
direction: round(state.direction),
onSurface: !!state.currentPlanet,
secondsSinceOnSurface: round(state.secondsSinceOnSurface),
});
};
const round = (v) => Math.round(v * 1000) / 1000;
const roundVec = (v) => [round(v[0]), round(v[1])];
const runSimulation = () => {
const start = vec2.fromValues(100, 100);
const state = {
head: makeBody(vec2.add(vec2.create(), start, headOffset), headRadius),
leftFoot: makeBody(vec2.add(vec2.create(), start, leftFootOffset), feetRadius),
rightFoot: makeBody(vec2.add(vec2.create(), start, rightFootOffset), feetRadius),
direction: 0,
currentPlanet: undefined,
secondsSinceOnSurface: 1,
bodyVelocity: vec2.create(),
};
const state = makeState(vec2.fromValues(100, 100));
const world = makeWorld([]);
for (let i = 0; i < 300; i++) {
const angle = i * 0.1;
const input = vec2.fromValues(Math.cos(angle), Math.sin(angle));
stepCharacterMovement(state, emptyWorld, input, stepSeconds);
stepCharacterMovement(
state,
world,
vec2.fromValues(Math.cos(angle), Math.sin(angle)),
stepSeconds,
);
}
const round = (v) => Math.round(v * 1000) / 1000;
return JSON.stringify({
head: [round(state.head.center[0]), round(state.head.center[1])],
leftFoot: [round(state.leftFoot.center[0]), round(state.leftFoot.center[1])],
rightFoot: [round(state.rightFoot.center[0]), round(state.rightFoot.center[1])],
bodyVelocity: [round(state.bodyVelocity[0]), round(state.bodyVelocity[1])],
head: roundVec(state.head.center),
leftFoot: roundVec(state.leftFoot.center),
rightFoot: roundVec(state.rightFoot.center),
bodyVelocity: roundVec(state.bodyVelocity),
});
};
const runPlanetSimulation = () => {
Random.seed = 20;
const planet = new PlanetBase(
1,
PlanetBase.createPlanetVertices(vec2.fromValues(0, -900), 1700, 1900, 70),
);
planet.angularVelocity = 0.09;
const world = makeWorld([planet]);
const state = makeState(vec2.fromValues(0, 250));
for (let i = 0; i < 900; i++) {
const input = i < 200 ? vec2.create() : vec2.fromValues(i < 600 ? 1 : -1, 0);
tickPlanetDetachment(state, stepSeconds);
stepCharacterMovement(state, world, input, stepSeconds);
planet.advanceRotation(stepSeconds);
}
return JSON.stringify({
head: roundVec(state.head.center),
leftFoot: roundVec(state.leftFoot.center),
rightFoot: roundVec(state.rightFoot.center),
direction: round(state.direction),
onSurface: !!state.currentPlanet,
secondsSinceOnSurface: round(state.secondsSinceOnSurface),
});
};
@ -147,7 +104,6 @@ describe('shared character simulation determinism', () => {
});
it('matches the pinned reference pose (changes only with intentional physics edits)', () => {
// Regression pin — update deliberately when physics behaviour changes.
expect(runSimulation()).toMatchSnapshot();
});

View file

@ -1,4 +1,3 @@
// Reconciliation guard for the client predictor: acknowledged pose, deterministic replay, replay-window behaviour.
import { describe, it, expect } from 'vitest';
import {
LocalCharacterPredictor,
@ -95,7 +94,6 @@ describe('local prediction reconciliation', () => {
predictor.setAlive(false);
setFrameTimeMs(5200);
// Regression: a dead body must not be predicted/moved.
expect(predictor.update([], 1 / 60)).toBe(false);
});
@ -157,7 +155,6 @@ describe('local prediction reconciliation', () => {
});
it('replays the streamed facing direction, not one guessed from the pose', () => {
// Head trails 35 units behind: atan2 gives ~0.57 rad, server direction is 0.
const walkingPose = () => ({
head: { center: [-35, 37], radius: HEAD_RADIUS },
leftFoot: { center: [-33, -18], radius: FEET_RADIUS },

View file

@ -1,4 +1,3 @@
// Round-trip tests for the wire serializer, exercising the BUILT shared bundle.
import { describe, it, expect } from 'vitest';
import { createRequire } from 'node:module';
@ -13,12 +12,10 @@ const {
MoveActionCommand,
UpdatePropertyCommand,
PropertyUpdatesForObject,
// networked entity bases — their toArray() must mirror their constructor order
CharacterBase,
PlanetBase,
ProjectileBase,
LampBase,
// geometry — single source of truth shared by server & client prediction
headRadius,
feetRadius,
boundRadius,
@ -37,7 +34,6 @@ describe('serialization round-trip (built shared lib)', () => {
it('round-trips a Circle and rounds floats to 3 decimals', () => {
const out = deserialize(serialize(new Circle([12.34567, -7.1], 5.43219)));
expect(out).toBeInstanceOf(Circle);
// serialize.ts rounds every float via toFixed(3)
expect(out.center[0]).toBeCloseTo(12.346, 6);
expect(out.center[1]).toBeCloseTo(-7.1, 6);
expect(out.radius).toBeCloseTo(5.432, 6);
@ -64,7 +60,6 @@ describe('serialization round-trip (built shared lib)', () => {
});
it('preserves per-item class identity across a mixed batch', () => {
// A clobbered name→constructor mapping surfaces as the wrong class.
const batch = [
new ServerAnnouncement('a'),
new MoveActionCommand([0, 1], 5),
@ -127,14 +122,25 @@ describe('networked entity round-trips (toArray ↔ constructor contract)', () =
it('round-trips a PlanetBase (derived centre/radius recomputed from vertices)', () => {
const out = deserialize(
serialize(new PlanetBase(10, [[0, 0], [100, 0], [50, 100]], 0.7, true)),
serialize(
new PlanetBase(
10,
[
[0, 0],
[100, 0],
[50, 100],
],
0.7,
true,
),
),
);
expect(out).toBeInstanceOf(PlanetBase);
expect(out.id).toBe(10);
expect(out.vertices).toHaveLength(3);
expect(out.ownership).toBeCloseTo(0.7, 5);
expect(out.isKeystone).toBe(true);
expect(out.center[0]).toBeCloseTo(50, 5); // recomputed by the constructor
expect(out.center[0]).toBeCloseTo(50, 5);
});
});
@ -142,7 +148,7 @@ describe('shared character geometry — single source of truth', () => {
it('matches the known body layout', () => {
expect(headRadius).toBe(50);
expect(feetRadius).toBe(20);
expect(boundRadius).toBe((headRadius + feetRadius * 2) * 2); // 180
expect(boundRadius).toBe((headRadius + feetRadius * 2) * 2);
});
it('posture offsets are measured from the centre of mass (they sum to ~0)', () => {

View file

@ -1,12 +1,4 @@
// Production calls glMatrix.setMatrixArrayType(Array) before anything else
// (backend/src/main.ts, frontend/src/index.ts), which makes every vector an f64
// Array instead of the default Float32Array. Without the same call here the
// suite pins the numerics of a build nobody ships — including module-level
// scratch vectors, which are allocated the moment a module is imported.
//
// One call per installed gl-matrix: the prebuilt shared bundle keeps gl-matrix
// external and resolves shared/node_modules, while the backend and frontend
// sources the tests import directly resolve their own copies.
// Production makes every vector an f64 Array before any module-level vector is allocated.
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);