1
0

feat: real fire on the boards, the LA office as a twin, and a night sky worth reading

The world stops being a simulation of California and starts being California.

**THE PROMOTION GATE WAS THE FIRST COMMIT, BEFORE ANY ORANGE PIXEL EXISTED.**
On today's live store the SoCal board contains 22 incidents. Every one has NULL
acreage and fifteen are nameless LA County dispatch numbers. Drawn naively that
is 22 orange marks over Los Angeles on a day nothing is burning — in a frame that
contains no other warm colour, so one glyph would be the most salient object on
the board and twenty-two would spend its credibility permanently.

`acres >= 10 AND contained < 80 AND type != 'RX' AND last_seen = max(last_seen)`
returns 0 on SoCal, exactly 5 on California, 0 on the Bay — same body, same day,
three correct answers. The empty board is a deliverable, not a fallback: it says
"No active fire on this board — CAL FIRE and WFIGS, just now", states that 21
records were gated and why, lists the largest fires burning OUTSIDE the frame
with distances, and counts the hot pixels it is deliberately not drawing.

**The privacy leak is structurally impossible rather than carefully avoided.**
cloud-1 serves a projection; the four home-relative columns never leave that box.
`observations.threat` was the one that nearly got through — it is
`(16/distance)^2 x log10(acres) x momentum x containment x wind-alignment`, so
with acreage and containment public it inverts to a distance circle around a
house and three fires give an intersection. A grep of the built bundle for
distance_km, bearing_deg, threat, 7762 and the street name returns nothing.

**Deliberately not used, and both would have produced a confident wrong answer:**
the store's `air` table retains only the last parameter of each poll, so all 78
rows read "Good" while the live feed reports ozone 101 "Unhealthy for Sensitive
Groups" — haze driven off it would clear the sky during a smoke event. And
`weather` is written only inside the NWS alerts loop, so a quiet day stores no
wind at all. Tera's own per-region NWS wind is already correct and already what
the clouds drift on.

Satellite detections are drawn as evidence and never as incidents. The permanent
industrial heat source 4.7 km from the owner's house is flagged persistent and
dropped, asserted by a test that first proves it is present in the fixture.
MODIS integer confidence and VIIRS string confidence are branched on `sat`.

**The LA office is a twin.** Its entire authored second storey — Model Loft,
Model Bay, The Materials Room, 430 lines nobody had ever stood in — is reachable
on foot: a walker crosses level-1 to level-2 in 73 fixed steps, floorY 0 to 5,
verified against the real pack rather than a synthetic plan. Its two studio
devices read real hardware through a field-allowlisted bridge: mute, volume and
reachability only. Never level, because there is no passive level upstream and
obtaining one would record a room with people in it. Never dB, because upstream
is gainPct across four different native scales. The bridge refuses all writes.

Fixed at its root: an anonymous visitor was getting permanently at-rest
instruments backing off against a 401. The tier moves into `createDeviceSource`,
so anon gets the living simulator three file headers already promised.

**Item 8 is closed, not fixed, and the correction is the point.** The Bay Area
"stutter" was GPU power management — the card sat at 500 MHz of 2725 through
every run that reproduced it, 4096/2048/1024/256 shadow maps all render in
1.21-1.31 ms, and two consecutive runs over a byte-identical dist gave 33.4 then
16.7. The allowance is removed and the cell is back to 16.7. Geometry is the
gate; frame time is advisory.

Item 7 was re-scoped after measuring: 1,069,006 of the Bay Area's 2,265,056
triangles were the second submission of the same buildings into the shadow pass.
Mobile now has its own triangle caps and bay-area mobile draws 1,266,096.

Also: bridges and the freeway corridor light up at night as emission, not lights
— 1,614 deck lamps and 18 tower heads on the Bay in two draw calls. The single
change that made US-101 legible was moving its edge lines from the lit material
to the unlit one: retroreflective paint, the argument the SFO night frame already
makes. California went 21,991 lamps to 4,051, clustered at the 17 town districts,
because a rural interurban corridor genuinely is unlit.

Tests 1137 -> 1340, server 280. All ten budget cells pass on first attempt with
no cap raised.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-22 18:01:11 -07:00
parent b7f5c41da5
commit b25f217e3e
91 changed files with 15111 additions and 401 deletions
+79 -32
View File
@@ -138,44 +138,91 @@ Nothing here is geocoded and nothing can be. These are numbers you type, like
every other number in a pack — see CONTRACT.md §8 for why a coordinate's
provenance is a licensing question in this repo.
## Levels, and the one thing you cannot do with a second one
## Levels, and how somebody gets between two of them
A `Level` is a storey: an `elevation` (floor-to-**floor**, not floor-to-ceiling),
a default wall height, and its own floorplan in its own frame with its slab at
zero. `Plan` adds the elevation to every coordinate on the level exactly once, so
you author an upper floor without holding 5 m in your head.
> ### ⚠️ A walker cannot change levels. Do not author a staircase.
>
> **This is the single most expensive thing to discover by building it.** The
> walk controller is hard-locked to the level it spawned on, in two places:
>
> - `src/interiors/walker.ts` rejects any state whose `levelId` differs from the
> spawn level — a restored or proposed state on another storey is refused as
> *"walker snapshot is incompatible or invalid"*.
> - `src/interiors/officeWalker.ts` **throws** if the level it is on stops
> resolving — *"office walker lost level"*.
>
> There is no vertical transition anywhere in the engine: no stair traversal, no
> lift, no level handoff, and nothing that changes `levelId` after a spawn. So a
> flight of stairs you author is a flight of stairs the collider will never let
> anybody climb, however carefully you model it. `mateo-court.ts` has a real
> dog-leg stair standing in its courtyard, drawn as a floor finish with a 1.2 m
> gap in the balustrade at the head of it, and **its upper floor is unreachable
> on foot**. That is a known, accepted state and not a bug in the pack.
>
> Fixing it is an **engine** change — a cross-level walker state, a transition
> volume, and a collider that knows about both storeys — and it is out of scope
> for a pack author. Until it lands:
>
> - Author a second storey for what it *is*: a place the camera flies to, which
> viewpoints do perfectly well. `mateo-court` gives its upper floor five of
> them.
> - Give each level a viewpoint of its own so nothing up there is unreachable by
> every means at once.
> - Do not spend a day on treads. `viewpoints[0]` is the walk spawn, and it is on
> exactly one level; everything else on that level is walkable and everything
> on any other level is not.
### The way between two storeys is a `Transition`
A `Level` on its own is a place the camera can fly to. To make it a place
somebody can **walk** to, author a `Transition` on the `Office` — not on either
floorplan, because it is the one record in this format that is a fact about two
storeys at once and putting it on either would make the other one's copy a
restatement.
```ts
transitions: [{
id: "stair",
kind: "stair", // or "lift"
width: 1.2,
surface: STEEL,
lower: {
levelId: "level-1",
footprint: [/* a small patch of floor at the bottom */],
landing: { x: 10.2, z: 9.2 },
},
upper: {
levelId: "level-2",
footprint: [/* the gap in the balustrade at the top */],
landing: { x: 9.25, z: 10.4 },
},
// Optional. Absent means one straight flight between the two landings.
legs: [
{ to: { x: 14.1, z: 9.2 }, rise: 1 }, // a flight
{ to: { x: 14.1, z: 10.4 }, rise: 0 }, // a half landing
{ to: { x: 9.25, z: 10.4 }, rise: 1 }, // and the flight back
],
}]
```
**Standing on a footprint is the input.** There is no key to press, which is the
single most important thing to know when you size one. A footprint the size of
your whole stair means that walking *under* the flight takes you up it; the
right size is the bottom couple of metres, and at the top, the gap you arrive
through and nothing else.
That upper footprint is doing a second job that is easy to miss. A gap in a
balustrade is an unguarded edge, and the moment an upper floor is walkable
somebody will walk off it. A footprint covering the gap catches them and sends
them downstairs, which is what the gap is for.
`rise` on a leg is that leg's **share** of the total climb, not a height. The
height is already known exactly — it is the difference between the two levels'
`elevation`s — and stating it twice is how a pack ends up with a staircase that
does not reach its own landing. A flat half landing is `rise: 0`. `Plan`
normalises the shares, so two flights written `{ rise: 1 }` and `{ rise: 1 }`
mean half each.
**You do not author treads.** `src/interiors/shell.ts` builds them from this
record: it divides each climbing leg into a whole number of ~178 mm risers and
lays a tread on each, which is why `mateo-court`'s 2.5 m flights come out at the
fourteen risers its own comment always claimed. The drawn flight and the flight
the walk controller climbs are the same list of points, so a staircase nobody
can climb is not expressible.
Three things `Plan` will refuse, all of which drop the transition **whole**
rather than in pieces — half a staircase is a hole in a collider:
- a footprint outside its own level's bounds, or with a wall running *through*
it. A wall along its edge is fine and expected: stairs go against walls.
- a landing outside its own footprint, or pressed so close to a wall that a
walker of the default radius could not stand on it.
- an `upper` that is not actually above `lower`.
Two things it will not do for you:
- **The treads do not collide.** `Plan` derives collision from the wall list
alone, so like every prop in every pack, a flight can be walked through at its
low end. That is the engine's existing physics rather than a property of this
record.
- **It will not find a route.** A footprint you cannot walk to is a way up
nobody reaches. Check it the way `src/test/packs/mateoContent.test.ts` does.
Still worth doing, transition or no transition: give every level a viewpoint of
its own, so nothing up there is unreachable by every means at once.
## Rooms are slabs. Walls are segments.
+49 -9
View File
@@ -12,7 +12,7 @@
* without invalidating those addresses.
*/
import { CANONICAL_CAPABILITIES, type DeviceDeclaration } from "../devices/types.ts";
import type { DeviceCapability, DeviceDeclaration } from "../devices/types.ts";
import type {
AssetId,
DeskBank,
@@ -286,8 +286,10 @@ const PROPS: Prop[] = [
* one by omission.
*/
const DISCLOSURE =
"Simulated studio hardware. These readings are demonstration data, never live " +
"presence data.";
"Simulated studio hardware in an authored room. Lumbridge's San Francisco " +
"studio is a place this pack describes, not a room anybody is standing in: " +
"there is no hardware in San Francisco to read. These readings are " +
"demonstration data, never live presence data.";
/**
* Two devices: the mic on the desk and the speaker on the computer.
@@ -297,11 +299,47 @@ const DISCLOSURE =
* `agent-mic` 200 mm and the mic moves with it, because there was never a second
* number to forget.
*
* `capabilities` is `CANONICAL_CAPABILITIES[kind]` rather than a hand-written
* list. Two studios authored months apart should describe the same instrument
* the same way — the device panel builds its controls by walking this array, and
* the arena's observation width is the sum of them.
* ### This studio stays simulated, and says so louder
*
* `mateo-court`'s two studio instruments read a real desk in the LA Studio. This
* one does not, and it is not going to: every machine in that inventory is
* physically in that one room, and there is no sensor, camera or microphone
* anywhere in the fleet at this address. Inventing an SF feed — or, worse,
* quietly relabelling LA's readings — would be exactly the
* `first-party-sensor` / `simulated` confusion `DeviceProvenance` exists to
* prevent, in the direction that matters. So the answer is the honest one and it
* is written into the sentence a viewer actually reads: *this is a room nobody
* is standing in*. The day an SF room exists, `provenance` and `ranges` change
* and nothing else here moves.
*
* ### The capability list matches LA's exactly, including the omission
*
* `capabilities` used to be `CANONICAL_CAPABILITIES[kind]`. It is now the same
* hand-written pair `mateo-court` declares, which differs from canonical in two
* ways, and both are deliberate:
*
* - **no `level`.** LA's real microphone has no passive level to read — getting
* one records the room — so it declares none. This one *could* invent one, and
* choosing not to is what makes the two studios the same instrument with two
* provenances rather than two different products. A viewer comparing them is
* then comparing where the numbers come from, which is the only interesting
* difference, instead of counting rows.
* - **`mute` on the speaker**, which canonical omits and both real and simulated
* speakers plainly have.
*
* `ranges` restates the global default rather than overriding it, which looks
* redundant and is not: stating the unit is now part of how a studio describes
* itself, and the interesting thing about the pair is that this one really is
* decibels and LA's really is a percentage of a mixer's travel.
*/
const STUDIO_MIC_CAPABILITIES: readonly DeviceCapability[] = ["power", "mute", "gain"];
const STUDIO_SPEAKER_CAPABILITIES: readonly DeviceCapability[] = [
"power",
"mute",
"volume",
"playback",
];
const DEVICES: DeviceDeclaration[] = [
{
id: "sf-desk-mic",
@@ -317,7 +355,9 @@ const DEVICES: DeviceDeclaration[] = [
// sitting where the mic is pointed without being told a coordinate.
seatId: "sf-agent-01",
},
capabilities: CANONICAL_CAPABILITIES.mic,
capabilities: STUDIO_MIC_CAPABILITIES,
// A desk condenser's preamp, in decibels, because that is what it would be.
ranges: { gain: { min: -12, max: 36, initial: 12, unit: "dB" } },
provenance: "simulated",
disclosure: DISCLOSURE,
},
@@ -332,7 +372,7 @@ const DEVICES: DeviceDeclaration[] = [
roomId: "live-work",
seatId: "sf-agent-01",
},
capabilities: CANONICAL_CAPABILITIES.speaker,
capabilities: STUDIO_SPEAKER_CAPABILITIES,
provenance: "simulated",
disclosure: DISCLOSURE,
},
+214 -38
View File
@@ -52,29 +52,26 @@
* balustrade authored as a prop is a balcony you can walk off.
*
* The **stair**, which is the one thing that had to be argued about. It stands
* in the courtyard, outdoors, which is the type's signature move — and it is a
* room with no treads in it, because nothing in the `src/assets/office/`
* catalogue is a stair. So `stair` is a floor finish the shape of the flight,
* exactly as the reference pack's `stair-core` is, and the way up is modelled as
* the **gap between two balustrade walls** at the head of it rather than as
* geometry. A pack that wants treads registers `acme:stair.dogleg` with
* `defineAsset` and drops it in; nothing here has to move for that to work.
* in the courtyard, outdoors, which is the type's signature move. The `stair`
* room is still a floor finish the shape of the flight — the slab the dog-leg
* stands on and the pad at the bottom of it — and the treads on top of it are
* built by `interiors/shell.ts` from the `Transition` at the foot of this file
* rather than authored as a prop, so the drawn flight and the walked one are
* the same list of points.
*
* ### ⚠️ Nobody can walk up it, and modelling it better will not change that
* ### You can walk up it now, and that is what level 2 was waiting for
*
* **Level 2 of this building is unreachable on foot**, and that is an engine
* fact rather than an authoring one. `interiors/walker.ts` refuses any state
* whose `levelId` differs from the one it spawned on, and
* `interiors/officeWalker.ts` throws outright if its level stops resolving.
* There is no transition volume, no lift and nothing anywhere that changes a
* walker's level after the spawn — so treads, a wider flight or a landing at the
* head of it would all be geometry the collider still refuses to carry anybody
* across. The upper floor is reached by the five viewpoints that frame it, which
* is the whole of what this build supports.
* This file used to carry a warning here saying that **level 2 was unreachable
* on foot** and that modelling the stair better would not change it, because
* `interiors/walker.ts` refused any state on another storey. That is no longer
* true: `levelId` is walker state, `TRANSITIONS` at the bottom of this file says
* where the way up is, and `interiors/officeWalker.ts` runs the climb as
* presentation. The Model Loft, the Model Bay and the Materials Room are places
* you can stand in.
*
* Do not spend a day on this one. It is written up in `README.md` under
* "Levels, and the one thing you cannot do with a second one", and it is an
* engine change when somebody takes it on.
* The five viewpoints that frame the upper floor are still there and still
* worth having — a camera reaches a room faster than a pair of legs — but they
* are no longer the only way up.
*
* ### Why the prop list is long, and why it is long in *kinds*
*
@@ -107,7 +104,11 @@
* consequences are worked through, and `interiors/types.ts` on `OfficeSite`.
*/
import { CANONICAL_CAPABILITIES, type DeviceDeclaration } from "../devices/types.ts";
import {
CANONICAL_CAPABILITIES,
type DeviceCapability,
type DeviceDeclaration,
} from "../devices/types.ts";
import type {
AssetId,
DeskBank,
@@ -119,6 +120,7 @@ import type {
Prop,
Room,
Seat,
Transition,
Viewpoint,
Wall,
Yaw,
@@ -638,10 +640,10 @@ const ROOMS: Room[] = [
{
id: "stair",
name: "The Stair",
// A floor finish the shape of the flight, and no treads — the kit has no
// stair asset, and inventing an id for one would resolve to a placeholder
// box in the middle of the yard. The reference pack's `stair-core` is the
// same admission with a wall round it.
// The slab the flight stands on, and the pad at the bottom of it. The treads
// themselves are not a room and not a prop: `interiors/shell.ts` builds them
// from the `Transition` at the foot of this file, so the flight that is
// drawn is the flight the walk controller climbs. This is what is under it.
outline: rect(COURT_W, COURT_N, STAIR_E, STAIR_S),
floor: STEEL,
ceiling: null,
@@ -1736,6 +1738,80 @@ const DISCLOSURE =
"Simulated studio hardware. These readings are demonstration data, never live " +
"presence data.";
/**
* The two studio instruments are real, and everything about how they are
* declared follows from what that costs.
*
* `press-mic` and `press-speaker` are still the props they always were, in a
* press room this pack invented. What has changed is where their *readings* come
* from: `TERA_DEVICES_SOURCE=first-party` points `server/src/devices/firstParty.ts`
* at a real desk in the LA Studio, and these two ids are the two the bridge
* publishes. So the placement is authored and the reading is measured, and the
* disclosure below says exactly that rather than letting a viewer assume both
* halves are one or the other. `src/tools/geo.ts` labels MEASURED, PLACEMENT and
* DRAWN separately for the same reason; this is that distinction at building
* scale.
*
* ### The ids are the upstream's, not names we chose
*
* `mic-yeti` and `speaker` are the keys `GET /api/la-studio/state` publishes,
* and the bridge binds a reading to a declaration **by id**. A prettier id here
* would be a device that declares itself live and is permanently unreachable,
* which is worse than a simulated one. They read oddly in a floorplan; that is
* the price of the binding being one lookup rather than a mapping table nobody
* remembers to update.
*
* ### No `level`, and it is the most important line in this file
*
* `CANONICAL_CAPABILITIES.mic` is `power, mute, gain, level`, and this mic
* declares the first three. There is no passive level upstream: obtaining one
* means `POST /levels`, which records one and a half to three seconds of audio
* per microphone. A level meter that breathes is the single most convincing
* thing a twin could show and it would be a continuously-open microphone in a
* room with people in it, looking like a feature the entire time it did it. The
* meter row hides itself on a missing reading, which is what `undefined` has
* always meant on `DeviceState`.
*
* ### The gain range is a percent because the gain *is* a percent
*
* Upstream reports `gainPct`, normalised over four different native scales — a
* Yeti Nano's ALSA travel is 050, an Anker's is 0100, a ThinkPad's is 063.
* The global default range is decibels, and 68 % of a Yeti's travel is not any
* number of decibels. Declaring the range here is a pack author saying what the
* number means, and it is the only condition under which the bridge will emit a
* gain reading at all — without it, fail-closed, there is no gain row.
*
* ### And a second sentence for the path that is not live
*
* An anonymous visitor cannot read the device route — it is a room somebody is
* standing in — so they get the local simulator running this declaration.
* `simulatedDisclosure` is what the panel prints instead the moment a reading is
* synthetic, so "live, LA Studio" never appears under a number invented one
* millisecond earlier in somebody's browser.
*/
const STUDIO_DISCLOSURE =
"Live reading from the LA Studio's own hardware, mirrored read-only over the " +
"operator's network. The room it stands in here is authored; the number is not.";
const STUDIO_SIMULATED_DISCLOSURE =
"Simulated: this viewer is not reading the LA Studio's hardware, so these " +
"numbers are demonstration data generated in your own browser.";
/** Mute and gain, and deliberately not level. See the note above. */
const STUDIO_MIC_CAPABILITIES: readonly DeviceCapability[] = ["power", "mute", "gain"];
/**
* The canonical speaker list plus `mute`, which the canonical list omits and the
* upstream actually reports. `playback` stays because a speaker has a transport
* whether or not this deployment reads one.
*/
const STUDIO_SPEAKER_CAPABILITIES: readonly DeviceCapability[] = [
"power",
"mute",
"volume",
"playback",
];
/**
* Four devices in two places: the desk in reception, and the two capture marks
* in the media studio.
@@ -1746,11 +1822,10 @@ const DISCLOSURE =
* second number to forget. That is the rule `Prop.seat` follows for chairs and
* the one CONTRACT.md follows for sites, one level further in.
*
* `capabilities` is `CANONICAL_CAPABILITIES[kind]` rather than a hand-written
* list, and that matters more than it looks: the device 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 describing the same instrument
* differently would quietly change the shape of an RL observation.
* The two in reception are **simulated** and say so. The two in the media studio
* are **first-party** and say something different. Keeping both in one pack, with
* the disclosure under each instrument rather than in a header over all four, is
* the whole point: the sentence has to travel with the reading it is about.
*
* `seatId` is an address and not a position. It says which standing or sitting
* place each unit serves, which is what lets a consumer ask whether anybody is
@@ -1778,24 +1853,33 @@ const DEVICES: DeviceDeclaration[] = [
disclosure: DISCLOSURE,
},
{
id: "la-studio-mic",
// Upstream's own id for the Blue Yeti Nano on the studio desk.
id: "mic-yeti",
kind: "mic",
label: "Studio mic",
assetId: MIC,
anchor: { levelId: "level-1", propId: "press-mic", roomId: "press", seatId: "media-01" },
capabilities: CANONICAL_CAPABILITIES.mic,
provenance: "simulated",
disclosure: DISCLOSURE,
capabilities: STUDIO_MIC_CAPABILITIES,
// 0100 of the mixer's own travel. `initial` is where an unread simulator
// starts, not a reading: a live one is whatever the desk is set to.
ranges: { gain: { min: 0, max: 100, initial: 60, unit: "%" } },
provenance: "first-party-sensor",
disclosure: STUDIO_DISCLOSURE,
simulatedDisclosure: STUDIO_SIMULATED_DISCLOSURE,
},
{
id: "la-studio-speaker",
// Upstream publishes its chosen sink under the literal key `speaker` as well
// as under the sink's own name. `speaker` is the one that is always present,
// so it is the one that cannot silently stop binding when a sink changes.
id: "speaker",
kind: "speaker",
label: "Studio monitor",
assetId: SPEAKER,
anchor: { levelId: "level-1", propId: "press-speaker", roomId: "press", seatId: "media-02" },
capabilities: CANONICAL_CAPABILITIES.speaker,
provenance: "simulated",
disclosure: DISCLOSURE,
capabilities: STUDIO_SPEAKER_CAPABILITIES,
provenance: "first-party-sensor",
disclosure: STUDIO_DISCLOSURE,
simulatedDisclosure: STUDIO_SIMULATED_DISCLOSURE,
},
];
@@ -2573,11 +2657,103 @@ const LEVEL_2: Level = {
},
};
/**
* The way up, and the record that finally makes the upper floor a place.
*
* Level 2 of this building — the Model Loft, the Model Bay, the Materials Room,
* two desk banks and twenty-four props — was authored and then unreachable on
* foot, because `interiors/walker.ts` refused any state on a storey other than
* the one it spawned on. That is fixed, and this is the record that uses it.
*
* ### The dog-leg is the one the balustrade already implied
*
* The shape was never free. The gap in the rail is 1.2 m of nothing between
* `rail-west-n` and `rail-west-s`, at z 9.8 to 11.0 on the yard's west line, and
* a flight arriving there is arriving **westbound**. So the second flight runs
* east to west along the south half of the stair's footprint, the half landing
* is at its east end, and the first flight runs west to east along the north
* half — which is exactly what the constants at the top of this file describe
* and what `STAIR_HEAD_N` was put there for. Nothing about the building moved to
* accommodate this; the transition states what was already drawn.
*
* Two and a half metres of rise per flight comes out at fourteen risers each at
* the shell's 178 mm, which is the number this file's own comment claimed before
* there were any treads to count.
*
* ### The footprints are small on purpose
*
* Standing on one *is* the input — there is no key to press — so a footprint the
* size of the whole stair would mean walking under the flight took you up it.
* The lower one is the bottom two metres, reachable by stepping north out of the
* yard; the upper one is the gap in the balustrade and nothing else, which is
* also what stops a walker strolling off a 5 m drop onto pavers. That gap has
* been an unguarded edge since the loggia was authored and nobody could ever
* reach it to find out.
*
* ### What still does not collide
*
* The treads are drawn geometry and, like every prop in every pack in this repo,
* they are not in the collider — `Plan` derives collision from the wall list
* alone. A walker crossing the north half of the stair's footprint passes
* through the low end of the first flight in the same way it passes through a
* desk. That is the engine's existing physics rather than something this record
* introduces, and the fix for it is a collider that knows about furniture.
*/
const TRANSITIONS: Transition[] = [
{
id: "stair",
kind: "stair",
label: "The Stair",
// Steel, like the floor finish it stands on, and like the balustrade it
// arrives through.
surface: STEEL,
// 1.2 m, which is the width of the gap in the rail at the head of it.
width: 1.2,
lower: {
levelId: "level-1",
// The bottom of the flight, open to the yard on its south side. It stops
// short of the wall on the west and the wall on the north because a
// footprint is a place to stand, not a place to be inside masonry.
footprint: [
{ x: 9.95, z: 8.75 },
{ x: 11.6, z: 8.75 },
{ x: 11.6, z: 10.5 },
{ x: 9.95, z: 10.5 },
],
landing: { x: 10.2, z: 9.2 },
},
upper: {
levelId: "level-2",
// The gap in the balustrade, and only the gap: 9.15 to 9.95 in x covers
// both sides of the rail line at 9.6, and 9.88 to 10.92 sits inside the
// 9.8-to-11.0 opening without touching either rail's end.
footprint: [
{ x: 9.15, z: 9.88 },
{ x: 9.95, z: 9.88 },
{ x: 9.95, z: 10.92 },
{ x: 9.15, z: 10.92 },
],
landing: { x: 9.25, z: 10.4 },
},
legs: [
// Up the north half, west to east: 3.9 m of run for 2.5 m of rise.
{ to: { x: 14.1, z: 9.2 }, rise: 1 },
// The half landing, at the east end, against the yard-shop side of the
// footprint. Flat, so its share of the rise is zero.
{ to: { x: 14.1, z: 10.4 }, rise: 0 },
// Back west along the south half, out through the rail gap onto the
// loggia. The last tread is the loggia's own deck.
{ to: { x: 9.25, z: 10.4 }, rise: 1 },
],
},
];
export const MATEO_COURT: Office = {
id: "mateo-court",
name: "LA HQ · Office",
levels: [LEVEL_1, LEVEL_2],
viewpoints: VIEWPOINTS,
transitions: TRANSITIONS,
/**
* The Arts District, on the board `cities/socal.ts` draws. See
* `MATEO_COURT_SITE` above for where the three numbers come from and which of