1
0

California gets roads, traffic, and a car to follow

This commit is contained in:
2026-08-11 18:24:53 -07:00
parent 9c9e78f6f9
commit fe58290728
43 changed files with 5593 additions and 68 deletions
+113
View File
@@ -0,0 +1,113 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import * as THREE from "three";
import {
CROW_METRICS,
DOG_METRICS,
HUMANOID_METRICS,
buildCrow,
buildDog,
buildHumanoid,
cloneCrow,
cloneDog,
cloneHumanoid,
disposeCrow,
disposeDog,
disposeHumanoid,
poseCrowFlight,
poseDogAttention,
poseDogWalk,
poseHumanoid,
} from "../assets/actors/index.ts";
function meshes(root: THREE.Object3D): THREE.Mesh[] {
const result: THREE.Mesh[] = [];
root.traverse((object) => {
if (object instanceof THREE.Mesh) result.push(object);
});
return result;
}
function assertSharedResources(source: THREE.Group, clone: THREE.Group): void {
const a = meshes(source);
const b = meshes(clone);
assert.equal(b.length, a.length);
for (let i = 0; i < a.length; i++) {
assert.equal(b[i]!.geometry, a[i]!.geometry);
assert.equal(b[i]!.material, a[i]!.material);
}
}
describe("procedural actor assets", () => {
it("builds a metre-scale customizable humanoid with a front face surface", () => {
const rig = buildHumanoid({ bodyShape: "broad", outfitColor: 0x224466 });
const box = new THREE.Box3().setFromObject(rig.root);
const size = box.getSize(new THREE.Vector3());
assert.ok(Math.abs(size.y - HUMANOID_METRICS.height) < 0.08, `height ${size.y}`);
assert.ok(box.min.y > -0.015, `floor ${box.min.y}`);
assert.equal(rig.root.userData.forwardAxis, "-Z");
assert.ok(rig.face.getWorldPosition(new THREE.Vector3()).z < 0);
const clone = cloneHumanoid(rig);
assertSharedResources(rig.root, clone.root);
poseHumanoid(clone, { walkPhase: Math.PI / 2, stride: 0.5, headYaw: 0.3 });
assert.notEqual(clone.joints.hipLeft.rotation.x, rig.joints.hipLeft.rotation.x);
assert.equal(clone.joints.head.rotation.y, 0.3);
assert.equal(clone.ownsMaterials, false);
disposeHumanoid(rig);
});
it("builds an anonymous office dog with independent attention and gait joints", () => {
const rig = buildDog();
const box = new THREE.Box3().setFromObject(rig.root);
const size = box.getSize(new THREE.Vector3());
assert.ok(size.y <= DOG_METRICS.height + 0.08, `height ${size.y}`);
assert.ok(size.z >= DOG_METRICS.length - 0.1, `length ${size.z}`);
assert.equal(rig.root.userData.actorType, "anonymous-dog");
const clone = cloneDog(rig);
assertSharedResources(rig.root, clone.root);
poseDogWalk(clone, Math.PI / 2);
poseDogAttention(clone, 0.4, Math.PI / 2);
assert.notEqual(clone.joints.legFrontLeft.rotation.x, rig.joints.legFrontLeft.rotation.x);
assert.equal(clone.joints.head.rotation.y, 0.4);
assert.notEqual(clone.joints.tail.rotation.z, 0);
disposeDog(rig);
});
it("builds a Tera crow with mirrored independent wing joints", () => {
const rig = buildCrow();
const box = new THREE.Box3().setFromObject(rig.root);
assert.ok(box.max.y <= CROW_METRICS.perchedHeight + 0.1, `height ${box.max.y}`);
assert.equal(rig.root.userData.actorType, "anonymous-crow");
const beak = rig.root.getObjectByName("crow.beak");
assert.ok(beak);
assert.ok(beak.getWorldPosition(new THREE.Vector3()).z < 0);
const clone = cloneCrow(rig);
assertSharedResources(rig.root, clone.root);
poseCrowFlight(clone, Math.PI / 2, 1);
assert.equal(clone.joints.wingLeft.rotation.z, -clone.joints.wingRight.rotation.z);
assert.notEqual(clone.joints.wingLeft.rotation.z, rig.joints.wingLeft.rotation.z);
disposeCrow(rig);
});
it("never disposes caller-owned materials unless explicitly requested", () => {
const source = buildCrow();
const shared = meshes(source.root)[0]!.material as THREE.Material;
let disposals = 0;
shared.addEventListener("dispose", () => disposals++);
const external = {
feather: shared,
sheen: shared,
beak: shared,
eye: shared,
foot: shared,
};
const rig = buildCrow({ materials: external });
disposeCrow(rig);
assert.equal(disposals, 0);
disposeCrow(source);
assert.equal(disposals, 1);
});
});
+59
View File
@@ -0,0 +1,59 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { layoutBuildingGlyph } from "../engine/buildingGlyph.ts";
import type { BuildingGlyph } from "../engine/types.ts";
function glyph(overrides: Partial<BuildingGlyph> = {}): BuildingGlyph {
return {
kind: "building",
width: 40,
depth: 30,
height: 100,
storeys: 24,
heading: 0,
profile: "block",
...overrides,
};
}
describe("map building glyph layouts", () => {
it("steps a tower inward without changing its declared height", () => {
const segments = layoutBuildingGlyph(glyph({ profile: "tower" }));
assert.equal(segments.length, 3);
assert.ok(segments[1]!.width < segments[0]!.width);
assert.ok(segments[2]!.width < segments[1]!.width);
assert.equal(Math.max(...segments.map((s) => s.base + s.height)), 100);
});
it("leaves a real hole inside a courtyard ring", () => {
const segments = layoutBuildingGlyph(
glyph({ profile: "courtyard", width: 36, depth: 26, height: 9 }),
);
assert.equal(segments.length, 4);
const north = segments[0]!;
const west = segments[2]!;
const openWidth = 36 - west.width * 2;
const openDepth = 26 - north.depth * 2;
assert.ok(openWidth > 0, `courtyard closes across its width: ${openWidth}`);
assert.ok(openDepth > 0, `courtyard closes across its depth: ${openDepth}`);
});
it("reserves the top of a hangar for its pitched roof", () => {
const [body] = layoutBuildingGlyph(glyph({ profile: "hangar", height: 11 }));
assert.ok(body);
assert.equal(body.base, 0);
assert.equal(body.height, 11 * 0.72);
});
it("keeps undersized authored footprints renderable", () => {
const [segment] = layoutBuildingGlyph(
glyph({ width: 0, depth: -2, height: 0, profile: "block" }),
);
assert.ok(segment);
assert.deepEqual(
{ width: segment.width, depth: segment.depth, height: segment.height },
{ width: 4, depth: 4, height: 3 },
);
});
});
+33
View File
@@ -0,0 +1,33 @@
/** Contract checks for the state-scale rendering adapter. */
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import CALIFORNIA_CITY, { CALIFORNIA_I_5, CALIFORNIA_US_101 } from "../cities/california.ts";
describe("California corridor city", () => {
it("keeps the two transport routes on one coarse render board", () => {
assert.equal(CALIFORNIA_CITY.id, "california");
assert.equal(CALIFORNIA_CITY.roads.length, 2);
assert.ok(CALIFORNIA_US_101.length > 10);
assert.ok(CALIFORNIA_I_5.length > 10);
for (const path of [CALIFORNIA_US_101, CALIFORNIA_I_5]) {
for (const [lat, lng] of path) {
assert.ok(lat >= CALIFORNIA_CITY.bounds.minLat && lat <= CALIFORNIA_CITY.bounds.maxLat);
assert.ok(lng >= CALIFORNIA_CITY.bounds.minLng && lng <= CALIFORNIA_CITY.bounds.maxLng);
}
}
});
it("offers route chapters plus doors into both detailed city boards", () => {
assert.deepEqual(
CALIFORNIA_CITY.chapters.map((chapter) => chapter.id),
["california-overview", "la-sf-us-101", "la-sf-i-5", "los-angeles", "san-francisco"],
);
});
it("uses a state-scale field rather than city-scale cells", () => {
assert.ok(CALIFORNIA_CITY.cellLat >= 0.01);
assert.ok(CALIFORNIA_CITY.cellLng >= 0.01);
assert.equal(CALIFORNIA_CITY.districts.length, 0);
});
});
+139
View File
@@ -0,0 +1,139 @@
/** Contract tests for the authored California transport pack. */
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import CALIFORNIA_TRANSPORT from "../transport/california.ts";
import type { GeographicPoint, TransportRoute } from "../transport/types.ts";
function assertUnique(values: readonly string[], what: string): void {
assert.equal(new Set(values).size, values.length, `${what} must be unique`);
}
function assertPoint(point: GeographicPoint, what: string): void {
assert.ok(Number.isFinite(point.lat), `${what} latitude must be finite`);
assert.ok(Number.isFinite(point.lng), `${what} longitude must be finite`);
assert.ok(point.lat >= -90 && point.lat <= 90, `${what} latitude is outside the globe`);
assert.ok(point.lng >= -180 && point.lng <= 180, `${what} longitude is outside the globe`);
}
function assertProvenance(value: string, what: string): void {
assert.ok(value.trim().length > 20, `${what} needs meaningful provenance`);
}
function routeSegments(route: TransportRoute) {
const byId = new Map(CALIFORNIA_TRANSPORT.segments.map((segment) => [segment.id, segment]));
return route.segmentIds.map((id) => {
const segment = byId.get(id);
assert.ok(segment, `route ${route.id} references missing segment ${id}`);
return segment;
});
}
describe("California transport graph", () => {
it("has stable, unique identifiers and valid references", () => {
assertUnique(
CALIFORNIA_TRANSPORT.nodes.map((node) => node.id),
"node ids",
);
assertUnique(
CALIFORNIA_TRANSPORT.segments.map((segment) => segment.id),
"segment ids",
);
assertUnique(
CALIFORNIA_TRANSPORT.routes.map((route) => route.id),
"route ids",
);
assertUnique(
CALIFORNIA_TRANSPORT.anchors.map((anchor) => anchor.id),
"anchor ids",
);
const nodeIds = new Set(CALIFORNIA_TRANSPORT.nodes.map((node) => node.id));
for (const segment of CALIFORNIA_TRANSPORT.segments) {
assert.ok(nodeIds.has(segment.fromNodeId), `${segment.id} has no start node`);
assert.ok(nodeIds.has(segment.toNodeId), `${segment.id} has no end node`);
}
for (const anchor of CALIFORNIA_TRANSPORT.anchors) {
assert.ok(nodeIds.has(anchor.nodeId), `${anchor.id} has no corridor node`);
}
});
it("keeps every route continuous from its declared start to its declared end", () => {
for (const route of CALIFORNIA_TRANSPORT.routes) {
const segments = routeSegments(route);
assert.ok(segments.length > 0, `${route.id} is empty`);
assert.equal(segments[0]?.fromNodeId, route.fromNodeId);
assert.equal(segments.at(-1)?.toNodeId, route.toNodeId);
for (let index = 1; index < segments.length; index += 1) {
assert.equal(
segments[index - 1]?.toNodeId,
segments[index]?.fromNodeId,
`${route.id} breaks between segments ${index - 1} and ${index}`,
);
}
}
});
it("names I-5's real Bay connectors instead of pretending I-5 reaches San Francisco", () => {
const route = CALIFORNIA_TRANSPORT.routes.find((candidate) => candidate.id === "la-sf-i-5");
assert.ok(route);
const roads = routeSegments(route).map((segment) => segment.roadName);
assert.deepEqual([...new Set(roads)], ["I-5", "I-580", "I-80 / Bay Bridge", "I-80"]);
assert.match(route.label, /I-580/);
assert.match(route.label, /I-80/);
});
it("keeps US-101 on US-101 for the complete authored itinerary", () => {
const route = CALIFORNIA_TRANSPORT.routes.find((candidate) => candidate.id === "la-sf-us-101");
assert.ok(route);
assert.ok(routeSegments(route).every((segment) => segment.roadName === "US-101"));
});
it("contains finite California coordinates and usable simulation envelopes", () => {
for (const node of CALIFORNIA_TRANSPORT.nodes) {
assertPoint(node.position, `node ${node.id}`);
assert.ok(node.position.lat >= 32 && node.position.lat <= 42, `${node.id} is outside California`);
assert.ok(node.position.lng >= -125 && node.position.lng <= -114, `${node.id} is outside California`);
}
for (const anchor of CALIFORNIA_TRANSPORT.anchors) {
assertPoint(anchor.position, `anchor ${anchor.id}`);
}
for (const segment of CALIFORNIA_TRANSPORT.segments) {
assert.ok(segment.speedLimitMph > 0 && segment.speedLimitMph <= 70);
assert.ok(Number.isInteger(segment.lanesPerDirection));
assert.ok(segment.lanesPerDirection >= 1 && segment.lanesPerDirection <= 8);
}
});
it("records provenance on every authored item", () => {
for (const note of CALIFORNIA_TRANSPORT.provenance) assertProvenance(note, "pack");
for (const node of CALIFORNIA_TRANSPORT.nodes) assertProvenance(node.provenance, node.id);
for (const segment of CALIFORNIA_TRANSPORT.segments) {
assertProvenance(segment.provenance, segment.id);
}
for (const route of CALIFORNIA_TRANSPORT.routes) assertProvenance(route.provenance, route.id);
for (const anchor of CALIFORNIA_TRANSPORT.anchors) {
assertProvenance(anchor.provenance, anchor.id);
}
});
it("has scene anchors for both cities and all shipped offices", () => {
const cityIds = CALIFORNIA_TRANSPORT.anchors
.filter((anchor) => anchor.kind === "city")
.map((anchor) => anchor.cityId)
.sort();
const officeIds = CALIFORNIA_TRANSPORT.anchors
.filter((anchor) => anchor.kind === "office")
.map((anchor) => anchor.officeId)
.sort();
assert.deepEqual(cityIds, ["sf", "socal"]);
assert.deepEqual(officeIds, ["frontier-valley", "lumbridge-hq", "mateo-court"]);
});
it("survives a JSON round trip without losing data", () => {
assert.deepEqual(JSON.parse(JSON.stringify(CALIFORNIA_TRANSPORT)), CALIFORNIA_TRANSPORT);
});
});
+28 -8
View File
@@ -444,13 +444,14 @@ describe("the Frontier Valley pack", () => {
});
/**
* Both shipped packs declare where they stand, and the two are deliberately
* All shipped packs declare where they stand, and the three are deliberately
* nothing alike — which is the entire argument for the field existing.
*/
describe("the sites", () => {
it("are both declared", () => {
assert.ok(LUMBRIDGE_HQ.site, "Lumbridge HQ has no site");
assert.ok(FRONTIER_VALLEY.site, "Frontier Valley has no site");
const packs = [LUMBRIDGE_HQ, FRONTIER_VALLEY, MATEO_COURT];
it("are all declared", () => {
for (const pack of packs) assert.ok(pack.site, `${pack.name} has no site`);
});
it("put one high in the air and one on the ground", () => {
@@ -465,15 +466,15 @@ describe("the sites", () => {
});
it("carry headings inside the compass", () => {
for (const pack of [LUMBRIDGE_HQ, FRONTIER_VALLEY, MATEO_COURT]) {
for (const pack of packs) {
const h = pack.site?.heading ?? 0;
assert.ok(h >= 0 && h < 360, `${pack.id} has a heading of ${h}`);
}
});
it("are both on the board the city view draws", () => {
// Not a format requirement — an office may stand anywhere — but both of
// these are meant to be places in *this* product's San Francisco, and a
it("puts the Bay Area offices on the board the city view draws", () => {
// Not a format requirement — an office may stand anywhere — but these two
// are meant to be places in *this* product's San Francisco, and a
// coordinate typo that put one in Nevada would otherwise render fine.
for (const pack of [LUMBRIDGE_HQ, FRONTIER_VALLEY]) {
const site = pack.site;
@@ -482,6 +483,25 @@ describe("the sites", () => {
assert.ok(site.lng > -122.8 && site.lng < -121.8, `${pack.id} longitude ${site.lng}`);
}
});
it("gives every map destination a finite, aligned exterior glyph", () => {
for (const pack of packs) {
const site = pack.site;
assert.ok(site, `${pack.id} has no site`);
const exterior = site.exterior;
assert.ok(exterior, `${pack.id} has no exterior glyph`);
assert.equal(exterior.kind, "building");
assert.equal(exterior.heading, site.heading, `${pack.id} exterior faces away from its plan`);
for (const [field, value] of Object.entries({
width: exterior.width,
depth: exterior.depth,
height: exterior.height,
storeys: exterior.storeys,
})) {
assert.ok(Number.isFinite(value) && value > 0, `${pack.id} has invalid ${field}: ${value}`);
}
}
});
});
/**
+83
View File
@@ -0,0 +1,83 @@
/** Render-layer contract tests that do not require a WebGL context. */
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import * as THREE from "three";
import type { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import CALIFORNIA_TRANSPORT from "../transport/california.ts";
import { createRoadTrafficLayer } from "../engine/roadTraffic.ts";
import type { World } from "../engine/world.ts";
function fixture() {
const world = {
project(lat: number, lng: number): [number, number] {
return [(lng + 121) * 20, -(lat - 36) * 20];
},
groundAt(): number {
return 0;
},
} as unknown as World;
const camera = new THREE.PerspectiveCamera(42, 16 / 9, 0.1, 2_000);
const controls = {
target: new THREE.Vector3(),
enabled: true,
} as unknown as OrbitControls;
const layer = createRoadTrafficLayer(world, camera, controls, {
pack: CALIFORNIA_TRANSPORT,
routeId: "la-sf-us-101",
count: 8,
seed: 115,
});
return { layer, camera, controls };
}
describe("road traffic render layer", () => {
it("draws one articulated hero and instanced background parts", () => {
const { layer } = fixture();
const hero = layer.group.getObjectByName("model-x-hero");
assert.ok(hero);
assert.equal(hero.scale.x, 0.18);
assert.ok(layer.group.children.some((child) => child instanceof THREE.InstancedMesh));
assert.equal(layer.hero()?.routeId, "la-sf-us-101");
assert.ok(Math.abs(hero.position.y - 0.155) < 1e-9);
layer.dispose();
});
it("switches routes and owns the orbit-control handoff while following", () => {
const { layer, camera, controls } = fixture();
layer.setRoute("la-sf-i-5");
assert.equal(layer.routeId(), "la-sf-i-5");
assert.equal(layer.hero()?.routeId, "la-sf-i-5");
layer.setFollowing(true);
assert.equal(layer.following(), true);
assert.equal(controls.enabled, false);
layer.tick(0.1);
assert.ok(camera.position.toArray().every(Number.isFinite));
assert.ok(controls.target.toArray().every(Number.isFinite));
layer.setCameraMode("driver");
assert.equal(layer.cameraMode(), "driver");
layer.tick(1 / 60);
assert.ok(camera.position.y > layer.group.getObjectByName("model-x-hero")!.position.y);
layer.setFollowing(false);
assert.equal(controls.enabled, true);
layer.dispose();
});
it("hands manual input to the deterministic hero and resumes assistance", () => {
const { layer } = fixture();
for (let index = 0; index < 20; index += 1) {
layer.setVehicleActions({ throttle: 1, steering: 0.8 });
layer.tick(1 / 30);
}
assert.equal(layer.hero().mode, "manual");
assert.ok(layer.hero().lateralOffsetM > 0);
layer.setVehicleActions({ modeRequest: "assisted" });
layer.tick(1 / 30);
assert.equal(layer.hero().mode, "assisted");
layer.dispose();
});
});
+80
View File
@@ -0,0 +1,80 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import * as THREE from "three";
import {
MODEL_X_METRICS,
advanceModelXWheels,
buildModelX,
cloneModelX,
disposeModelX,
modelXInstanceParts,
setModelXSteering,
setModelXWheelRotation,
} from "../assets/vehicles/index.ts";
function meshes(root: THREE.Object3D): THREE.Mesh[] {
const found: THREE.Mesh[] = [];
root.traverse((object) => {
if (object instanceof THREE.Mesh) found.push(object);
});
return found;
}
describe("procedural Model X vehicle asset", () => {
it("has a metre-scale crossover silhouette and faces -Z", () => {
const rig = buildModelX({ detail: "corridor" });
const size = new THREE.Box3().setFromObject(rig.root).getSize(new THREE.Vector3());
assert.ok(Math.abs(size.x - MODEL_X_METRICS.width) < 0.12, `width ${size.x}`);
assert.ok(Math.abs(size.y - MODEL_X_METRICS.height) < 0.08, `height ${size.y}`);
assert.ok(Math.abs(size.z - MODEL_X_METRICS.length) < 0.08, `length ${size.z}`);
assert.equal(rig.root.userData.forwardAxis, "-Z");
assert.ok(rig.wheels.frontLeft.steering.position.z < 0);
assert.ok(rig.wheels.rearLeft.steering.position.z > 0);
disposeModelX(rig);
});
it("exposes independent steering and rolling joints", () => {
const rig = buildModelX();
setModelXWheelRotation(rig, 1.25);
for (const wheel of Object.values(rig.wheels)) assert.equal(wheel.spin.rotation.x, 1.25);
setModelXSteering(rig, 99);
assert.equal(rig.wheels.frontLeft.steering.rotation.y, MODEL_X_METRICS.maxSteeringAngle);
assert.equal(rig.wheels.frontRight.steering.rotation.y, MODEL_X_METRICS.maxSteeringAngle);
assert.equal(rig.wheels.rearLeft.steering.rotation.y, 0);
advanceModelXWheels(rig, MODEL_X_METRICS.wheelRadius);
assert.equal(rig.wheels.frontLeft.spin.rotation.x, 0.25);
disposeModelX(rig);
});
it("clones cheaply while keeping its pose independent", () => {
const original = buildModelX();
const clone = cloneModelX(original);
const sourceMeshes = meshes(original.root);
const clonedMeshes = meshes(clone.root);
assert.equal(clonedMeshes.length, sourceMeshes.length);
for (let i = 0; i < sourceMeshes.length; i++) {
assert.equal(clonedMeshes[i]!.geometry, sourceMeshes[i]!.geometry);
assert.equal(clonedMeshes[i]!.material, sourceMeshes[i]!.material);
}
setModelXSteering(clone, -0.3);
assert.equal(clone.wheels.frontLeft.steering.rotation.y, -0.3);
assert.equal(original.wheels.frontLeft.steering.rotation.y, 0);
assert.equal(clone.ownsMaterials, false);
disposeModelX(original);
});
it("publishes stable neutral-pose pieces for instanced traffic", () => {
const rig = buildModelX({ detail: "corridor" });
const parts = modelXInstanceParts(rig);
assert.equal(parts.length, meshes(rig.root).length);
assert.ok(parts.some((part) => part.name === "frontLeft.tire"));
assert.ok(parts.some((part) => part.name.startsWith("model-x.body:")));
assert.ok(parts.every((part) => Number.isFinite(part.matrix.determinant())));
disposeModelX(rig);
});
});
+183
View File
@@ -0,0 +1,183 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import CALIFORNIA_TRANSPORT from "../transport/california.ts";
import {
VehicleController,
normalizeVehicleActions,
replayVehicleInputs,
} from "../transport/vehicleController.ts";
describe("vehicle controller", () => {
it("normalizes arbitrary adapter input into safe device-neutral actions", () => {
assert.deepEqual(
normalizeVehicleActions({
throttle: 4,
brake: Number.NaN,
steering: -3,
handbrake: true,
modeRequest: "manual",
reset: true,
}),
{
throttle: 1,
brake: 0,
steering: -1,
handbrake: true,
modeRequest: "manual",
reset: true,
},
);
assert.deepEqual(normalizeVehicleActions(undefined), {
throttle: 0,
brake: 0,
steering: 0,
handbrake: false,
modeRequest: "none",
reset: false,
});
});
it("advances assisted driving on a deterministic fixed clock", () => {
const a = new VehicleController(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
initialDistanceM: 1_000,
});
const b = new VehicleController(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
initialDistanceM: 1_000,
});
for (let index = 0; index < 240; index += 1) {
a.stepFixed();
b.stepFixed();
}
assert.deepEqual(a.snapshot(), b.snapshot());
assert.equal(a.state().mode, "assisted");
assert.ok(a.state().distanceM > 1_000);
assert.ok(a.state().speedMps > 0);
assert.ok(Number.isFinite(a.state().lat));
assert.ok(Number.isFinite(a.state().lng));
});
it("gives manual input priority and cleanly resumes assistance", () => {
const controller = new VehicleController(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-i-5",
initialSpeedMps: 25,
});
for (let index = 0; index < 90; index += 1) {
controller.stepFixed({ throttle: 0.7, steering: 0.8 });
}
assert.equal(controller.state().mode, "manual");
assert.ok(controller.state().lateralOffsetM > 0.5);
controller.stepFixed({ modeRequest: "assisted", steering: 0.9 });
assert.equal(controller.state().mode, "manual", "simultaneous human input must win");
const takeoverOffset = controller.state().lateralOffsetM;
controller.stepFixed({ modeRequest: "assisted" });
assert.equal(controller.state().mode, "assisted");
assert.ok(
Math.abs(controller.state().lateralOffsetM - takeoverOffset) < 0.25,
"assistance must not teleport the car to centre",
);
for (let index = 0; index < 300; index += 1) controller.stepFixed();
assert.ok(Math.abs(controller.state().lateralOffsetM) < Math.abs(takeoverOffset));
});
it("enforces speed and road-edge guardrails and exposes contact", () => {
const controller = new VehicleController(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
mode: "manual",
initialSpeedMps: 200,
initialLateralOffsetM: 100,
maximumSpeedMps: 30,
guardrailOffsetM: 4,
});
assert.equal(controller.state().speedMps, 30);
assert.equal(controller.state().lateralOffsetM, 4);
for (let index = 0; index < 120; index += 1) {
controller.stepFixed({ throttle: 1, steering: 1 });
}
assert.ok(controller.state().lateralOffsetM <= 4);
assert.ok(controller.state().speedMps <= 30);
assert.equal(controller.state().guardrailContact, true);
});
it("resets exactly to its configured spawn state", () => {
const controller = new VehicleController(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-i-5",
mode: "manual",
initialDistanceM: 12_345,
initialLateralOffsetM: -1.25,
initialSpeedMps: 8,
});
const spawn = controller.snapshot();
for (let index = 0; index < 100; index += 1) {
controller.stepFixed({ throttle: 1, steering: 0.5 });
}
controller.stepFixed({ reset: true });
assert.deepEqual(controller.snapshot(), spawn);
});
it("caps sleeping-tab catch-up and ignores invalid render deltas", () => {
const controller = new VehicleController(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
});
assert.equal(controller.tick(Number.NaN), 0);
assert.equal(controller.tick(-1), 0);
const steps = controller.tick(600);
assert.ok(steps <= 15);
assert.equal(controller.state().elapsedSteps, steps);
});
it("replays timed input frames bit-for-bit", () => {
const options = {
routeId: "la-sf-i-5",
initialSpeedMps: 15,
fixedStepSeconds: 1 / 30,
} as const;
const frames = [
{ steps: 40, actions: { throttle: 0.8, steering: -0.3 } },
{ steps: 1, actions: { modeRequest: "assisted" as const } },
{ steps: 80 },
{ steps: 20, actions: { brake: 0.7 } },
];
const first = replayVehicleInputs(CALIFORNIA_TRANSPORT, options, frames);
const second = replayVehicleInputs(CALIFORNIA_TRANSPORT, options, frames);
assert.deepEqual(first, second);
assert.equal(first.trajectory.length, 142);
assert.equal(first.final.elapsedSteps, 141);
assert.equal(first.final.mode, "manual");
});
it("can switch route variants while preserving normalized progress", () => {
const controller = new VehicleController(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
initialDistanceM: 220_000,
});
const progress = controller.state().progress;
controller.setRoute("la-sf-i-5", true);
assert.equal(controller.routeId(), "la-sf-i-5");
assert.ok(Math.abs(controller.state().progress - progress) < 1e-12);
assert.equal(controller.state().elapsedSteps, 0);
});
it("compresses corridor progress without changing vehicle dynamics", () => {
const normal = new VehicleController(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
initialSpeedMps: 20,
mode: "manual",
});
const compressed = new VehicleController(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
initialSpeedMps: 20,
mode: "manual",
travelScale: 900,
});
normal.stepFixed();
compressed.stepFixed();
assert.equal(compressed.state().speedMps, normal.state().speedMps);
assert.equal(compressed.state().steering, normal.state().steering);
assert.ok(compressed.state().distanceM > normal.state().distanceM * 800);
assert.equal(compressed.state().wheelRadians, normal.state().wheelRadians);
});
});
+48
View File
@@ -0,0 +1,48 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { mergeVehicleActions, sampleStandardGamepad } from "../input/vehicle.ts";
function pad(over: { axes?: number[]; buttons?: Record<number, number> } = {}) {
const buttons = Array.from({ length: 8 }, (_, index) => ({
pressed: (over.buttons?.[index] ?? 0) > 0.5,
value: over.buttons?.[index] ?? 0,
}));
return { axes: over.axes ?? [0, 0, 0, 0], buttons };
}
describe("vehicle input adapters", () => {
it("maps a standard gamepad with a steering deadzone and analogue triggers", () => {
const sample = sampleStandardGamepad(pad({ axes: [0.5], buttons: { 6: 0.2, 7: 0.75, 1: 1 } }));
assert.ok(sample.actions.steering > 0 && sample.actions.steering < 0.5);
assert.equal(sample.actions.brake, 0.2);
assert.equal(sample.actions.throttle, 0.75);
assert.equal(sample.actions.handbrake, true);
assert.equal(sampleStandardGamepad(pad({ axes: [0.05] })).actions.steering, 0);
});
it("publishes assisted/reset buttons only on their rising edge", () => {
const first = sampleStandardGamepad(pad({ buttons: { 2: 1, 3: 1 } }));
assert.equal(first.actions.modeRequest, "assisted");
assert.equal(first.actions.reset, true);
const held = sampleStandardGamepad(pad({ buttons: { 2: 1, 3: 1 } }), first.buttons);
assert.equal(held.actions.modeRequest, "none");
assert.equal(held.actions.reset, false);
});
it("merges simultaneous adapters by strongest analogue and any safety input", () => {
assert.deepEqual(
mergeVehicleActions(
{ throttle: 1, steering: -0.4 },
{ brake: 0.7, steering: 0.8, handbrake: true },
),
{
throttle: 1,
brake: 0.7,
steering: 0.8,
handbrake: true,
modeRequest: "none",
reset: false,
},
);
});
});
+102
View File
@@ -0,0 +1,102 @@
/** Determinism and lifecycle tests for statewide road traffic. */
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import CALIFORNIA_TRANSPORT from "../transport/california.ts";
import {
VehicleSimulation,
buildRoutePath,
distanceMetres,
sampleRoute,
} from "../transport/vehicleSim.ts";
describe("vehicle simulation", () => {
it("builds both complete routes and samples their declared endpoints", () => {
for (const id of ["la-sf-us-101", "la-sf-i-5"]) {
const path = buildRoutePath(CALIFORNIA_TRANSPORT, id);
assert.ok(path.lengthM > 500_000);
const start = sampleRoute(path, 0);
const finish = sampleRoute(path, path.lengthM - 0.01);
assert.ok(distanceMetres(start, { lat: 34.0522, lng: -118.2437 }) < 10);
assert.ok(distanceMetres(finish, { lat: 37.7749, lng: -122.4194 }) < 20);
}
});
it("is deterministic for the same seed, route, and frame sequence", () => {
const a = new VehicleSimulation(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
count: 8,
seed: 42,
});
const b = new VehicleSimulation(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
count: 8,
seed: 42,
});
for (const dt of [0.016, 0.033, 0.2, 0.041, 0.08]) {
a.tick(dt);
b.tick(dt);
}
assert.deepEqual(a.poses(), b.poses());
});
it("caps a background-tab delta and keeps every pose finite", () => {
const sim = new VehicleSimulation(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-i-5",
count: 16,
});
const path = buildRoutePath(CALIFORNIA_TRANSPORT, "la-sf-i-5");
const before = sim.poses()[0]?.distanceM ?? 0;
sim.tick(600);
const after = sim.poses()[0]?.distanceM ?? 0;
const direct = Math.abs(after - before);
const travelled = Math.min(direct, path.lengthM - direct);
assert.ok(travelled < 20_000, "a sleeping tab must not replay ten minutes");
for (const pose of sim.poses()) {
assert.ok(Number.isFinite(pose.lat));
assert.ok(Number.isFinite(pose.lng));
assert.ok(Number.isFinite(pose.headingDeg));
assert.ok(pose.progress >= 0 && pose.progress < 1);
}
});
it("changes route as one deterministic state transition", () => {
const sim = new VehicleSimulation(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
count: 4,
seed: 7,
});
sim.setRoute("la-sf-i-5");
assert.equal(sim.routeId(), "la-sf-i-5");
assert.ok(sim.poses().every((pose) => pose.routeId === "la-sf-i-5"));
assert.equal(sim.poses()[0]?.id, "model-x-hero");
});
it("moves reverse traffic south while keeping its heading finite", () => {
const sim = new VehicleSimulation(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
count: 4,
seed: 115,
timeScale: 1,
});
const southbound = sim.poses().find((pose) => pose.direction === -1);
assert.equal(southbound?.direction, -1);
const before = southbound?.distanceM ?? 0;
const beforeLat = southbound?.lat ?? 0;
sim.tick(0.1);
assert.ok((southbound?.distanceM ?? before) < before);
assert.ok((southbound?.lat ?? beforeLat) < beforeLat);
assert.ok(Number.isFinite(southbound?.headingDeg));
});
it("returns one stable pose view for allocation-free render polling", () => {
const sim = new VehicleSimulation(CALIFORNIA_TRANSPORT, {
routeId: "la-sf-us-101",
count: 4,
});
const poses = sim.poses();
sim.tick(0.1);
assert.equal(sim.poses(), poses);
assert.equal(sim.poses()[0], poses[0]);
});
});
+131
View File
@@ -0,0 +1,131 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { Plan } from "../interiors/plan.ts";
import {
createWalker,
normalizeWalkerAction,
type WalkerOptions,
} from "../interiors/walker.ts";
import type { Level, Office, Room, Wall } from "../interiors/types.ts";
const ROOM: Room = {
id: "floor",
name: "Floor",
floor: "floor" as never,
outline: [
{ x: 0, z: 0 },
{ x: 10, z: 0 },
{ x: 10, z: 8 },
{ x: 0, z: 8 },
],
};
function planWith(walls: Wall[] = []): Plan {
const level: Level = {
id: "ground",
name: "Ground",
elevation: 0,
wallHeight: 3,
wallThickness: 0.1,
floorplan: { rooms: [ROOM], walls },
};
const office: Office = { id: "walk-test", name: "Walk Test", levels: [level], viewpoints: [] };
return new Plan(office, { warn: false });
}
function walker(plan: Plan, over: Partial<WalkerOptions> = {}) {
return createWalker(plan, {
levelId: "ground",
position: { x: 2, z: 2 },
speed: 1,
fixedStep: 0.1,
...over,
});
}
describe("walker input and clock", () => {
it("normalizes planar actions without amplifying smaller input", () => {
assert.deepEqual(normalizeWalkerAction({ x: 0.3, z: -0.4 }), { x: 0.3, z: -0.4 });
const diagonal = normalizeWalkerAction({ x: 1, z: 1 });
assert.ok(Math.abs(Math.hypot(diagonal.x, diagonal.z) - 1) < 1e-12);
assert.deepEqual(normalizeWalkerAction({ x: Number.NaN, z: 1 }), { x: 0, z: 0 });
});
it("moves only in fixed steps and is deterministic across frame chunking", () => {
const plan = planWith();
const one = walker(plan);
const many = walker(plan);
one.tick(0.05, { x: 1, z: 0 });
assert.deepEqual(one.state().position, { x: 2, z: 2 });
one.tick(0.35, { x: 1, z: 0 });
for (let index = 0; index < 4; index += 1) many.tick(0.1, { x: 1, z: 0 });
assert.deepEqual(one.state(), many.state());
assert.ok(Math.abs(one.state().distance - 0.4) < 1e-12);
});
it("returns defensive state snapshots", () => {
const controller = walker(planWith());
const leaked = controller.state();
leaked.position.x = Number.NaN;
assert.deepEqual(controller.state().position, { x: 2, z: 2 });
});
});
describe("walker collision", () => {
it("sweeps its circular footprint and cannot tunnel through a wall", () => {
const plan = planWith([{ id: "divider", from: { x: 5, z: 0 }, to: { x: 5, z: 8 } }]);
const controller = walker(plan, { speed: 100, fixedStep: 0.1 });
const state = controller.tick(0.1, { x: 1, z: 0 });
assert.ok(state.position.x < 4.65 && state.position.x > 4.64, `${state.position.x}`);
assert.equal(plan.blocked("ground", state.position, state.position, 0.3), false);
});
it("slides the unblocked component of diagonal movement along a wall", () => {
const plan = planWith([{ id: "divider", from: { x: 5, z: 0 }, to: { x: 5, z: 8 } }]);
const controller = walker(plan, { position: { x: 4.6, z: 2 }, speed: 2 });
for (let index = 0; index < 10; index += 1) controller.tick(0.1, { x: 1, z: 1 });
const state = controller.state();
assert.ok(state.position.x < 4.65, `${state.position.x}`);
assert.ok(state.position.z > 3, `${state.position.z}`);
assert.equal(plan.blocked("ground", state.position, state.position, 0.3), false);
});
it("walks through a resolved door gap without a door-specific exception", () => {
const plan = planWith([
{
id: "divider",
from: { x: 5, z: 0 },
to: { x: 5, z: 8 },
openings: [{ kind: "door", start: 3.4, width: 1.2, sill: 0, head: 2.1 }],
},
]);
const controller = walker(plan, { position: { x: 4, z: 4 }, speed: 2 });
for (let index = 0; index < 10; index += 1) controller.tick(0.1, { x: 1, z: 0 });
assert.ok(controller.state().position.x > 5.5, `${controller.state().position.x}`);
});
});
describe("walker guardrails", () => {
it("stays within finite level bounds and ignores invalid time/input", () => {
const controller = walker(planWith(), { position: { x: 9.6, z: 4 }, speed: 10 });
controller.tick(Number.NaN, { x: 1, z: 0 });
controller.tick(1, { x: Number.POSITIVE_INFINITY, z: 0 });
assert.deepEqual(controller.state().position, { x: 9.6, z: 4 });
controller.tick(1, { x: 1, z: 0 });
const state = controller.state();
assert.equal(state.position.x, 9.7);
assert.ok(Number.isFinite(state.position.x) && Number.isFinite(state.distance));
});
it("resets atomically and rejects invalid spawns/configuration", () => {
const plan = planWith();
const controller = walker(plan);
controller.tick(0.2, { x: 1, z: 0 });
assert.deepEqual(controller.reset({ levelId: "ground", position: { x: 7, z: 6 } }).position, { x: 7, z: 6 });
assert.equal(controller.state().distance, 0);
assert.throws(() => controller.reset({ levelId: "ground", position: { x: Number.NaN, z: 1 } }), RangeError);
assert.deepEqual(controller.state().position, { x: 7, z: 6 });
assert.throws(() => walker(plan, { radius: 0 }), RangeError);
assert.throws(() => walker(plan, { position: { x: 11, z: 2 } }), RangeError);
});
});