1
0

The Southland gets a door, and the people in it move

**Mateo Court**, a courtyard block in the Arts District — a third pack and
a third *kind* of building. Two office floors and a shed already existed,
so this is the plan the format had not been shown: a ring of rooms round
an open-air yard with **no corridor anywhere**. Every door opens onto the
yard, and the yard does the job a corridor does in the other two. It is
also the first pack whose `ceiling: null` means there is genuinely no
ceiling at any height rather than "take the lid off so the shot can see
in", and the first sited off the Bay Area board at all.

That last part needed a fix, not just a coordinate. `OFFICE_MARKERS` was
gated on `id === "sf"`, which was correct for exactly as long as every
office was in the Bay Area — it would have kept the Los Angeles building
off the Los Angeles board and pinned it to San Francisco's. The gate is
the board's own bounds now, which is the same question asked honestly.

Every door through the 0.25 m courtyard skin is 1.2 m rather than the
usual 0.9, and that is not a style choice: `blocked` inflates by the
walker's radius *and* the wall's thickness, so a 0.9 m leaf through a wall
that thick seals the room behind it while rendering perfectly. Two rooms
were sealed exactly that way on the first pass. The test says so, because
a well-meaning edit back to 0.9 for consistency would do it again.

**People move.** `samplePresenceAt` thinned the roster by hour, which
fixed a building that was full at 1 a.m., but everybody was still pinned
to their own desk all day. Occupancy is a hand-written booking table now:
meetings fill a room for a plausible length, the kitchen island fills at
lunch, and a `Presence` binds to a seat id — so "in a meeting" means
occupying a meeting-room seat, and the whole thing is choosing seat ids
rather than inventing positions.

The flood fill that checks a pack is walkable existed three times over.
One copy now, since the third is where a divergence lives.

**Films.** A new `office-dusk` reel — six hours over Lumbridge HQ catching
the moment the house lights take over from the sun, which is the one thing
only a time-lapse can show and which did not exist. The three existing
reels are re-rendered rather than re-captioned: `films.ts` in v4 named a
commit eleven behind HEAD, so the published reels were shot before there
were any clouds and before the city drew office pins.

Reviewers caught roughly a dozen false statements in the new prose across
these files — a room census that did not add up, a wall-thickness count,
a claim that every room has daylight when one does not, and a cost figure
saying `updateSun` runs once a second when it runs once a minute. The
consequential ones are fixed. In a codebase where the comments are the
design record, a confident wrong number is a defect.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-07 05:50:32 -07:00
parent df9641cddd
commit 9c9e78f6f9
6 changed files with 2700 additions and 149 deletions
+171 -3
View File
@@ -27,10 +27,77 @@ import { describe, it } from "node:test";
import { Plan } from "../interiors/plan.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 plan = new Plan(LUMBRIDGE_HQ, { warn: false });
/**
* Which rooms on a level can be walked to from a point, at 0.1 m.
*
* Shared by all three packs, because it was written three times otherwise and
* the third copy is where a subtle divergence lives. The grid is finer than it
* looks like it needs to be and that is not optional: `blocked` inflates by the
* walker's radius, so threading a 0.9 m door with a 0.3 m radius leaves 0.3 m of
* clear width, and a 0.25 m grid can straddle that and report a sealed room that
* is fine. Erring the other way is not possible — a coarser grid only ever
* reaches fewer rooms, so a pass is always a real pass.
*/
function reachableRoomsOf(
plan: Plan,
levelId: string,
entry: { x: number; z: number },
): Set<string> {
const STEP = 0.1;
const RADIUS = 0.3;
const b = plan.bounds;
const cols = Math.ceil(b.width / STEP);
const rows = Math.ceil(b.depth / STEP);
const at = (c: number, r: number) => ({ x: b.minX + c * STEP, z: b.minZ + r * STEP });
const room: (string | null)[] = new Array(cols * rows).fill(null);
for (let r = 0; r < rows; r += 1) {
for (let c = 0; c < cols; c += 1) {
room[r * cols + c] = plan.roomAt(levelId, at(c, r))?.id ?? null;
}
}
const sc = Math.round((entry.x - b.minX) / STEP);
const sr = Math.round((entry.z - b.minZ) / STEP);
assert.ok(room[sr * cols + sc], `${levelId}'s entry point is not inside a room`);
const seen = new Uint8Array(cols * rows);
const queue: [number, number][] = [[sc, sr]];
seen[sr * cols + sc] = 1;
while (queue.length > 0) {
const [c, r] = queue.pop() as [number, number];
for (const [dc, dr] of [
[1, 0],
[-1, 0],
[0, 1],
[0, -1],
]) {
const nc = c + (dc as number);
const nr = r + (dr as number);
if (nc < 0 || nr < 0 || nc >= cols || nr >= rows) continue;
const i = nr * cols + nc;
if (seen[i] === 1 || room[i] === null) continue;
if (plan.blocked(levelId, at(c, r), at(nc, nr), RADIUS)) continue;
seen[i] = 1;
queue.push([nc, nr]);
}
}
const reached = new Set<string>();
for (let i = 0; i < seen.length; i += 1) {
const id = room[i];
if (seen[i] === 1 && id != null) reached.add(id);
}
return reached;
}
describe("the reference pack resolves cleanly", () => {
/** Checklist item 1, and the one everything else here depends on. */
it("reports no problems at all", () => {
@@ -398,7 +465,7 @@ describe("the sites", () => {
});
it("carry headings inside the compass", () => {
for (const pack of [LUMBRIDGE_HQ, FRONTIER_VALLEY]) {
for (const pack of [LUMBRIDGE_HQ, FRONTIER_VALLEY, MATEO_COURT]) {
const h = pack.site?.heading ?? 0;
assert.ok(h >= 0 && h < 360, `${pack.id} has a heading of ${h}`);
}
@@ -430,12 +497,12 @@ describe("the office site table", () => {
it("lists exactly the packs this build ships", () => {
assert.deepEqual(
OFFICE_SITES.map((e) => e.id).sort(),
[FRONTIER_VALLEY.id, LUMBRIDGE_HQ.id].sort(),
[FRONTIER_VALLEY.id, LUMBRIDGE_HQ.id, MATEO_COURT.id].sort(),
);
});
it("hands each pack the very same site object it publishes", () => {
for (const pack of [LUMBRIDGE_HQ, FRONTIER_VALLEY]) {
for (const pack of [LUMBRIDGE_HQ, FRONTIER_VALLEY, MATEO_COURT]) {
const entry = OFFICE_SITES.find((e) => e.id === pack.id);
assert.ok(entry, `${pack.id} is missing from OFFICE_SITES`);
// Identity, not equality: the packs import from the table, so anything
@@ -444,3 +511,104 @@ describe("the office site table", () => {
}
});
});
/**
* The third pack, and the first on the other board.
*
* A courtyard block: a ring of rooms round an open-air yard with **no corridor
* anywhere** — every door opens onto the yard, and the yard does the job a
* corridor does in the other two. That makes it the first pack whose
* circulation is outdoors, and the first whose `ceiling: null` means there is
* genuinely no ceiling rather than "take the lid off so the shot can see in".
*/
describe("the Mateo Court pack", () => {
const mc = new Plan(MATEO_COURT, { warn: false });
it("resolves with no problems", () => {
assert.deepEqual(
mc.problems.map((p) => `${p.where}: ${p.message} (${p.action})`),
[],
);
});
it("stacks its upper floor floor-to-floor", () => {
assert.deepEqual(
mc.levels.map((l) => [l.id, l.floorY]),
[
["level-1", 0],
["level-2", 5],
],
);
});
it("keeps its seat ids disjoint from both other packs", () => {
const mine = mc.allSeats().map((s) => s.id);
assert.equal(new Set(mine).size, mine.length);
const others = new Set([
...plan.allSeats().map((s) => s.id),
...new Plan(FRONTIER_VALLEY, { warn: false }).allSeats().map((s) => s.id),
]);
assert.deepEqual(mine.filter((id) => others.has(id)), []);
});
/**
* **The check that matters most in this pack.**
*
* Every door through the 0.25 m courtyard skin is 1.2 m rather than the 0.9 m
* the rest of the library uses, and that is not a style choice: `blocked`
* inflates by the walker's radius *and* by the wall's thickness, so a 0.9 m
* leaf in a wall this thick leaves too little clear width and seals the room
* behind it — while rendering perfectly. Two rooms were sealed exactly that
* way on the pack's first pass. A well-meaning edit back to 0.9 for
* consistency would do it again, and this is the only thing that would say so.
*/
for (const [levelId, entry] of [
["level-1", { x: 18.1, z: 1.0 }],
["level-2", { x: 8.4, z: 10.4 }],
] as const) {
it(`${levelId}: every room reachable from the way in`, () => {
const reached = reachableRoomsOf(mc, levelId, entry);
const sealed = mc.levels
.find((l) => l.id === levelId)!
.rooms.map((r) => r.id)
.filter((id) => !reached.has(id));
assert.deepEqual(sealed, [], `sealed rooms on ${levelId}`);
});
}
/**
* The loggia rail, and the gap in it.
*
* Both halves matter and only together: a rail that also sealed the stair head
* would pass an assertion that only checked you cannot fall off.
*/
it("guards the loggia edge without sealing the way up", () => {
assert.ok(mc.blocked("level-2", { x: 8.8, z: 9.0 }, { x: 10.6, z: 9.0 }, 0.3));
assert.ok(mc.blocked("level-2", { x: 8.8, z: 14.0 }, { x: 10.6, z: 14.0 }, 0.3));
assert.ok(mc.blocked("level-2", { x: 18.0, z: 7.6 }, { x: 18.0, z: 9.4 }, 0.3));
assert.ok(
!mc.blocked("level-2", { x: 8.8, z: 10.4 }, { x: 10.4, z: 10.4 }, 0.3),
"the stair head is walled off",
);
});
it("stands its upper-floor occupants on the deck", () => {
for (const id of ["loggia-01", "palmetto-01"]) {
assert.equal(mc.seat(id)?.y, 5, `${id} is not on the deck`);
}
});
it("leaves the yard open to the sky", () => {
const court = mc.levels[0]?.rooms.find((r) => r.id === "court");
assert.ok(court, "no courtyard");
assert.equal(court.ceiling, null);
});
/** The point of the pack: the Southland board finally has a door. */
it("stands on the Southland board", () => {
const site = MATEO_COURT.site;
assert.ok(site);
assert.ok(site.lat > 33.28 && site.lat < 34.36, `latitude ${site.lat}`);
assert.ok(site.lng > -118.88 && site.lng < -117.22, `longitude ${site.lng}`);
});
});