1
0

feat: tone-mapped render rig, studio devices, LA fidelity pass, UI overhaul

The build the studios needed, across eight workstreams and one strict file
partition.

**The render rig was the quality ceiling.** The renderer ran three's
NoToneMapping default while atmosphere drove the sun to 2.35 and assets set
emissives to 3.2, so every value above 1.0 hard-clipped to flat white — which is
why walls blew out and every fitting looked like a white rectangle. ACES filmic
tone mapping and an explicit output colour space land in `stage.ts`, and the
atmosphere intensity table and palette headroom are re-tuned against the new
curve rather than left tuned for the clipping we removed.

`engine/environmentRig.ts` builds a PMREM environment at runtime, procedurally,
so nothing binary is committed. There was no environment map anywhere before, so
every `metalness > 0` role had nothing to reflect and rendered dull grey — a
defect the code already documented against itself in `office/optimus.ts`, where a
whole material role was abandoned over it, and worked around in `modelX.ts` with
a fake emissive that this change deletes. Atmosphere remains the sole light
owner; the rig derives from the `LightingState` it already produced.

**Studio hardware exists.** There was no device concept anywhere in the product:
no type, no route, no state. `devices/types.ts` fixes a declaration/state/
capability/command contract that a smart light, a thermostat, a door sensor and a
charger all fit without a schema change, and both studios now carry a desk mic
and a computer speaker with deterministic simulated behaviour behind an adapter
seam a real API can occupy later. Reads are the demo and are open; commands are a
signed-in action and are kept off the read body entirely, because a shared cache
replaying a GET that turned a microphone on is exactly what the fail-closed
cache default exists to prevent.

**The ADS-B licence hole is closed.** `TERA_ADSB_ENDPOINT` accepted any URL, the
response was served publicly cacheable, and the attribution hardcoded adsb.lol
regardless of where the endpoint pointed — one env var away from republishing
non-redistributable data under an open-terms credit. The host is now allowlisted,
the credit is derived from the host actually configured, public cacheability is
conditional on redistributability, and a refused endpoint demotes to simulated
flights and says so in `degraded[]`. The gate is on the source, not the feature:
live aircraft and their detail cards stay open to anonymous visitors.

**The LA studio was never the smaller pack** — 16 rooms and 248 props against
SF's 4 and 28. Its deficit was fidelity per square metre: 98 of those props were
ceiling troffers, it bound no props to seats, placed none of the habitat kit, and
12 of its 16 rooms had no viewpoint. Density comes from new asset kinds rather
than more instances, because `furnish.ts` draws once per kind and folds colour
into the batch key, so repeat instances add nothing the eye can read.

**The interface stops being forty imperative mutations.** Every visibility
decision moves into a pure, tested `ui/chromeState.ts` and one applier, so the
chrome has coverage for the first time. Deleted: ~100 lines of CSS and two
bindings targeting elements that no longer exist, and a `body:has()` rule that
shifted the desktop layout by 160px for touch controls hidden there. Fixed: the
office picker tabs that drew their label and their badge on top of each other.
Added: a first-run flow, because the product is two verbs and neither was ever
stated on screen. Mobile is designed on its own terms instead of being the
desktop with things hidden — the plan view comes back, and the keyboard-only
shortcuts button is replaced by touch controls.

`arena/studioOps.ts` frames the whole thing as the multi-variable environment it
is, wrapping the same simulators the renderer drives rather than a headless copy.

Also removed `input/vehicle.ts`, which nothing but its own test imported.

Tests 385 -> 961, all passing. Typecheck, build, performance budgets across six
matrix cells, no-binaries, provenance, dependency licences, zero-config boot and
arena source hashes all green.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-21 19:44:24 -07:00
parent 8738367258
commit db074e9cf7
150 changed files with 36237 additions and 2586 deletions
+5
View File
@@ -0,0 +1,5 @@
# Test home for the `packs` workstream.
#
# Each build workstream owns its own subdirectory so eight builders can add
# suites in parallel without ever colliding on a path. `npm test` picks these
# up through the widened `src/test/**/*.test.ts` glob in package.json.
+131
View File
@@ -0,0 +1,131 @@
/**
* The exterior arrival anchor: one marked stall on the ground outside each
* shipped building.
*
* `src/engine/officeExterior.ts` builds an apron and a vehicle there, and it
* needs a number no other field in the format can give it. `site.lat`/`lng` says
* where the building is on the earth and nothing about which corner of the lot
* you park on; `Plan.bounds` is the extent of what was authored and its edge is
* a wall, not a kerb. So the stall is authored — and the one thing an authored
* stall can get catastrophically wrong is being **inside the building**, which
* renders as a car in the lobby and looks entirely plausible in the source.
*
* That check is deliberately here and not in `Plan`. A pack may legitimately
* mean a covered undercroft or a courtyard, and the resolver has no business
* ruling on architecture; these three packs mean the street, the podium kerb and
* the apron, and this is where that is stated.
*/
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { Plan } from "../../interiors/plan.ts";
import type { Office } from "../../interiors/types.ts";
import LUMBRIDGE_HQ from "../../offices/lumbridge-hq.ts";
import FRONTIER_VALLEY from "../../offices/frontier-valley.ts";
import MATEO_COURT from "../../offices/mateo-court.ts";
const PACKS: readonly Office[] = [LUMBRIDGE_HQ, FRONTIER_VALLEY, MATEO_COURT];
describe("every shipped pack parks a vehicle outside itself", () => {
for (const pack of PACKS) {
const arrival = pack.site?.arrival;
it(`${pack.id} declares a vehicle stall on a level that exists`, () => {
assert.ok(pack.site, `${pack.id} has no site`);
assert.ok(arrival, `${pack.id} has no arrival anchor`);
assert.equal(arrival.kind, "vehicle-stall");
assert.ok(Number.isFinite(arrival.rotation), `${pack.id} stall has no rotation`);
assert.ok(Number.isFinite(arrival.position.x) && Number.isFinite(arrival.position.z));
assert.ok(
pack.levels.some((level) => level.id === arrival.levelId),
`${pack.id} stall stands on unknown level "${arrival?.levelId}"`,
);
});
it(`${pack.id} stands its stall outside every room, on every level`, () => {
assert.ok(arrival);
const plan = new Plan(pack, { warn: false });
// The named level is what the criterion is about; the others are checked
// too because a stall under an upper storey is still under a building.
for (const level of plan.levels) {
const room = plan.roomAt(level.id, arrival.position);
assert.equal(
room,
null,
`${pack.id} parks in ${room?.name} on ${level.id}`,
);
}
});
/**
* Stronger than "not in a room", and true of all three by intent rather than
* by rule: none of them parks in its own courtyard or under its own upper
* floor. `Plan.bounds` is the union of every level's walls, props and slabs,
* so a stall outside it is a stall outside the building.
*/
it(`${pack.id} stands its stall clear of the whole footprint`, () => {
assert.ok(arrival);
const bounds = new Plan(pack, { warn: false }).bounds;
const { x, z } = arrival.position;
const outside =
x < bounds.minX || x > bounds.maxX || z < bounds.minZ || z > bounds.maxZ;
assert.ok(
outside,
`${pack.id} stall at (${x}, ${z}) is inside the footprint ` +
`x ${bounds.minX}..${bounds.maxX}, z ${bounds.minZ}..${bounds.maxZ}`,
);
});
it(`${pack.id} hands the very anchor it authored to Plan`, () => {
// Identity, not equality — the same argument `office.test.ts` makes about
// sites. A copy means somebody restated a coordinate on the way through.
assert.equal(new Plan(pack, { warn: false }).exteriorArrival, arrival);
});
}
});
describe("Plan drops an arrival it cannot use", () => {
function withArrival(levelId: string, kind: string): Office {
return {
...MATEO_COURT,
site: {
...MATEO_COURT.site!,
arrival: {
levelId,
position: { x: 22.6, z: -3.4 },
rotation: 0,
kind: kind as "vehicle-stall",
},
},
};
}
it("reports an unknown level and resolves to nothing", () => {
const plan = new Plan(withArrival("level-9", "vehicle-stall"), { warn: false });
assert.equal(plan.exteriorArrival, null);
assert.deepEqual(
plan.problems.map((problem) => `${problem.where}: ${problem.action}`),
["site.arrival: dropped"],
);
});
it("reports a kind this build does not know", () => {
const plan = new Plan(withArrival("level-1", "helipad"), { warn: false });
assert.equal(plan.exteriorArrival, null);
assert.match(plan.problems[0]?.message ?? "", /unknown kind "helipad"/);
});
/**
* And a pack with no stall at all is not a pack with a problem. Every field
* added to this format has to leave the packs written before it existed
* resolving exactly as they did, which for an office with no vehicle outside
* it means `null` and silence.
*/
it("says nothing about a pack that authored no stall", () => {
const site = { ...MATEO_COURT.site! };
delete site.arrival;
const plan = new Plan({ ...MATEO_COURT, site }, { warn: false });
assert.equal(plan.exteriorArrival, null);
assert.deepEqual(plan.problems, []);
});
});
+375
View File
@@ -0,0 +1,375 @@
/**
* The authored device layer, in the two studios and in `Plan`.
*
* A `DeviceDeclaration` is the first authored thing in this format that points
* at another authored thing *and carries no coordinate of its own*. `Prop.seat`
* is an address and nothing renders from it; a device's anchor is an address the
* renderer takes a transform from, so a broken anchor is not a dangling label —
* it is a microphone that is nowhere, or worse, a microphone somewhere it never
* was.
*
* Two properties are worth the file on their own:
*
* - **The anchor prop is the hardware.** Every declaration names a prop that
* exists on the level it claims, and that prop's asset id agrees with the
* device's kind. `deviceKindOfAssetId` reads the kind out of
* `<ns>:device.<kind>.<placement>`, so the check needs no asset registry and
* works for a self-hoster's `acme:device.mic.boom` for free.
* - **A bad device costs one device.** `Plan` drops it and records a problem.
* It must never throw, because a pack is 250 props and one typo should not
* cost a visitor the building — the same argument `plan.ts` makes about wall
* openings, and the reason `validateDeviceDeclaration` returns sentences
* instead of raising.
*/
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
CANONICAL_CAPABILITIES,
deviceKindOfAssetId,
validateDeviceDeclaration,
type DeviceDeclaration,
type DeviceKind,
} from "../../devices/types.ts";
import { Plan } from "../../interiors/plan.ts";
import type { Office, Prop } from "../../interiors/types.ts";
import LUMBRIDGE_HQ from "../../offices/lumbridge-hq.ts";
import MATEO_COURT from "../../offices/mateo-court.ts";
/** The two studios. The hangar is in development and declares no hardware. */
const STUDIOS: readonly Office[] = [LUMBRIDGE_HQ, MATEO_COURT];
function declarationsOf(pack: Office): DeviceDeclaration[] {
return pack.levels.flatMap((level) => [...(level.floorplan.devices ?? [])]);
}
function propsOfLevel(pack: Office, levelId: string): Prop[] {
const level = pack.levels.find((entry) => entry.id === levelId);
return [...(level?.floorplan.props ?? [])];
}
describe("both studios declare the hardware the product promises", () => {
for (const pack of STUDIOS) {
const declarations = declarationsOf(pack);
it(`${pack.id} has at least one mic and at least one speaker`, () => {
const kinds = declarations.map((device) => device.kind);
for (const kind of ["mic", "speaker"] as DeviceKind[]) {
assert.ok(kinds.includes(kind), `${pack.id} declares no ${kind}`);
}
});
it(`${pack.id} anchors every device to real hardware on the level it names`, () => {
assert.ok(declarations.length > 0, `${pack.id} declares no devices at all`);
for (const device of declarations) {
const prop = propsOfLevel(pack, device.anchor.levelId).find(
(entry) => entry.id === device.anchor.propId,
);
assert.ok(
prop,
`${device.id} is anchored to "${device.anchor.propId}", which is not a prop on ` +
`${device.anchor.levelId}`,
);
// The prop must be the hardware, not merely near it: a mic declaration
// pointing at a desk would render nothing and command something.
assert.equal(
deviceKindOfAssetId(prop.kind),
device.kind,
`${device.id} is a ${device.kind} standing on ${prop.kind}`,
);
assert.equal(deviceKindOfAssetId(device.assetId), device.kind);
}
});
it(`${pack.id} says its readings are simulated, in words`, () => {
for (const device of declarations) {
// The library check — provenance, disclosure wording, capability
// vocabulary — restated here against the shipped packs rather than
// against a fixture, because it is the shipped packs that get edited.
assert.deepEqual(validateDeviceDeclaration(device), [], device.id);
assert.equal(device.provenance, "simulated");
assert.match(device.disclosure, /simulat/i);
}
});
it(`${pack.id} describes each instrument with the canonical capabilities`, () => {
// Not style: the panel builds its controls by walking this array and the
// arena's observation width is the sum of them, so two studios authored
// months apart disagreeing about what a mic can do changes the shape of an
// RL observation without anybody editing the arena.
for (const device of declarations) {
assert.deepEqual(
[...device.capabilities],
[...CANONICAL_CAPABILITIES[device.kind]],
device.id,
);
}
});
it(`${pack.id} keeps device ids unique across the building`, () => {
const ids = declarations.map((device) => device.id);
assert.equal(new Set(ids).size, ids.length);
});
}
});
describe("Plan resolves a device onto its anchor prop", () => {
it("gives every declaration a position derived from the hardware", () => {
for (const pack of STUDIOS) {
const plan = new Plan(pack, { warn: false });
const declarations = declarationsOf(pack);
assert.equal(plan.allDevices().length, declarations.length, pack.id);
for (const device of declarations) {
const resolved = plan.device(device.id);
assert.ok(resolved, `${device.id} did not resolve`);
const prop = plan.prop(device.anchor.propId);
assert.ok(prop);
// No offset is authored in either studio, so the device stands exactly
// where its hardware does — including the 0.73 m desktop the prop's own
// `elevation` put it on. Nothing restates that height.
assert.deepEqual(resolved.position, {
x: prop.position.x,
y: prop.position.y,
z: prop.position.z,
});
assert.equal(resolved.rotation, prop.rotation);
assert.equal(resolved.propId, prop.id);
}
}
});
/**
* The LA studio binds each unit to the standing or sitting address it serves,
* which is what lets a consumer ask whether anybody is where the mic is
* pointed. An unknown seat would be repaired away silently, so this asserts
* the bindings survived rather than that the field is spelled right.
*/
it("keeps the LA studio's seat and room addresses", () => {
const plan = new Plan(MATEO_COURT, { warn: false });
assert.deepEqual(
plan.allDevices().map((device) => `${device.id}@${device.roomId}/${device.seatId}`),
[
"la-front-mic@lobby/front-01",
"la-front-speaker@lobby/front-01",
"la-studio-mic@press/media-01",
"la-studio-speaker@press/media-02",
],
);
});
/**
* The offset is in the **prop's** frame, and that is the whole reason it
* exists: turn the desk and the mic stays on the corner of it. A fixture
* rather than a shipped pack, because neither studio needs an offset and a
* test that only exercises the zero case does not test the rotation at all.
*/
it("rotates an authored offset into the prop's frame", () => {
const plan = new Plan(offsetFixture(), { warn: false });
assert.deepEqual(plan.problems, []);
const device = plan.device("fixture-mic");
assert.ok(device);
// The desk is at (4, 0, 6) turned a quarter turn clockwise about +Y, so the
// prop's local +X points along world +Z. An offset of 0.5 along local +X
// therefore lands 0.5 further down the page, not 0.5 to the right.
assert.equal(round(device.position.x), 4);
assert.equal(round(device.position.y), 0.73);
assert.equal(round(device.position.z), 6.5);
});
});
describe("a broken device costs one device", () => {
const CASES: readonly [string, (device: DeviceDeclaration) => DeviceDeclaration, RegExp][] = [
[
"an anchor naming a prop that does not exist",
(device) => ({ ...device, anchor: { ...device.anchor, propId: "no-such-prop" } }),
/anchored to unknown prop/,
],
[
"an anchor on a level the declaration was not written on",
(device) => ({ ...device, anchor: { ...device.anchor, levelId: "level-9" } }),
/declared on level/,
],
[
"hardware of the wrong kind",
(device) => ({ ...device, kind: "speaker", assetId: "tera:device.speaker.desk" }),
/is a speaker anchored to tera:device\.mic\.desk/,
],
[
"a disclosure that does not say the readings are simulated",
(device) => ({ ...device, disclosure: "Live studio hardware." }),
/does not say so/,
],
];
for (const [what, mutate, message] of CASES) {
it(`drops a device with ${what}, and never throws`, () => {
const office = offsetFixture();
const level = office.levels[0];
assert.ok(level);
const original = level.floorplan.devices?.[0];
assert.ok(original);
level.floorplan.devices = [mutate(original)];
const plan = new Plan(office, { warn: false });
assert.equal(plan.allDevices().length, 0);
assert.equal(plan.levels[0]?.devices.length, 0);
assert.equal(plan.problems.length, 1);
assert.equal(plan.problems[0]?.action, "dropped");
assert.match(plan.problems[0]?.message ?? "", message);
// And the building is still a building: the drop costs the device and
// nothing else, which is the property that makes authored furniture safe.
assert.equal(plan.levels[0]?.props.length, 1);
assert.equal(plan.levels[0]?.rooms.length, 1);
});
}
it("clears an unknown seat rather than dropping the device", () => {
const office = offsetFixture();
const level = office.levels[0];
assert.ok(level);
const original = level.floorplan.devices?.[0];
assert.ok(original);
level.floorplan.devices = [
{ ...original, anchor: { ...original.anchor, seatId: "nobody-sits-here" } },
];
const plan = new Plan(office, { warn: false });
assert.equal(plan.problems.length, 1);
assert.equal(plan.problems[0]?.action, "repaired");
assert.equal(plan.device("fixture-mic")?.seatId, undefined);
});
});
/**
* A public build takes the device away with the furniture, and says nothing.
*
* This is the one case where a device that does not resolve is **not** a
* problem, and telling the two apart is the whole of the distinction: "your
* hardware does not exist" is a typo in a pack, and "your hardware is not in
* this build" is `PlanOptions.depth` doing exactly what it is for. Reporting the
* second would put a line in `problems` on every public build of any pack that
* ever marks a desk private, and `packRegression.test.ts` asserts that list is
* empty at both depths.
*/
describe("depth takes a device away with its hardware", () => {
it("drops a device standing on a private prop, without reporting one", () => {
const office = offsetFixture();
const prop = office.levels[0]?.floorplan.props?.[0];
assert.ok(prop);
prop.audience = "private";
const full = new Plan(office, { warn: false });
assert.equal(full.allDevices().length, 1);
assert.deepEqual(full.problems, []);
const publicBuild = new Plan(office, { depth: "public", warn: false });
assert.equal(publicBuild.allDevices().length, 0);
assert.equal(publicBuild.levels[0]?.devices.length, 0);
assert.deepEqual(publicBuild.problems, []);
});
/**
* And the same for a private desk bank, which is the harder half: a private
* bank generates no props at all, so the ids it *would* have generated have to
* be derived from the contract rather than observed.
*/
it("drops a device standing on a private bank's desk, without reporting one", () => {
const office = offsetFixture();
const level = office.levels[0];
assert.ok(level);
level.floorplan.props = [];
level.floorplan.deskBanks = [
{
id: "hidden",
desk: "tera:desk.workstation",
chair: "tera:seat.task-chair",
origin: { x: 4, z: 6 },
rotation: 0,
columns: 2,
rows: 1,
pitch: 1.7,
audience: "private",
},
];
const original = level.floorplan.devices?.[0];
assert.ok(original);
level.floorplan.devices = [
{ ...original, anchor: { ...original.anchor, propId: "hidden-desk-01" } },
];
const publicBuild = new Plan(office, { depth: "public", warn: false });
assert.equal(publicBuild.allDevices().length, 0);
assert.deepEqual(publicBuild.problems, []);
// The full build still resolves it, standing on the desk the bank generated
// — which is also the assertion that the derived id was the right one.
const full = new Plan(office, { warn: false });
assert.equal(full.device("fixture-mic")?.propId, "hidden-desk-01");
});
});
function round(value: number): number {
return Math.round(value * 1e6) / 1e6;
}
/**
* The smallest office that can carry a device: one room, one desk, one mic on
* the corner of it, and a quarter turn so that a frame error is visible.
*
* Built fresh on every call, because half of these tests mutate it.
*/
function offsetFixture(): Office {
const mic: DeviceDeclaration = {
id: "fixture-mic",
kind: "mic",
label: "Fixture mic",
assetId: "tera:device.mic.desk",
anchor: {
levelId: "level-1",
propId: "fixture-mic-hardware",
offset: { x: 0.5, y: 0, z: 0 },
},
capabilities: CANONICAL_CAPABILITIES.mic,
provenance: "simulated",
disclosure: "Simulated fixture hardware, never presence data.",
};
return {
id: "fixture",
name: "Fixture",
levels: [
{
id: "level-1",
name: "Ground",
elevation: 0,
wallHeight: 2.8,
floorplan: {
rooms: [
{
id: "room",
name: "Room",
outline: [
{ x: 0, z: 0 },
{ x: 0, z: 10 },
{ x: 10, z: 10 },
{ x: 10, z: 0 },
],
floor: "tera:concrete.polished",
},
],
walls: [],
props: [
{
id: "fixture-mic-hardware",
kind: "tera:device.mic.desk",
position: { x: 4, z: 6 },
rotation: -Math.PI / 2,
elevation: 0.73,
},
],
devices: [mic],
},
},
],
viewpoints: [],
};
}
+379
View File
@@ -0,0 +1,379 @@
/**
* The LA studio's content, held to the bar the SF studio set.
*
* `mateo-court` was never the smaller pack — it is sixteen rooms and roughly
* 250 props against four rooms and thirty. What it lacked was **fidelity per
* square metre and authoring generation**, and that had four measurable
* symptoms, every one of which is a check in this file:
*
* 1. Ninety-eight of its props were ceiling troffers, including an eight-by-
* three grid in a room declared `ceiling: null`.
* 2. It bound **zero** props to seats, so ten hand-authored addresses had no
* furniture and an occupancy layer had nothing to dim.
* 3. It placed **none** of the habitat kit past the kitchen: no sofa, no bed,
* no wardrobe, and — in a building whose every fitting was overhead — no
* floor lamp anywhere.
* 4. Twelve of its sixteen rooms had no viewpoint at all, and a room nobody
* has framed is a room nobody has looked at since they authored it.
*
* None of the four fails a build, none of them throws, and all four look
* completely fine in a screenshot of the one room somebody did frame. That is
* what makes them worth asserting rather than remembering.
*/
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { Plan, type PropPlacement } from "../../interiors/plan.ts";
import LUMBRIDGE_HQ from "../../offices/lumbridge-hq.ts";
import MATEO_COURT from "../../offices/mateo-court.ts";
const plan = new Plan(MATEO_COURT, { warn: false });
const props: PropPlacement[] = plan.levels.flatMap((level) => [...level.props]);
/** A light fitting, by id convention: `tera:light.*` is the whole family. */
function isFitting(prop: PropPlacement): boolean {
return prop.kind.startsWith("tera:light.");
}
/**
* Non-light props per square metre of authored floor, building-wide.
*
* Lights are excluded because they are the thing that was being counted instead
* of furniture — a room can hit any density target with a ceiling grid and still
* be empty. Fittings are measured separately, below, and capped.
*/
function densityOf(plan: Plan): { overall: number; byRoom: Map<string, number> } {
let area = 0;
let count = 0;
const byRoom = new Map<string, number>();
for (const level of plan.levels) {
for (const room of level.rooms) {
const inside = level.props.filter(
(prop) =>
!isFitting(prop) &&
plan.roomAt(level.id, { x: prop.position.x, z: prop.position.z })?.id === room.id,
);
area += room.area;
count += inside.length;
byRoom.set(room.id, inside.length / room.area);
}
}
return { overall: count / area, byRoom };
}
describe("the LA studio binds its furniture to its addresses", () => {
/**
* A seat is an address and a chair is a prop, and the whole point of the
* `seat` field is that something outside this repo can say "review-03" and
* have it mean a chair. Ten seats were authored here by hand and not one of
* them had a prop pointing at it.
*/
it("gives every hand-authored seat at least one prop that names it", () => {
const bound = new Set(props.map((prop) => prop.seat).filter((id) => id !== undefined));
const authored = MATEO_COURT.levels
.flatMap((level) => level.floorplan.seats ?? [])
.map((seat) => seat.id);
assert.ok(authored.length >= 10, "the pack stopped authoring seats by hand");
assert.deepEqual(
authored.filter((id) => !bound.has(id)),
[],
"seats with no furniture bound to them",
);
});
it("keeps the bindings on the props that are actually at those places", () => {
// Named pairs rather than a count, because the failure this catches is a
// chair bound to the seat on the other side of the table — which is invisible
// until an occupancy layer dims the wrong one.
for (const [propId, seatId] of [
["front-chair", "front-01"],
["mess-stool-01", "commons-01"],
["mess-stool-02", "commons-02"],
["hewitt-chair-n-01", "review-01"],
["hewitt-chair-n-02", "review-02"],
["hewitt-chair-s-01", "review-03"],
["hewitt-chair-s-02", "review-04"],
["loggia-chair-01", "loggia-01"],
] as const) {
const prop = plan.prop(propId);
const seat = plan.seat(seatId);
assert.ok(prop, `${propId} is gone`);
assert.ok(seat, `${seatId} is gone`);
assert.equal(prop.seat, seatId);
// Bound and co-located: a binding that is right and a chair that is two
// metres away is a different bug with the same symptom.
assert.ok(
Math.hypot(prop.position.x - seat.position.x, prop.position.z - seat.position.z) < 1.0,
`${propId} is nowhere near ${seatId}`,
);
}
});
});
describe("the LA studio is furnished, not merely lit", () => {
/**
* Mirrors the SF assertion in `office.test.ts`. Four of these seven assets
* were written, tested and placed by nobody — the kit existed and the second
* studio used none of it.
*/
it("places all seven of the habitat kit", () => {
const kinds = new Set(props.map((prop) => prop.kind));
for (const id of [
"tera:bed.platform",
"tera:sofa.modular",
"tera:kitchen.run",
"tera:kitchen.island",
"tera:storage.wardrobe",
"tera:seat.stool",
"tera:light.floor",
]) assert.ok(kinds.has(id), `${id} is not placed in the LA studio`);
});
/**
* The troffer cap, and the reason it is a cap and not a target.
*
* `furnish.ts` batches per kind, so the ninety-eighth troffer buys nothing the
* eye reads while costing exactly as much authoring attention as a piece of
* furniture would. Two of the grids hung from rooms declared `ceiling: null`.
* The baseline was 98; the cap is 55 and the pack currently sits at 48.
*/
it("stops hanging a hundred troffers from ceilings that are not there", () => {
const troffers = props.filter((prop) => prop.kind === "tera:light.troffer");
assert.ok(
troffers.length <= 55,
`${troffers.length} troffers, which is more than the 55 this building is allowed`,
);
// And the fittings that remain are still fittings: every one is authored at
// an elevation, because a troffer on the floor is a box in the middle of the
// room. This is the check that stops the cap being met by moving them.
for (const prop of troffers) {
assert.ok(prop.position.y > 2.5, `${prop.id} is a ceiling fitting at y ${prop.position.y}`);
}
});
/**
* Soft light exists at all, which is the other half of the troffer argument. A
* building lit exclusively from a ceiling grid reads as a rendering of an
* office rather than as a place, and this pack had 108 fittings and not one of
* them below head height.
*/
it("lights something with a lamp somebody could turn off", () => {
const lamps = props.filter((prop) => prop.kind === "tera:light.floor");
assert.ok(lamps.length >= 5, `only ${lamps.length} floor lamps in sixteen rooms`);
const rooms = new Set(
lamps.map(
(lamp) =>
plan.roomAt(lamp.levelId, { x: lamp.position.x, z: lamp.position.z })?.id ?? "nowhere",
),
);
assert.ok(rooms.size >= 5, `every floor lamp is in one of ${rooms.size} rooms`);
assert.equal(rooms.has("nowhere"), false, "a floor lamp stands outside every room");
});
/**
* ### Density, and the target it is measured against
*
* The bar is the SF studio's own figure — 0.28 non-light props/m² over its
* whole floor — and the gate is 0.26 building-wide with no room over 20 m²
* below 0.15. This pack reached 0.288 with the studio kit; it was at 0.135
* when the pass started and 0.149 before those twelve assets existed.
*
* Lights are excluded on purpose. A ceiling grid will satisfy any prop count
* you like while leaving the floor bare, and this building's first version
* proved it: ninety-eight of its props were troffers, two of the grids hung in
* rooms declared `ceiling: null`, and it still looked empty from every
* viewpoint. Fittings are capped separately, above.
*/
it("carries at least as much furniture per square metre as the SF studio", () => {
const { overall, byRoom } = densityOf(plan);
assert.ok(overall >= 0.26, `density fell to ${overall.toFixed(3)} non-light props/m²`);
for (const level of plan.levels) {
for (const room of level.rooms) {
if (room.area < 20) continue;
const density = byRoom.get(room.id) ?? 0;
assert.ok(
density >= 0.15,
`${room.id} is at ${density.toFixed(3)} props/m² over ${room.area.toFixed(0)}`,
);
}
}
});
/** The bar this pack is being measured against, stated rather than assumed. */
it("measures the SF studio the same way, so the target is a real number", () => {
const sf = densityOf(new Plan(LUMBRIDGE_HQ, { warn: false }));
assert.ok(sf.overall >= 0.26, `the SF studio itself fell to ${sf.overall.toFixed(3)}`);
const { overall } = densityOf(plan);
assert.ok(
overall >= sf.overall,
`LA is at ${overall.toFixed(3)} against SF's ${sf.overall.toFixed(3)}`,
);
});
/**
* ### The check that actually stops this pack going thin again
*
* `furnish.ts` batches props by **(asset, colorKey)** and draws `ctx.rand`
* once per batch, so every instance of a kind is geometrically identical —
* same seeded jitter, same books on the same shelf. Ten more shelves in a room
* are one shelf drawn ten times. That makes the density figure above gameable
* by exactly the move that would not change a single pixel a viewer resolves,
* and it is why the courtyard could sit at thirteen props of six kinds and
* read as a car park.
*
* So the real assertion is **distinct kinds per room**, and it is deliberately
* a floor per room rather than a building-wide count: a pack can put thirty
* kinds in reception and leave the yard bare, and the yard is the room every
* viewpoint looks across.
*/
it("furnishes its big rooms out of many kinds and not many copies", () => {
const thin: string[] = [];
for (const level of plan.levels) {
for (const room of level.rooms) {
if (room.area < 40) continue;
const kinds = new Set(
level.props
.filter(
(prop) =>
!isFitting(prop) &&
plan.roomAt(level.id, { x: prop.position.x, z: prop.position.z })?.id === room.id,
)
.map((prop) => prop.kind),
);
// Seven is the number the *reference* pack's one big room manages, and
// it is the floor rather than the aspiration: `works`, `loft` and `court`
// are all well past it.
if (kinds.size < 7) thin.push(`${room.id} (${kinds.size} kinds over ${room.area.toFixed(0)} m²)`);
}
}
assert.deepEqual(thin, [], "big rooms furnished out of too few distinct assets");
});
/**
* The studio kit is placed at all, mirroring the habitat assertion above.
*
* Twelve assets arrived in `src/assets/office/studio.ts` for this pack and no
* other, and an asset nobody places is an asset nobody has looked at since it
* was written — which is precisely the state four of the seven habitat assets
* were found in.
*/
it("places every one of the twelve studio assets", () => {
const kinds = new Set(props.map((prop) => prop.kind));
for (const id of [
"tera:planter.trough",
"tera:bench.slat",
"tera:canopy.parasol",
"tera:bench.lab",
"tera:rack.equipment",
"tera:cart.tool",
"tera:dock.robot",
"tera:case.stack",
"tera:light.softbox",
"tera:camera.tripod",
"tera:acoustic.baffle",
"tera:divider.slat",
]) assert.ok(kinds.has(id), `${id} is not placed in the LA studio`);
});
/**
* A robot charge station stands on a dock, and not on bare floor.
*
* `operations/mateo-court.ts` parks a humanoid at `la-l1-dock` and
* `la-l2-dock`. Before `tera:dock.robot` existed, the ground-floor one was a
* point at (18.4, 13.2) — underneath the courtyard's long table. That was
* invisible for as long as nothing was drawn there, which is the whole problem
* with an address that names no furniture.
*/
it("stands its charge stations on something", () => {
const docks = props.filter((prop) => prop.kind === "tera:dock.robot");
assert.ok(docks.length >= 4, `only ${docks.length} robot docks in a building with a robot`);
for (const [levelId, x, z] of [
["level-1", 10.9, 16.9],
["level-2", 22.6, 1.5],
] as const) {
const near = docks.filter(
(dock) =>
dock.levelId === levelId &&
Math.hypot(dock.position.x - x, dock.position.z - z) < 1.2,
);
assert.ok(near.length >= 1, `the ${levelId} charge station stands on nothing`);
}
});
});
describe("the LA studio frames every room it has", () => {
it("declares at least twelve viewpoints, arriving at the passage", () => {
assert.ok(plan.viewpoints.length >= 12, `${plan.viewpoints.length} viewpoints`);
// `viewpoints[0]` is the arrival pose *and* the walk spawn, so its identity
// is load-bearing in two places at once.
assert.equal(plan.viewpoints[0]?.id, "paseo");
});
it("puts a viewpoint inside every room over twenty square metres", () => {
const unframed: string[] = [];
for (const level of plan.levels) {
for (const room of level.rooms) {
if (room.area < 20) continue;
const framed = plan.viewpoints.some(
(view) =>
view.levelId === level.id && plan.roomAt(level.id, view.focus.at)?.id === room.id,
);
if (!framed) unframed.push(`${room.id} (${room.area.toFixed(0)} m²)`);
}
}
assert.deepEqual(unframed, [], "rooms with no viewpoint");
});
it("writes a description for each one that says something", () => {
for (const view of plan.viewpoints) {
// The length band is the existing six, which were written to sit on two
// lines of the legend. A one-word description is a placeholder somebody
// meant to come back to.
assert.ok(view.description, `${view.id} has no description`);
assert.ok(
(view.description?.length ?? 0) >= 110 && (view.description?.length ?? 0) <= 200,
`${view.id} description is ${view.description?.length} characters`,
);
assert.ok(view.shortLabel, `${view.id} has no short label`);
}
const numbers = plan.viewpoints.map((view) => view.number);
assert.equal(new Set(numbers).size, numbers.length, "two viewpoints share a number");
});
});
/**
* Two sets of prop ids in this pack are addresses something outside it holds.
*
* Media screens are named by hosted screen grants (`server/src/media/bindings.ts`
* treats every `tera:screen.*` prop as a shareable surface), and robot stations
* are anchored to props by id in `operations/mateo-court.ts` — where a miss
* throws rather than degrades. A content pass renumbers a `scatter` without
* noticing; this is what notices.
*/
describe("the pinned ids survive a content pass", () => {
it("keeps every media screen id a screen", () => {
for (const id of [
"front-monitor",
"paseo-directory",
"hewitt-display",
"willow-display",
"palmetto-display",
"works-display",
"loft-display",
]) {
const prop = plan.prop(id);
assert.ok(prop, `media screen ${id} is gone`);
assert.match(prop.kind, /^tera:screen\./, `${id} is no longer a screen`);
}
});
it("keeps every prop a robot station is anchored to", () => {
for (const id of [
"store-shelf-02",
"works-locker-02",
"loft-locker-02",
"jesse-shelf-01",
"jesse-board-02",
]) assert.ok(plan.prop(id), `robot station anchor ${id} is gone`);
});
});
+127
View File
@@ -0,0 +1,127 @@
/**
* Every shipped pack still resolves, and still resolves to the same thing over
* the wire as it does in the bundle.
*
* This is the file that stands between "deprioritised" and "broken". Two of the
* three packs in this repo are not being invested in — `frontier-valley` is
* published as `building` and `lumbridge-hq` is finished — and the LA content
* pass edits shared helpers, shared constants and the schema all three are
* authored against. A pack nothing asserts on is a pack that stops resolving
* the first time somebody changes a helper two directories away, and the
* failure is silent: `Plan` never throws, it drops the offending item and
* records a line in `problems` that nothing reads.
*
* The JSON round trip is here for the same reason and caught a real defect.
* CONTRACT.md §2 says a pack hand-written as a `.ts` module and a pack arriving
* as a `.json` body over HTTP have to be **literally the same thing**. Both
* `mateo-court.ts` and `frontier-valley.ts` had a `scatter()` helper assigning
* `elevation: opts.elevation` unconditionally, which put 283 and 106
* undefined-valued keys into their exported values respectively. `JSON.stringify`
* drops those keys, so the served pack was a different object from the bundled
* one — invisible in every renderer, and exactly the sort of thing that turns
* into a two-day bug the first time a self-hoster round-trips a pack through the
* office API and finds their props have moved.
*/
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { Plan } from "../../interiors/plan.ts";
import type { Office } from "../../interiors/types.ts";
import LUMBRIDGE_HQ from "../../offices/lumbridge-hq.ts";
import FRONTIER_VALLEY from "../../offices/frontier-valley.ts";
import MATEO_COURT from "../../offices/mateo-court.ts";
import { OFFICE_SITES } from "../../offices/sites.ts";
const PACKS: readonly Office[] = [LUMBRIDGE_HQ, FRONTIER_VALLEY, MATEO_COURT];
/** Every path in `value` whose key is present and whose value is `undefined`. */
function undefinedKeys(value: unknown, path: string, out: string[]): void {
if (Array.isArray(value)) {
value.forEach((item, i) => undefinedKeys(item, `${path}[${i}]`, out));
return;
}
if (value === null || typeof value !== "object") return;
for (const [key, entry] of Object.entries(value)) {
if (entry === undefined) out.push(`${path}.${key}`);
else undefinedKeys(entry, `${path}.${key}`, out);
}
}
describe("every shipped pack resolves", () => {
for (const pack of PACKS) {
/**
* At **both** depths, because they are different builds and only one of them
* is the one a visitor gets. `PlanOptions.depth` skips every item marked
* `audience: "private"` before it is resolved, so a pack can be clean at
* `"full"` and drop something at `"public"` — a device standing on a private
* prop is the case this build introduced.
*/
for (const depth of ["full", "public"] as const) {
it(`${pack.id} at ${depth} depth reports no problems`, () => {
const plan = new Plan(pack, { depth, warn: false });
assert.deepEqual(
plan.problems.map((p) => `${p.where}: ${p.message} (${p.action})`),
[],
);
});
}
it(`${pack.id} survives a JSON round trip unchanged`, () => {
// Strict deep equality, which treats `{ a: undefined }` and `{}` as
// different objects. That is the whole point: they *are* different
// objects, and only one of them survives `JSON.stringify`.
assert.deepEqual(JSON.parse(JSON.stringify(pack)), pack);
const stray: string[] = [];
undefinedKeys(pack, pack.id, stray);
assert.deepEqual(stray, [], `${pack.id} carries undefined-valued keys`);
});
/**
* `main.ts` spawns the walker at `viewpoints[0].focus.at` — that is not a
* camera target in this one case, it is a coordinate a person stands on. A
* pack whose first viewpoint frames a shot from outside the building looks
* fine in the legend and spawns the visitor inside a wall.
*/
it(`${pack.id} arrives somewhere a walker can stand`, () => {
const plan = new Plan(pack, { warn: false });
const arrival = plan.arrival();
assert.ok(arrival, `${pack.id} declares no viewpoints`);
const room = plan.roomAt(arrival.levelId, arrival.focus.at);
assert.ok(room, `${pack.id} arrives at ${JSON.stringify(arrival.focus.at)}, which is in no room`);
for (const [dx, dz] of [[0.4, 0], [-0.4, 0], [0, 0.4], [0, -0.4]] as const) {
const step = { x: arrival.focus.at.x + dx, z: arrival.focus.at.z + dz };
if (!plan.blocked(arrival.levelId, arrival.focus.at, step, 0.3)) return;
}
assert.fail(`${pack.id} arrives in a spot with no clear step in any direction`);
});
it(`${pack.id} keeps every viewpoint on a level that exists`, () => {
const plan = new Plan(pack, { warn: false });
const levels = new Set(plan.levels.map((level) => level.id));
// `Plan` drops a viewpoint whose level does not resolve, so a count that
// matches the authored one is the assertion that none were dropped.
assert.equal(plan.viewpoints.length, pack.viewpoints.length);
for (const view of plan.viewpoints) {
assert.ok(levels.has(view.levelId), `${pack.id}/${view.id} is on nothing`);
}
});
}
});
/**
* The in-development pack stays in development.
*
* `frontier-valley` is deprioritised, which is a decision about investment and
* not about correctness: it must keep resolving, and it must keep telling a
* visitor the truth about itself. A content pass that quietly promoted it to
* `active` would put a half-furnished hangar in the same sentence as two
* finished studios.
*/
describe("the published runtime status", () => {
it("still calls Frontier Valley a building site and the two studios active", () => {
assert.deepEqual(
OFFICE_SITES.map(({ id, status }) => `${id}:${status}`),
["lumbridge-hq:active", "frontier-valley:building", "mateo-court:active"],
);
});
});