1
0

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:
2026-08-06 23:30:45 -07:00
parent d8afc42d15
commit 06455f7424
15 changed files with 2061 additions and 75 deletions
+48 -3
View File
@@ -194,14 +194,59 @@ export async function createScene(
const [eastX, southZ] = world.project(city.bounds.minLat, city.bounds.maxLng);
const boardSpan = Math.max(Math.abs(eastX - westX), Math.abs(southZ - northZ));
/**
* How far the board reaches **from the scene origin**, which is not the same
* as how big it is.
*
* Scene space is centred on `city.center` — the city — and the Bay Area board
* runs forty kilometres down the peninsula from there, so the origin is
* nowhere near the middle of it. The furthest corner is 0.94 spans out where
* the half-diagonal is only 0.65, and anything sized off the half-diagonal is
* therefore too small by half.
*
* The satellite dome is centred on the origin, because that is where its look
* angles were computed for, so this is the radius it has to clear.
*/
const boardRadius = Math.max(
Math.hypot(westX, northZ),
Math.hypot(eastX, northZ),
Math.hypot(westX, southZ),
Math.hypot(eastX, southZ),
);
const kit = createSceneKit({
scene,
dom: stage.renderer.domElement,
fov: 42,
near: 0.1,
far: boardSpan * 3,
/**
* Everything, at the worst pose, plus room.
*
* The furthest thing from the camera is the back of the satellite dome seen
* from a chapter at the far end of the board: `maxChapterOffset` (0.94
* spans) + `maxDistance` (2.0) + the dome radius (about 0.99) — call it 3.9.
* At 3.0 the sky was being clipped from any off-centre chapter, which is
* most of them.
*
* It also now sits at the fog's far plane, which is the honest statement of
* the invariant: nothing should be cut off before it has fully faded out.
*/
far: boardSpan * 4,
minDistance: Math.max(4, boardSpan * 0.02),
maxDistance: boardSpan * 1.5,
/**
* Far enough out to be **above the satellites**, which is what the extra
* half-span buys.
*
* The satellite dome is at 0.7 spans (`engine/satellites.ts`), so at 1.5 the
* camera was always inside the constellation and could only ever look up
* through it. At 2.0 the far end of the zoom is outside it looking down, with
* the whole dome in frame at this field of view and the board still filling
* about two thirds of the screen.
*
* The far plane already covers it: the furthest thing from the camera is then
* the back of the dome at 2.7 spans, against `far` at 3.0.
*/
maxDistance: boardSpan * 2.0,
shadowExtent: boardSpan * 0.75,
shadowFar: boardSpan * 2.2,
});
@@ -235,7 +280,7 @@ export async function createScene(
let satelliteLayer: SatelliteLayer | null = null;
if (options.satellites) {
satelliteLayer = createSatelliteLayer(boardSpan);
satelliteLayer = createSatelliteLayer(boardRadius);
scene.add(satelliteLayer.group);
}