The office learns where it stands, and the sky stops being a backdrop
**Aircraft actually move now, and the reason they did not is the headline.**
`HttpFlights` holds a frozen snapshot between network refreshes and is
polled at 1 Hz, so a live feed handed the layer the same position five to
fifteen times and then jumped. `span` therefore measured the poll interval
rather than the gap between the two positions that differ, the teleport
test saw an airliner covering 36 units in a "second" against a ceiling of
8, and **every live track's history was wiped on every refresh** — so no
aircraft on the deployed site could ever grow a trail, however long
TRAIL_POINTS was set. Skipping the repeat fixes the motion and the trail
at once. Trails then go to 72 points / 240 s, which is about seventy
seconds of flying.
Three more defects in the same file, found while looking: trail
truncation dropped the segments nearest the aircraft (leaving a streak
with no aeroplane attached), MAX_TRACKS was declared and never enforced,
and one missing target deleted its whole trail. The buffer now uploads
only what it wrote, rather than 46 MB/s of untouched array.
**You can get above the constellation.** Dome to 1.05 board *radii* and
the orbit to 2.0 spans. Radii, not spans: scene space is centred on the
city and the Bay Area board runs forty kilometres down the peninsula, so
the furthest corner is 0.94 spans out where the half-diagonal is 0.65 —
sized off the half-diagonal the dome sat inside its own city. The far
plane goes to 4 spans to stop clipping the sky from off-centre chapters,
and `PointsMaterial` defaults `fog: true`, which was quietly dimming the
whole constellation with the city's haze.
**An office can say where it stands.** `Office.site` — lat, lng, height
above the ground outside, and the compass bearing the pack's −Z points
along — and with one it gets the same sun the city does, a sky, and a
horizon at `-elevation`. CONTRACT §4 reserved this as "a later
refinement"; it is taken up rather than overturned, and `daylight.ts`
computes no light of its own. It does the two things a room needs that a
map does not: turn the sun into the building's frame, and move the fog
outdoors before it greys out the far wall.
Two buildings now, and they are deliberately unalike: Lumbridge HQ 188 m
up a Transbay tower facing 205°, and **Frontier Valley**, a startup in a
hangar at Alameda Point — one room, 54 x 30 m, nine metres to the
trusses, four metres above reclaimed ground.
Floor-to-floor in the reference pack is now 16.8 m: the interstitial is
ten times a real one, so the space between the slabs is somewhere things
can hang. It is frankly not architecture, `PLENUM` is the one number to
change, and the file says so.
Also fixed, all found by review rather than by looking at the screen:
- `sun.shadow.camera.updateProjectionMatrix()` was never called, so
three's default ±5 unit box has been in force this whole time and
every `shadowExtent` this repo passes — including the city's ±752 —
has been silently ignored.
- A missing aircraft was kept alive by the new grace period and *drawn*,
so it froze in mid-air at full opacity for 32 s.
- Frontier Valley's mezzanine was a `Room`, which carries no height: its
slab lay on the concrete, its chairs floated 4.4 m over it, and its
balustrade fenced off a patch of ground floor. It is a `Level`.
- Overlapping floor slabs z-fought. The format permits overlap and
resolves later-first, so `shell.ts` now lifts a slab a hair per
earlier slab it overlaps — and by nothing at all in a pack, like the
reference office, whose rooms only ever abut.
- `switchOffice` bypassed the `entering` guard (leaking a whole scene
per double-click) and tore down the old room before knowing the new
one would load, with no way back.
Known and not fixed: raising MAX_SPAN to 30 s doubles the worst-case
re-base snap when a feed's gap shortens. It is bounded, pre-existing in
kind, and the fix wants carrying the live head into the next leg.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+197
-17
@@ -16,7 +16,7 @@
|
||||
* room behind it is sealed, and the only evidence is a line in
|
||||
* `plan.problems` that nothing reads. That exact bug happened once while the
|
||||
* wing was being written.
|
||||
* - **The balustrade.** The gallery is 4.2 m above terrazzo. `Plan` derives
|
||||
* - **The balustrade.** The gallery is 16.8 m above terrazzo. `Plan` derives
|
||||
* the walk collider from the wall list, so the difference between a
|
||||
* balustrade and a decorative rail is whether it is in that list — and both
|
||||
* look identical in a screenshot.
|
||||
@@ -26,6 +26,7 @@ import assert from "node:assert/strict";
|
||||
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";
|
||||
|
||||
const plan = new Plan(LUMBRIDGE_HQ, { warn: false });
|
||||
|
||||
@@ -38,13 +39,28 @@ describe("the reference pack resolves cleanly", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("has both storeys, at floor-to-floor and not floor-to-ceiling", () => {
|
||||
assert.deepEqual(
|
||||
plan.levels.map((l) => [l.id, l.floorY]),
|
||||
[
|
||||
["level-1", 0],
|
||||
["level-2", 4.2],
|
||||
],
|
||||
/**
|
||||
* The relationship, not the number.
|
||||
*
|
||||
* Floor-to-floor is deliberately exaggerated in this pack — see `PLENUM` in
|
||||
* `lumbridge-hq.ts` — and an assertion on the literal would have to be edited
|
||||
* every time somebody dials it, which makes it a change-detector rather than a
|
||||
* test. What must stay true is that level 2 sits a clear interstitial *above*
|
||||
* level 1's ceiling, and never at or below it: `elevation` is floor-to-floor,
|
||||
* and setting it to the ceiling height is the classic way to bury one storey's
|
||||
* slab inside the one below.
|
||||
*/
|
||||
it("stacks the storeys floor-to-floor, not floor-to-ceiling", () => {
|
||||
const [first, second] = plan.levels;
|
||||
assert.ok(first && second, "both storeys should resolve");
|
||||
assert.equal(first.id, "level-1");
|
||||
assert.equal(second.id, "level-2");
|
||||
assert.equal(first.floorY, 0);
|
||||
|
||||
const ceiling = LUMBRIDGE_HQ.levels[0]?.wallHeight ?? 0;
|
||||
assert.ok(
|
||||
second.floorY > ceiling,
|
||||
`level 2's slab at ${second.floorY} m is inside level 1, whose ceiling is at ${ceiling} m`,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -188,7 +204,7 @@ describe("the gallery balustrade", () => {
|
||||
for (const [name, from, to] of edges) {
|
||||
assert.ok(
|
||||
plan.blocked("level-2", from, to, 0.3),
|
||||
`the ${name} edge of the gallery lets a walker off a 4.2 m drop`,
|
||||
`the ${name} edge of the gallery lets a walker off a 16.8 m drop`,
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -218,20 +234,184 @@ describe("the commons is open to both storeys", () => {
|
||||
});
|
||||
|
||||
it("is enclosed to two storeys rather than one", () => {
|
||||
const level1 = plan.levels.find((l) => l.id === "level-1");
|
||||
assert.ok(level1);
|
||||
// 7.0 m: one storey of 4.2 plus one room of 2.8. Asserted against the walls
|
||||
// as resolved, so a level default leaking through would be caught.
|
||||
//
|
||||
const [level1, level2] = plan.levels;
|
||||
assert.ok(level1 && level2);
|
||||
|
||||
// The height the void *should* be, derived rather than typed: everything up
|
||||
// to level 2's slab, plus level 2's own room. That is what "open to both
|
||||
// storeys" means, and it stays true whatever the interstitial is set to.
|
||||
const ceiling = LUMBRIDGE_HQ.levels[1]?.wallHeight ?? 0;
|
||||
const expected = level2.floorY + ceiling;
|
||||
|
||||
// `solid` only. The splitting pass emits a run per piece, so a wall with a
|
||||
// door in it also yields a `lintel` over the opening — 4.6 m of wall above a
|
||||
// 2.4 m head, which is correct and is not the wall's height.
|
||||
// door in it also yields a `lintel` over the opening — correct, and not the
|
||||
// wall's height.
|
||||
const wingWalls = level1.runs.filter(
|
||||
(run) => run.wallId.startsWith("wing-") && run.role === "solid",
|
||||
);
|
||||
assert.ok(wingWalls.length > 0, "the wing has no walls");
|
||||
for (const run of wingWalls) {
|
||||
assert.equal(run.top - run.bottom, 7, `${run.wallId} is ${run.top - run.bottom} m tall`);
|
||||
assert.equal(
|
||||
run.top - run.bottom,
|
||||
expected,
|
||||
`${run.wallId} is ${run.top - run.bottom} m tall, not the ${expected} m the void needs`,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* The second pack, held to the same bar as the first.
|
||||
*
|
||||
* A shipped pack that nothing asserts on is a pack that quietly stops resolving
|
||||
* the first time somebody edits a shared constant. It gets the two checks that
|
||||
* catch that — clean resolution and a walkable building — plus the one thing
|
||||
* that is specific to it: it is a *hangar*, and the point of shipping it is that
|
||||
* the format describes one room fifty-four metres across as readily as it
|
||||
* describes a corridor with fifteen doors off it.
|
||||
*/
|
||||
describe("the Frontier Valley pack", () => {
|
||||
const fv = new Plan(FRONTIER_VALLEY, { warn: false });
|
||||
|
||||
it("resolves with no problems", () => {
|
||||
assert.deepEqual(
|
||||
fv.problems.map((p) => `${p.where}: ${p.message} (${p.action})`),
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* The deck is a level, and that is the fix for a real defect rather than a
|
||||
* modelling preference: authored as a `Room` it had no floor height, so its
|
||||
* slab lay on the concrete while its furniture floated 4.4 m over it.
|
||||
*/
|
||||
it("puts the mezzanine on its own level, at deck height", () => {
|
||||
assert.deepEqual(
|
||||
fv.levels.map((l) => [l.id, l.floorY]),
|
||||
[
|
||||
["level-1", 0],
|
||||
["level-mezz", 4.4],
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
it("has unique seat ids, which must not collide with the other pack's", () => {
|
||||
const mine = fv.allSeats().map((s) => s.id);
|
||||
assert.equal(new Set(mine).size, mine.length);
|
||||
// Not a hard requirement of the format — ids are unique per *building* — but
|
||||
// a deployment serving both from one presence API would find out the hard
|
||||
// way, and the two packs cost nothing by staying disjoint.
|
||||
const theirs = new Set(plan.allSeats().map((s) => s.id));
|
||||
const shared = mine.filter((id) => theirs.has(id));
|
||||
assert.deepEqual(shared, [], "seat ids shared between the two shipped packs");
|
||||
});
|
||||
|
||||
it("can be walked from the personnel door to every room", () => {
|
||||
const STEP = 0.1;
|
||||
const RADIUS = 0.3;
|
||||
const b = fv.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] = fv.roomAt("level-1", at(c, r))?.id ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
// Just inside the west gable's personnel door.
|
||||
const sc = Math.round((1.0 - b.minX) / STEP);
|
||||
const sr = Math.round((14.4 - b.minZ) / STEP);
|
||||
assert.ok(room[sr * cols + sc], "the way in 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 (fv.blocked("level-1", 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);
|
||||
}
|
||||
// Level 1 only. The mezzanine is a level of its own now and is reached by a
|
||||
// stair this pack does not model, so a flood fill across the slab cannot and
|
||||
// should not walk onto it.
|
||||
const sealed = fv.levels[0]!.rooms.map((r) => r.id).filter((id) => !reached.has(id));
|
||||
assert.deepEqual(sealed, [], "sealed rooms in the hangar");
|
||||
});
|
||||
|
||||
it("guards the mezzanine edge, which is a 4.4 m drop onto concrete", () => {
|
||||
// On the deck's own level — the balustrade belongs to it, not to the slab
|
||||
// below, which is the whole point of the deck being a level.
|
||||
assert.ok(fv.blocked("level-mezz", { x: 39.0, z: 25.0 }, { x: 37.0, z: 25.0 }, 0.3));
|
||||
assert.ok(fv.blocked("level-mezz", { x: 45.0, z: 21.0 }, { x: 45.0, z: 19.0 }, 0.3));
|
||||
});
|
||||
|
||||
/**
|
||||
* And the deck is genuinely up there. `Plan` resolves a seat's `y` from its
|
||||
* level's floor, so this is the assertion that would have caught the original
|
||||
* defect: authored as a ground-floor room, every one of these was at y = 0
|
||||
* with a chair drawn 4.4 m above it.
|
||||
*/
|
||||
it("stands its occupants on the deck rather than on the concrete", () => {
|
||||
for (const id of ["mezz-01", "mezz-02", "mezz-03"]) {
|
||||
assert.equal(fv.seat(id)?.y, 4.4, `${id} is not on the deck`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Both shipped packs declare where they stand, and the two 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");
|
||||
});
|
||||
|
||||
it("put one high in the air and one on the ground", () => {
|
||||
assert.ok(
|
||||
(LUMBRIDGE_HQ.site?.elevation ?? 0) > 100,
|
||||
"the tower office should be a long way up",
|
||||
);
|
||||
assert.ok(
|
||||
(FRONTIER_VALLEY.site?.elevation ?? 999) < 20,
|
||||
"the hangar should be near the ground",
|
||||
);
|
||||
});
|
||||
|
||||
it("carry headings inside the compass", () => {
|
||||
for (const pack of [LUMBRIDGE_HQ, FRONTIER_VALLEY]) {
|
||||
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
|
||||
// coordinate typo that put one in Nevada would otherwise render fine.
|
||||
for (const pack of [LUMBRIDGE_HQ, FRONTIER_VALLEY]) {
|
||||
const site = pack.site;
|
||||
assert.ok(site);
|
||||
assert.ok(site.lat > 37.2 && site.lat < 38.2, `${pack.id} latitude ${site.lat}`);
|
||||
assert.ok(site.lng > -122.8 && site.lng < -121.8, `${pack.id} longitude ${site.lng}`);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user