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
+32 -3
View File
@@ -66,9 +66,38 @@ going *down* is what makes the winding rule counter-intuitive:
a rectangle, and which has a *negative* shoelace area over `(x, z)`.
- Get it wrong and nothing breaks: `Plan` silently re-winds a reversed polygon.
An office has no orientation on the earth. Calling an edge "north" is a
convenience for reading your own file. Offices get no `Atmosphere`, no sun and
no sky (CONTRACT.md §4); interior lighting is a fixed rig owned by the scene.
By default an office has no orientation on the earth, and calling an edge
"north" is a convenience for reading your own file. A pack with no `site` gets
no `Atmosphere`, no sun and no sky (CONTRACT.md §4); interior lighting is a
fixed rig owned by the scene, and that is a supported, permanent state — you can
author a whole building without owning a coordinate.
Say where the building stands and the convenience becomes a fact:
```ts
site: {
lat: 37.7756,
lng: -122.3186,
elevation: 4, // metres above the ground OUTSIDE, not above sea level
heading: 0, // compass bearing, in degrees, that the pack's Z points along
label: "Alameda Point",
},
```
Then the pack gets the real sun for that place at the app's clock, a sky, and a
horizon `elevation` metres below the level-0 floor. **`heading` is the field that
matters most and the easiest to leave wrong**: it is what decides which of your
walls the light actually comes through. `0` means your "north" really is north.
`elevation` is the other one worth thinking about, because it is what the horizon
is measured from — the difference between an office on the 48th floor and a shed
on an airfield is one number, and it is this one. Both shipped packs are worked
examples: `lumbridge-hq.ts` is 188 m up and rotated 205°, `frontier-valley.ts` is
4 m up and square to the compass.
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.
## Rooms are slabs. Walls are segments.
+692
View File
@@ -0,0 +1,692 @@
/**
* Frontier Valley — a startup in a hangar at Alameda Point.
*
* The second office pack, and it exists to prove the format describes more than
* one kind of building. `lumbridge-hq.ts` is the dev kit: a corridor, fifteen
* rooms, a grid, everything a commercial floor plate has. This is the opposite
* building in every respect that matters, and the contrast is the point.
*
* ### Why a hangar, and why here
*
* Alameda Point is the former Naval Air Station Alameda, decommissioned in 1997:
* a mile of runway, a seaplane lagoon, and a row of enormous steel-framed
* hangars that have spent the last quarter century being rented to distilleries,
* film crews and companies that need a very large room cheaply. Putting a
* startup in one is not a conceit — it is the single most characteristic thing
* that happens on that piece of land.
*
* It also gives the site field something to say. `lumbridge-hq` is 188 m up a
* tower with the horizon far below it; this is **four metres above reclaimed
* ground on a flat island**, looking across the estuary at the city that the
* other office is inside. Same engine, same clock, same sun — and the two feel
* nothing like each other, which is the whole argument for `OfficeSite`.
*
* ### One level, one room, and a mezzanine that is furniture
*
* A hangar is a single volume. There is no corridor here because there is
* nothing to connect: the meeting rooms are freestanding boxes dropped on the
* slab, with their own low lids, and everything else is open floor. That is
* expressible in this format without a single new feature, which is worth
* knowing — the format was written against a cellular office and turns out to
* describe a shed just as well.
*
* ### The coordinate frame
*
* Metres, `1 unit = 1 m`, floor on the XZ plane with +Y up. Origin at the
* north-west corner. +X east, +Z south, so in plan view +Z runs down the page.
* The one difference from the reference pack is that here "north" is a genuine
* claim: `site.heading` is 0, because the hangars at Alameda Point really are
* laid out square to the compass along the old runways.
*/
import type {
AssetId,
DeskBank,
Level,
Office,
Opening,
Outline,
Point2,
Prop,
Room,
Seat,
Viewpoint,
Wall,
Yaw,
Zone,
} from "../interiors/types.ts";
// ---- The shed -------------------------------------------------------------
/**
* A hangar, in three numbers.
*
* 54 x 30 m is a small one by Alameda standards — the surviving hangars on the
* seaplane lagoon run to twice this — but it is a plausible sublet, and it is
* already three times the floor area of the reference office's desk floor with
* nothing standing in it.
*/
const WIDTH = 54.0;
const DEPTH = 30.0;
/**
* Nine metres to the underside of the trusses.
*
* This is the number that makes it a hangar rather than a warehouse-themed
* office. A commercial storey is 2.8 m; at 9 m the roof is somewhere you look
* *up* at, the meeting boxes read as objects standing in a room rather than as
* rooms carved out of one, and a mezzanine is a thing you can put under it.
*/
const RIDGE = 9.0;
/** The freestanding boxes get their own low lids. A booth in a shed is a box. */
const BOX_CEILING = 3.0;
const EXT_THICKNESS = 0.35;
const INT_THICKNESS = 0.12;
const EXT_FACE = EXT_THICKNESS / 2;
const INT_FACE = INT_THICKNESS / 2;
const DISPLAY_OFFSET = 0.07;
const BOARD_OFFSET = 0.06;
/**
* The mezzanine deck.
*
* It is a `Level`, and getting there took one wrong turn worth recording. A deck
* inside a single volume reads like furniture, so it was first authored as a
* `Room` on the ground floor with everything on it carrying `elevation: 4.4`.
* That is not expressible: a `Room` is a floor *finish* and has no height, so
* the deck's slab lay flat on the concrete while its chairs floated four and a
* half metres over it, its glass balustrade fenced off a patch of ground-floor
* slab, and anybody sitting at `mezz-01` stood on the concrete underneath their
* own chair.
*
* A `Level` is the only thing in this format that carries a floor height, so the
* deck is one — with a storey height of `RIDGE - MEZZ_HEIGHT`, because what is
* above it is the same roof.
*/
const MEZZ_W = 38.0;
const MEZZ_N = 20.4;
const MEZZ_HEIGHT = 4.4;
// The three freestanding boxes along the west end.
const BOX_1_W = 3.0;
const BOX_1_E = 10.2;
const BOX_2_W = 11.4;
const BOX_2_E = 17.4;
const BOX_N = 3.0;
const BOX_S = 9.6;
// ---- Yaw ------------------------------------------------------------------
const NORTH: Yaw = 0;
const EAST: Yaw = -Math.PI / 2;
const SOUTH: Yaw = Math.PI;
const WEST: Yaw = Math.PI / 2;
// ---- Assets ---------------------------------------------------------------
const DESK: AssetId = "tera:desk.workstation";
const PEDESTAL: AssetId = "tera:desk.pedestal";
const TASK_CHAIR: AssetId = "tera:seat.task-chair";
const LOUNGE_CHAIR: AssetId = "tera:seat.lounge";
const MEETING_TABLE: AssetId = "tera:table.meeting";
const SIDE_TABLE: AssetId = "tera:table.side";
const SHELF: AssetId = "tera:storage.shelf";
const LOCKER: AssetId = "tera:storage.locker";
const DISPLAY: AssetId = "tera:screen.wall-display";
const PLANT: AssetId = "tera:plant.potted";
const TREE: AssetId = "tera:plant.tall";
const PENDANT: AssetId = "tera:light.pendant";
const RUG: AssetId = "tera:rug";
const WHITEBOARD: AssetId = "tera:whiteboard";
const CONCRETE = "tera:concrete.polished";
const WOOD = "tera:wood.plank";
const CARPET_ACCENT = "tera:carpetAccent.broadloom";
const PAINT = "tera:paint.matt";
const ACCENT_PAINT = "tera:plasterAccent.deep";
const GLASS = "tera:glass.curtain";
const STEEL = "tera:steel.panel";
const FELT = "tera:felt.acoustic";
// ---- Helpers --------------------------------------------------------------
function rect(x0: number, z0: number, x1: number, z1: number): Outline {
return [
{ x: x0, z: z0 },
{ x: x0, z: z1 },
{ x: x1, z: z1 },
{ x: x1, z: z0 },
];
}
function grid(x0: number, z0: number, columns: number, rows: number, dx: number, dz: number): Point2[] {
const points: Point2[] = [];
for (let r = 0; r < rows; r++) {
for (let c = 0; c < columns; c++) points.push({ x: x0 + c * dx, z: z0 + r * dz });
}
return points;
}
function scatter(
prefix: string,
kind: AssetId,
points: Point2[],
opts: { rotation?: Yaw; elevation?: number; colorKey?: string } = {},
): Prop[] {
return points.map((position, i) => ({
id: `${prefix}-${String(i + 1).padStart(2, "0")}`,
kind,
position,
rotation: opts.rotation ?? NORTH,
elevation: opts.elevation,
colorKey: opts.colorKey,
}));
}
function doorway(start: number, width = 0.9, head = 2.1): Opening {
return { kind: "door", start, width, sill: 0, head };
}
function pane(start: number, width: number, sill = 0.9, head = 2.2): Opening {
return { kind: "window", start, width, sill, head };
}
function archway(start: number, width: number, head = 2.4): Opening {
return { kind: "arch", start, width, sill: 0, head };
}
// ---- Rooms ----------------------------------------------------------------
const ROOMS: Room[] = [
/**
* The slab. One room, fifty-four by thirty, notched around nothing.
*
* Every other "room" in this pack sits on top of this one as a different floor
* finish, and they are authored *after* it so `Plan.roomAt` resolves them
* first. That is the one ordering rule in the format and it is doing real work
* here: in the reference office the floor is a jigsaw of abutting slabs, and
* here it is one slab with rugs on it.
*/
{
id: "floor",
name: "The Floor",
outline: rect(0, 0, WIDTH, DEPTH),
floor: CONCRETE,
ceiling: null,
},
{
id: "box-standup",
name: "Standup",
outline: rect(BOX_1_W, BOX_N, BOX_1_E, BOX_S),
floor: CARPET_ACCENT,
ceiling: { height: BOX_CEILING, surface: FELT },
},
{
id: "box-quiet",
name: "The Quiet Box",
outline: rect(BOX_2_W, BOX_N, BOX_2_E, BOX_S),
floor: CARPET_ACCENT,
ceiling: { height: BOX_CEILING, surface: FELT },
},
{
id: "workshop",
name: "The Bench",
// Against the east gable, where the big door is. A hardware startup in a
// hangar puts the thing it is building next to the way out.
outline: rect(42.0, 3.0, WIDTH - 0.4, 16.0),
floor: CONCRETE,
ceiling: null,
},
{
id: "galley",
name: "The Galley",
outline: rect(3.0, 22.0, 16.0, DEPTH - 0.4),
floor: WOOD,
ceiling: null,
},
];
// ---- Walls ----------------------------------------------------------------
const WALLS: Wall[] = [
// -- The envelope, nine metres of it --------------------------------------
{
id: "gable-west",
from: { x: 0, z: 0 },
to: { x: 0, z: DEPTH },
thickness: EXT_THICKNESS,
height: RIDGE,
surface: STEEL,
openings: [doorway(13.6, 1.8, 2.4), pane(4.0, 6.0, 3.6, 7.2), pane(19.0, 6.0, 3.6, 7.2)],
},
{
id: "gable-east",
from: { x: WIDTH, z: 0 },
to: { x: WIDTH, z: DEPTH },
thickness: EXT_THICKNESS,
height: RIDGE,
surface: STEEL,
// The hangar door. Twelve metres of it, full height, because that is what a
// hangar is — and it is an `arch` rather than a `door` so the collider
// knows you can walk out onto the apron through it.
openings: [archway(6.0, 12.0, 6.4)],
},
{
id: "eave-north",
from: { x: 0, z: 0 },
to: { x: WIDTH, z: 0 },
thickness: EXT_THICKNESS,
height: RIDGE,
surface: STEEL,
// Clerestory glazing high on the north side: the light a shed actually
// wants, and the sill is well above head height so none of it is a doorway.
openings: [
pane(4.0, 9.0, 5.4, 8.2),
pane(16.0, 9.0, 5.4, 8.2),
pane(28.0, 9.0, 5.4, 8.2),
pane(40.0, 9.0, 5.4, 8.2),
],
},
{
id: "eave-south",
from: { x: 0, z: DEPTH },
to: { x: WIDTH, z: DEPTH },
thickness: EXT_THICKNESS,
height: RIDGE,
surface: STEEL,
// The lagoon side, and the only wall with glazing you can see out of at
// standing height. This is the view the whole building is arranged around.
openings: [
pane(3.0, 10.0, 0.9, 3.4),
pane(16.0, 10.0, 0.9, 3.4),
pane(30.0, 8.0, 0.9, 3.4),
doorway(44.0, 1.8, 2.4),
],
},
// -- The freestanding boxes -----------------------------------------------
//
// Three metres tall inside a nine-metre volume, which is what makes them read
// as objects on the floor. Their fourth sides are open — a box you can see
// into is a box people use.
{
id: "standup-north",
from: { x: BOX_1_W, z: BOX_N },
to: { x: BOX_1_E, z: BOX_N },
height: BOX_CEILING,
surface: ACCENT_PAINT,
},
{
id: "standup-west",
from: { x: BOX_1_W, z: BOX_N },
to: { x: BOX_1_W, z: BOX_S },
height: BOX_CEILING,
surface: ACCENT_PAINT,
},
{
id: "standup-south",
from: { x: BOX_1_W, z: BOX_S },
to: { x: BOX_1_E, z: BOX_S },
height: BOX_CEILING,
surface: GLASS,
openings: [archway(2.4, 2.4, 2.4)],
},
{
id: "quiet-north",
from: { x: BOX_2_W, z: BOX_N },
to: { x: BOX_2_E, z: BOX_N },
height: BOX_CEILING,
surface: ACCENT_PAINT,
},
{
id: "quiet-east",
from: { x: BOX_2_E, z: BOX_N },
to: { x: BOX_2_E, z: BOX_S },
height: BOX_CEILING,
surface: ACCENT_PAINT,
},
{
id: "quiet-south",
from: { x: BOX_2_W, z: BOX_S },
to: { x: BOX_2_E, z: BOX_S },
height: BOX_CEILING,
surface: GLASS,
openings: [doorway(2.6, 0.9, 2.1)],
},
];
// ---- Desks ----------------------------------------------------------------
/**
* Two long benches down the middle of the shed, and nothing against a wall.
*
* A hangar's walls are its least valuable surface — they are steel, they are
* cold, and the good light comes from above. So the desks sit in the volume and
* the edges are left for the things that want an edge.
*/
const DESK_BANKS: DeskBank[] = [
{
id: "fv",
desk: DESK,
chair: TASK_CHAIR,
origin: { x: 22.0, z: 5.2 },
rotation: 0,
columns: 7,
rows: 2,
pitch: 1.7,
rowPitch: 0.85,
facingRows: true,
},
{
id: "fv-b",
desk: DESK,
chair: TASK_CHAIR,
origin: { x: 22.0, z: 10.4 },
rotation: 0,
columns: 7,
rows: 2,
pitch: 1.7,
rowPitch: 0.85,
facingRows: true,
seatPrefix: "fv-b",
},
];
const SEATS: Seat[] = [
{ id: "standup-01", position: { x: 5.0, z: 5.6 }, facing: EAST, pose: "stand" },
{ id: "standup-02", position: { x: 8.2, z: 5.6 }, facing: WEST, pose: "stand" },
{ id: "standup-03", position: { x: 6.6, z: 4.4 }, facing: SOUTH, pose: "stand" },
{ id: "quietbox-01", position: { x: 13.0, z: 5.4 }, facing: EAST, pose: "sit" },
{ id: "quietbox-02", position: { x: 15.8, z: 5.4 }, facing: WEST, pose: "sit" },
{ id: "galley-01", position: { x: 6.0, z: 25.0 }, facing: SOUTH, pose: "stand" },
{ id: "galley-02", position: { x: 7.6, z: 25.0 }, facing: SOUTH, pose: "stand" },
{ id: "galley-03", position: { x: 9.2, z: 25.0 }, facing: SOUTH, pose: "stand" },
// On the table's south long side, not on the tabletop: the table is centred on
// z 27.0 and is 1.2 m deep, so a seat at 27.0 was inside it.
{ id: "galley-04", position: { x: 12.4, z: 28.0 }, facing: NORTH, pose: "sit" },
{ id: "galley-05", position: { x: 14.0, z: 28.0 }, facing: NORTH, pose: "sit" },
{ id: "bench-01", position: { x: 44.4, z: 6.0 }, facing: EAST, pose: "stand" },
{ id: "bench-02", position: { x: 44.4, z: 8.4 }, facing: EAST, pose: "stand" },
{ id: "bench-03", position: { x: 44.4, z: 10.8 }, facing: EAST, pose: "stand" },
];
// ---- Props ----------------------------------------------------------------
const PROPS: Prop[] = [
// -- The desk floor -------------------------------------------------------
...scatter("fv-ped", PEDESTAL, grid(22.0, 6.8, 7, 1, 1.7, 0)),
...scatter("fv-ped-b", PEDESTAL, grid(22.0, 12.0, 7, 1, 1.7, 0)),
/**
* The lights, hung from the trusses at seven metres.
*
* The one place this pack really needs the ceiling-fixture exception: a
* pendant is authored with its origin at the mounting plane and its geometry
* below, so 7.2 is a real height in a 9 m shed and not an offset from a lid
* that does not exist.
*/
...scatter("truss-light", PENDANT, grid(8.0, 5.0, 6, 4, 9.0, 7.0), { elevation: 7.2 }),
// -- The boxes ------------------------------------------------------------
{ id: "standup-board", kind: WHITEBOARD, position: { x: 6.6, z: BOX_N + INT_FACE + BOARD_OFFSET }, rotation: NORTH, elevation: 1.0 },
{ id: "standup-rug", kind: RUG, position: { x: 6.6, z: 6.3 }, rotation: NORTH, colorKey: "team" },
{ id: "quiet-table", kind: MEETING_TABLE, position: { x: 14.4, z: 5.4 }, rotation: NORTH },
...scatter("quiet-chair", TASK_CHAIR, [
{ x: 13.0, z: 5.4 },
{ x: 15.8, z: 5.4 },
]),
{ id: "quiet-display", kind: DISPLAY, position: { x: 14.4, z: BOX_N + INT_FACE + DISPLAY_OFFSET }, rotation: NORTH, elevation: 1.15 },
// -- The bench ------------------------------------------------------------
// Four, starting at z 1.1: the gable is solid only for z 0..6, and the hangar
// door's arch runs from 6.0 to 18.0 — a five-shelf run from 4.0 put three of
// them standing in the open doorway.
...scatter("bench-shelf", SHELF, grid(WIDTH - EXT_FACE - 0.2, 1.1, 1, 4, 0, 1.2), { rotation: EAST }),
{ id: "bench-board", kind: WHITEBOARD, position: { x: 43.0, z: 3.0 + BOARD_OFFSET }, rotation: NORTH, elevation: 1.0 },
...scatter("bench-locker", LOCKER, grid(42.4, 13.0, 3, 1, 1.1, 0), { rotation: WEST }),
// -- The galley -----------------------------------------------------------
{ id: "galley-rug", kind: RUG, position: { x: 9.0, z: 26.4 }, rotation: NORTH, colorKey: "social" },
{ id: "galley-table", kind: MEETING_TABLE, position: { x: 13.2, z: 27.0 }, rotation: NORTH },
...scatter("galley-lounge", LOUNGE_CHAIR, [
{ x: 6.0, z: 26.8 },
{ x: 8.4, z: 26.8 },
{ x: 10.8, z: 26.8 },
]),
{ id: "galley-side", kind: SIDE_TABLE, position: { x: 7.2, z: 25.8 }, rotation: NORTH },
...scatter("galley-plant", TREE, [
{ x: 4.0, z: 23.4 },
{ x: 15.0, z: 23.4 },
]),
// -- The floor, kept mostly empty -----------------------------------------
//
// Three trees and nothing else. The shed's argument is the volume, and a
// fifty-four-metre room with forty objects in it is a fifty-four-metre room
// you cannot see across.
...scatter("floor-tree", TREE, [
{ x: 20.0, z: 20.0 },
{ x: 30.0, z: 24.0 },
{ x: 36.0, z: 4.0 },
]),
...scatter("floor-plant", PLANT, [
{ x: 19.6, z: 3.2 },
{ x: 34.0, z: 14.0 },
]),
];
// ---- Zones ----------------------------------------------------------------
const ZONES: Zone[] = [
{ id: "zone-build", name: "Build", outline: rect(42.0, 3.0, WIDTH - 0.4, 16.0), colorKey: "team" },
{ id: "zone-galley", name: "Galley", outline: rect(3.0, 22.0, 16.0, DEPTH - 0.4), colorKey: "social" },
];
// ---- Viewpoints -----------------------------------------------------------
const VIEWPOINTS: Viewpoint[] = [
{
id: "hangar",
number: "01",
label: "The Hangar",
shortLabel: "Hangar",
levelId: "level-1",
focus: { at: { x: 27, z: 15 }, distance: 52, height: 26, rotation: 0.6 },
description:
"Fifty-four metres by thirty, nine to the trusses, one room. Everything Frontier Valley has is on this slab or on the deck at the far end.",
},
{
id: "benches",
number: "02",
label: "The Benches",
shortLabel: "Benches",
levelId: "level-1",
focus: { at: { x: 27.4, z: 8.0 }, distance: 15, height: 4.6, rotation: 0.4 },
description:
"Twenty-eight seats in two runs down the middle of the floor, under the trusses. Nothing is against a wall — in a shed the walls are the worst surface in the building.",
},
{
id: "big-door",
number: "03",
label: "The Big Door",
shortLabel: "Big Door",
levelId: "level-1",
// Low and looking east, straight out through the twelve-metre opening.
focus: { at: { x: 46, z: 9.5 }, distance: 18, height: 3.0, rotation: 1.5 },
description:
"Twelve metres of hangar door, open onto the apron, with the bench inside it. The reason a company rents one of these rather than a floor of an office block.",
},
{
id: "mezzanine",
number: "04",
label: "The Mezzanine",
shortLabel: "Mezzanine",
levelId: "level-mezz",
// `height` is metres above *this* level's floor, so 3.0 here is standing on
// the deck rather than 3 m off the concrete.
focus: { at: { x: 46, z: 25 }, distance: 13, height: 3.0, rotation: 2.4 },
description:
"A deck four and a half metres up with another four and a half above it. Its own level, because a level is the only thing in this format that carries a floor height — and without one its chairs floated over bare concrete.",
},
{
id: "galley",
number: "05",
label: "The Galley",
shortLabel: "Galley",
levelId: "level-1",
focus: { at: { x: 9.5, z: 26 }, distance: 12, height: 3.2, rotation: 3.4 },
description:
"The lagoon side, and the only glazing you can see out of standing up. The whole social end of the building is arranged around one row of windows.",
},
];
// ---- The pack -------------------------------------------------------------
// ---- The mezzanine, as its own level --------------------------------------
//
// Authored in its own floor's frame, with the deck at zero. `Plan` adds
// `MEZZ_HEIGHT` to every coordinate here exactly once.
const MEZZ_ROOMS: Room[] = [
{
id: "mezzanine",
name: "The Mezzanine",
outline: rect(MEZZ_W, MEZZ_N, WIDTH - 0.4, DEPTH - 0.4),
floor: WOOD,
ceiling: null,
},
];
/**
* The balustrade, and — as in the reference pack's gallery — a **wall** and not
* a prop, because `Plan` derives the walk collider from the wall list and the
* drop is 4.4 m onto polished concrete. No openings: that is what a balustrade
* is.
*/
const MEZZ_WALLS: Wall[] = [
{
id: "mezz-west",
from: { x: MEZZ_W, z: MEZZ_N },
to: { x: MEZZ_W, z: DEPTH - 0.4 },
height: 1.1,
surface: GLASS,
},
{
id: "mezz-north",
from: { x: MEZZ_W, z: MEZZ_N },
to: { x: WIDTH - 0.4, z: MEZZ_N },
height: 1.1,
surface: GLASS,
},
];
const MEZZ_SEATS: Seat[] = [
{ id: "mezz-01", position: { x: 44.0, z: 23.0 }, facing: NORTH, pose: "sit" },
{ id: "mezz-02", position: { x: 46.4, z: 23.0 }, facing: NORTH, pose: "sit" },
{ id: "mezz-03", position: { x: 48.8, z: 23.0 }, facing: NORTH, pose: "sit" },
];
const MEZZ_PROPS: Prop[] = [
{ id: "mezz-table", kind: MEETING_TABLE, position: { x: 46.4, z: 24.2 }, rotation: NORTH },
...scatter("mezz-chair", TASK_CHAIR, [
{ x: 44.0, z: 23.0 },
{ x: 46.4, z: 23.0 },
{ x: 48.8, z: 23.0 },
]),
...scatter("mezz-lounge", LOUNGE_CHAIR, [
{ x: 44.0, z: 27.4 },
{ x: 47.0, z: 27.4 },
], { rotation: SOUTH }),
{ id: "mezz-rug", kind: RUG, position: { x: 45.5, z: 27.4 }, rotation: NORTH, colorKey: "social" },
// Half-depth plus a 25 mm reveal off the wall face, which is how the reference
// pack stands the same asset against a wall — `EXT_FACE + 0.2` is the shelf's
// *clearance* and leaves it floating 0.42 m out in the room.
...scatter("mezz-shelf", SHELF, grid(WIDTH - EXT_FACE - 0.2, 22.0, 1, 3, 0, 1.2), {
rotation: EAST,
}),
];
const MEZZ_ZONES: Zone[] = [
{ id: "zone-mezz", name: "Mezzanine", outline: rect(MEZZ_W, MEZZ_N, WIDTH - 0.4, DEPTH - 0.4), colorKey: "social" },
];
const LEVEL_MEZZ: Level = {
id: "level-mezz",
name: "The Mezzanine",
elevation: MEZZ_HEIGHT,
// What is above the deck is the same roof, so its storey height is whatever is
// left of the shed.
wallHeight: RIDGE - MEZZ_HEIGHT,
wallThickness: INT_THICKNESS,
wallSurface: PAINT,
floorplan: {
rooms: MEZZ_ROOMS,
walls: MEZZ_WALLS,
props: MEZZ_PROPS,
seats: MEZZ_SEATS,
zones: MEZZ_ZONES,
},
};
const LEVEL_1: Level = {
id: "level-1",
name: "The Slab",
elevation: 0,
wallHeight: RIDGE,
wallThickness: INT_THICKNESS,
wallSurface: PAINT,
floorplan: {
rooms: ROOMS,
walls: WALLS,
props: PROPS,
deskBanks: DESK_BANKS,
seats: SEATS,
zones: ZONES,
},
};
export const FRONTIER_VALLEY: Office = {
id: "frontier-valley",
name: "Frontier Valley",
levels: [LEVEL_1, LEVEL_MEZZ],
viewpoints: VIEWPOINTS,
/**
* Alameda Point, on the estuary side of Alameda Island.
*
* Typed by hand from the street grid of the former Naval Air Station, not
* geocoded — CONTRACT.md §8. Four metres of elevation because this is
* reclaimed flat ground and the slab is barely above it, which is the exact
* opposite of `lumbridge-hq`'s 188 m and is the whole point of having both.
*
* `heading: 0` is a real claim rather than the reference pack's convenience:
* the hangars here are laid out square to the old runways, which run close
* enough to northsouth that calling the clerestory wall "north" is true.
* So the high glazing really does take north light and the lagoon really is
* to the south.
*/
site: {
lat: 37.7756,
lng: -122.3186,
elevation: 4,
heading: 0,
label: "Alameda Point",
},
meta: {
description:
"A startup in a hangar at Alameda Point: one room, fifty-four by thirty, nine metres to the trusses. The second pack, and the one that shows the format describes a shed as well as it describes a corridor.",
author: "Lumbridge",
license: "CC0-1.0",
version: "1.0.0",
updated: "2026-08-07",
},
};
export default FRONTIER_VALLEY;
+54 -10
View File
@@ -118,16 +118,36 @@ const DEPTH = 18.0;
const CEILING = 2.8;
/**
* Floor to floor. Not the same as `CEILING` and the difference is not slack:
* 4.2 m is 2.8 m of room plus 1.4 m of structure, services and raised floor,
* which is what a real storey costs and what puts level 2's slab at a height a
* stair can plausibly climb to.
* The gap between one storey's ceiling and the next one's floor.
*
* In a real building this is 1.4 m of structure, ducts, trays and raised floor,
* and you never see it. Here it is **ten times that**, and the exaggeration is
* deliberate and is the whole reason it has a name of its own.
*
* The brief was to be able to see the space between the floors and eventually to
* run things through it — cable trays, fibre, the drops that land on the ceiling
* of the floor below and the floor of the one above. At 1.4 m there is nowhere
* to put any of that and nothing to look at; at 14 m the interstitial is a
* storey in its own right, the two slabs read as two separate places, and the
* commons becomes a genuine shaft rather than a tall room.
*
* It is frankly not architecture. A 16.8 m floor-to-floor is a hangar, the stair
* in the east wing is no longer a stair anybody could climb, and the gallery
* looks down from the height of a five-storey building. That is an accepted
* cost of a deliberately unreal building, and **this is the one number to change
* if it reads as too much** — everything else in the file is measured off it.
*/
const PLENUM = 14.0;
/**
* Floor to floor. Not the same as `CEILING` and the difference is not slack: it
* is the room plus the interstitial above it.
*
* `Plan` adds this to every coordinate on level 2 exactly once, so both levels
* are authored in their own floor's frame and neither has to know about the
* other.
*/
const STOREY = 4.2;
const STOREY = CEILING + PLENUM;
/**
* The commons is open to both storeys, so its walls are two rooms tall.
@@ -1420,7 +1440,7 @@ const PROPS: Prop[] = [
elevation: 1.1,
},
/**
* Pendants at 6.4 m, hanging into the void from the roof rather than from a
* Pendants at 19 m, hanging into the void from the roof rather than from a
* ceiling at 2.8 m that is not there.
*
* This is the one place in the pack where the ceiling-fixture exception earns
@@ -1498,7 +1518,7 @@ const ZONES: Zone[] = [
*
* **Every coordinate below is in level 2's own frame**, with the floor at zero.
* `Plan` adds `STOREY` to all of them exactly once when it resolves the level,
* which is what lets this section be read without holding 4.2 in your head, and
* which is what lets this section be read without holding 16.8 in your head, and
* what lets both levels sit in one scene group at the origin.
*
* It stops at `BLOCK_E`. The wing below is open to the roof, so there is no slab
@@ -2004,9 +2024,12 @@ const VIEWPOINTS: Viewpoint[] = [
// wing did: an establishing shot that still framed 34 m put the commons
// half off the right-hand edge, which is a poor introduction to the largest
// room in the building.
focus: { at: { x: 24.0, z: 9.0 }, distance: 44, height: 19, rotation: 0.55 },
// Higher and further back than it was, because the building got taller
// rather than wider: at a 14 m interstitial the roof is 19.6 m up, and a
// camera at 19 m was level with it and looking at the parapet.
focus: { at: { x: 24.0, z: 9.0 }, distance: 58, height: 34, rotation: 0.55 },
description:
"Forty-eight metres by eighteen, two storeys, glazed along the north edge and open to the roof at the east end. Everything in this building is somewhere in this frame.",
"Forty-eight metres by eighteen, two storeys a long way apart, glazed along the north edge and open to the roof at the east end. Everything in this building is somewhere in this frame.",
},
{
id: "reception",
@@ -2081,7 +2104,7 @@ const VIEWPOINTS: Viewpoint[] = [
// there is something underneath.
focus: { at: { x: 37.0, z: 9.0 }, distance: 9, height: 1.8, rotation: 1.4 },
description:
"The balcony over the commons, four metres of it, with a glass balustrade and nothing below for another four. The reason the void is a volume rather than a tall room.",
"The balcony over the commons, four metres of it, with a glass balustrade and nothing below for another seventeen. The reason the void is a volume rather than a tall room.",
},
];
@@ -2135,6 +2158,27 @@ export const LUMBRIDGE_HQ: Office = {
name: "Lumbridge HQ",
levels: [LEVEL_1, LEVEL_2],
viewpoints: VIEWPOINTS,
/**
* High in a downtown tower, on the same board the city view draws.
*
* The coordinate is a block in the Transbay cluster, typed by hand from the
* street grid — not geocoded, for the reason CONTRACT.md §8 gives at length.
* `elevation` is what makes it a *tower*: 188 m is around the forty-eighth
* floor, so the horizon sits a long way down and the fog outside the glass is
* the fog you look across a city at rather than through.
*
* `heading: 205` turns the glazed façade — `ext-north`, the wall this pack has
* always called the daylight side — to face south-south-west. That is the one
* number that decides whether the sun ever actually enters the building, and
* pointing the glass at the afternoon is the whole reason the field exists.
*/
site: {
lat: 37.7897,
lng: -122.3972,
elevation: 188,
heading: 205,
label: "Transbay, San Francisco",
},
meta: {
description:
"The reference office: two levels around a double-height commons, twenty-six rooms, a hundred and twenty-six seats. Copy this file, change the numbers, keep the seat ids.",