The office gets a room you cannot see all of from a doorway
Lumbridge HQ was 34 x 18 m, 612 m², one storey, fifteen rooms. It is now
48 x 18 m over two storeys, twenty-six rooms and a hundred and
twenty-six seats — and the fourteen metres that were added are one room
rather than a second row of cellular offices, because area is not the
thing the building was short of.
**The commons** is the east wing: one volume, open all the way to the
roof at 7.0 m, with the block's old east curtain wall now looking into it
instead of onto a street. Two archways through that glass, four trees,
one refectory table on the axis of the corridor, and nothing along the
glazing.
**Level 2** sits at 4.2 m — floor to floor, not floor to ceiling, which
is the number people get wrong. A studio with nineteen metres of
unbroken north-lit floor, a library, two meeting rooms, a project room,
and a gallery that reaches 4.2 m out over the void so the commons can be
looked down into rather than merely walked through.
`WIDTH` became `BLOCK_E`: every room, wall and seat authored before the
wing existed is measured against the old east line, and folding the two
into one number would have stretched fifteen rooms sideways.
Three things worth knowing:
- Every existing seat id is unchanged. The README says to keep them
stable for the same reason street numbers survive repainting, and a
`Presence` binds to one.
- The balustrade is a wall and not a prop. `Plan` derives the walk
collider from the wall list, so a rail authored as furniture is a
balcony you can walk off, and the drop is a storey onto terrazzo.
- The wing's walls carry an explicit `height`, because "double height"
is a property of the walls and `ceiling: null` alone would leave a
lid you cannot see but the light rig can.
`src/test/office.test.ts` is new and is the README's own checklist, which
nothing had ever run: problems empty, seat ids unique building-wide, the
balustrade impassable from all three open edges, and a 0.1 m flood fill
proving every room on both levels is reachable on foot from the way in.
That last one caught a door authored 200 mm past the end of its wall —
silently dropped, room sealed, and invisible from every camera angle.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+810
-32
@@ -90,20 +90,54 @@ import type {
|
||||
// ---- The floor plate ------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The building, in six numbers. Everything else in this file is measured off
|
||||
* these, so a self-hoster with a different slab starts here.
|
||||
* The building, in a handful of numbers. Everything else in this file is
|
||||
* measured off these, so a self-hoster with a different slab starts here.
|
||||
*
|
||||
* 34 x 18 m is 612 m², which is a plausible single floor of a mid-rise: deep
|
||||
* enough for a row of rooms behind a corridor, shallow enough that the desks
|
||||
* still get daylight. Go much deeper and the middle of the plate becomes a
|
||||
* place nobody wants to sit, which is a real constraint and not a rendering one.
|
||||
* **The plate is in two pieces and they are different kinds of thing.**
|
||||
*
|
||||
* `BLOCK_E` at 34 m is the east edge of the original block — 34 x 18 m, 612 m²,
|
||||
* a plausible single floor of a mid-rise: deep enough for a row of rooms behind
|
||||
* a corridor, shallow enough that the desks still get daylight. Go much deeper
|
||||
* and the middle of the plate becomes a place nobody wants to sit, which is a
|
||||
* real constraint and not a rendering one. Every room, wall and seat authored
|
||||
* before the wing existed is measured against this line, which is why it keeps a
|
||||
* name of its own rather than being folded into `WIDTH`.
|
||||
*
|
||||
* `WIDTH` at 48 m is the whole plate, block plus wing. The 14 m east of the
|
||||
* block is one room — see `COMMONS` — and it is deliberately not laid out on the
|
||||
* block's grid. A second row of cellular offices would have added area without
|
||||
* adding anything you could feel; a double-height volume you walk into changes
|
||||
* what the building is like to be in, which is the thing that was actually
|
||||
* wanted.
|
||||
*/
|
||||
const WIDTH = 34.0;
|
||||
const BLOCK_E = 34.0;
|
||||
const WIDTH = 48.0;
|
||||
const DEPTH = 18.0;
|
||||
|
||||
/** Floor to underside of ceiling. 2.8 m is an ordinary commercial storey. */
|
||||
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.
|
||||
*
|
||||
* `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;
|
||||
|
||||
/**
|
||||
* The commons is open to both storeys, so its walls are two rooms tall.
|
||||
*
|
||||
* Stated as the sum rather than as `7.0` because it *is* the sum: change the
|
||||
* storey height and the void has to follow, and a hard-coded number here would
|
||||
* be the one thing that quietly did not.
|
||||
*/
|
||||
const COMMONS_HEIGHT = STOREY + CEILING;
|
||||
|
||||
/**
|
||||
* The booths get a lower lid than the room they stand in. That is what makes a
|
||||
* booth feel like a booth rather than a cupboard with the top cut off, and it
|
||||
@@ -165,6 +199,23 @@ const X_BOOTH_2 = 10.4;
|
||||
const X_BOOTH_3 = 12.4;
|
||||
const X_BOOTH_E = 14.4;
|
||||
|
||||
// -- The east wing ----------------------------------------------------------
|
||||
//
|
||||
// Three lines, and the wing needs no more because it is one room. The stair is
|
||||
// the only enclosure in it, tucked into the south-east corner where it takes
|
||||
// daylight from nothing.
|
||||
const STAIR_W = 42.8; // stair core / commons floor
|
||||
const STAIR_N = 12.6; // stair core / commons floor
|
||||
/**
|
||||
* How far level 2's gallery reaches out over the commons.
|
||||
*
|
||||
* 4.2 m of balcony, which is enough to stand two people and a rail at without
|
||||
* being a floor — past about six the void stops reading as a void and starts
|
||||
* reading as a corridor with a hole in it, and the whole point of the wing is
|
||||
* the volume you can see all of at once.
|
||||
*/
|
||||
const GALLERY_E = BLOCK_E + 4.2;
|
||||
|
||||
// ---- Yaw ------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -396,14 +447,14 @@ const ROOMS: Room[] = [
|
||||
{
|
||||
id: "lounge",
|
||||
name: "The Lounge",
|
||||
outline: rect(SOCIAL_W, 0, WIDTH, KITCHEN_N),
|
||||
outline: rect(SOCIAL_W, 0, BLOCK_E, KITCHEN_N),
|
||||
floor: CARPET_ACCENT,
|
||||
ceiling: null,
|
||||
},
|
||||
{
|
||||
id: "kitchen",
|
||||
name: "The Kitchen",
|
||||
outline: rect(SOCIAL_W, KITCHEN_N, WIDTH, SPINE_N),
|
||||
outline: rect(SOCIAL_W, KITCHEN_N, BLOCK_E, SPINE_N),
|
||||
floor: TERRAZZO,
|
||||
ceiling: null,
|
||||
},
|
||||
@@ -440,7 +491,7 @@ const ROOMS: Room[] = [
|
||||
// 1.8 m clear, running the full 34 m. A corridor is a room like any other;
|
||||
// giving it an id is what lets a walk-mode controller, a wayfinding overlay
|
||||
// or a cleaning schedule refer to it without inventing a second concept.
|
||||
outline: rect(0, SPINE_N, WIDTH, SPINE_S),
|
||||
outline: rect(0, SPINE_N, BLOCK_E, SPINE_S),
|
||||
floor: CONCRETE,
|
||||
ceiling: null,
|
||||
},
|
||||
@@ -493,10 +544,57 @@ const ROOMS: Room[] = [
|
||||
{
|
||||
id: "store",
|
||||
name: "Facilities",
|
||||
outline: rect(X_STORE, SPINE_S, WIDTH, DEPTH),
|
||||
outline: rect(X_STORE, SPINE_S, BLOCK_E, DEPTH),
|
||||
floor: CONCRETE,
|
||||
ceiling: { height: 2.6, surface: CEILING_TILE },
|
||||
},
|
||||
|
||||
// -- The east wing --------------------------------------------------------
|
||||
/**
|
||||
* One room, fourteen metres by eighteen, open to both storeys.
|
||||
*
|
||||
* `ceiling: null` is doing something different here from everywhere else in
|
||||
* this file. Elsewhere it means "take the lid off so the establishing shot can
|
||||
* see in" — a rendering convenience for a room that has a ceiling in reality.
|
||||
* Here there genuinely is no ceiling at 2.8 m, because level 2's slab stops at
|
||||
* `BLOCK_E` and this volume runs all the way to the roof. The walls around it
|
||||
* carry `COMMONS_HEIGHT` to say so.
|
||||
*
|
||||
* It is deliberately *not* subdivided. Fourteen metres would take three more
|
||||
* meeting rooms and a run of desks, and that would have been more floor area
|
||||
* doing exactly what the block already does. A room you can see the whole of,
|
||||
* with a tree in it and a balcony over one edge, is the thing the building did
|
||||
* not have.
|
||||
*/
|
||||
{
|
||||
id: "commons",
|
||||
name: "The Commons",
|
||||
// Notched around the stair rather than passing underneath it, for the same
|
||||
// reason the open floor is notched around the booths: two coplanar slabs at
|
||||
// y = 0 is a z-fight waiting for the wrong GPU. Wound the way `rect` winds —
|
||||
// down the west side, east along the south, back up — which is
|
||||
// counter-clockwise in plan view with +Z down the page.
|
||||
outline: [
|
||||
{ x: BLOCK_E, z: 0 },
|
||||
{ x: BLOCK_E, z: DEPTH },
|
||||
{ x: STAIR_W, z: DEPTH },
|
||||
{ x: STAIR_W, z: STAIR_N },
|
||||
{ x: WIDTH, z: STAIR_N },
|
||||
{ x: WIDTH, z: 0 },
|
||||
],
|
||||
floor: TERRAZZO,
|
||||
ceiling: null,
|
||||
},
|
||||
{
|
||||
id: "stair-core",
|
||||
name: "The Stair",
|
||||
// The one enclosure in the wing, in the corner that gets no daylight from
|
||||
// the two glazed sides. A stair is the right thing to put where nobody
|
||||
// wants to sit.
|
||||
outline: rect(STAIR_W, STAIR_N, WIDTH, DEPTH),
|
||||
floor: CONCRETE,
|
||||
ceiling: null,
|
||||
},
|
||||
];
|
||||
|
||||
// ---- Walls ----------------------------------------------------------------
|
||||
@@ -519,7 +617,7 @@ const WALLS: Wall[] = [
|
||||
// that the desk floor reads as a place with a view, enough wall that the
|
||||
// building still has corners.
|
||||
from: { x: 0, z: 0 },
|
||||
to: { x: WIDTH, z: 0 },
|
||||
to: { x: BLOCK_E, z: 0 },
|
||||
thickness: EXT_THICKNESS,
|
||||
surface: PAINT,
|
||||
openings: [
|
||||
@@ -532,24 +630,84 @@ const WALLS: Wall[] = [
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "ext-east-glazed",
|
||||
id: "commons-west-glazed",
|
||||
// Full-height glazing as a *wall with a glass surface*, not as one enormous
|
||||
// opening. This is the distinction the format turns on: an opening is a hole
|
||||
// and a hole is something you can see and sometimes walk through, whereas a
|
||||
// curtain wall is a solid you happen to be able to see through. Making it an
|
||||
// opening would hand the collider a 12 m gap and put the lounge on the
|
||||
// pavement.
|
||||
from: { x: WIDTH, z: 0 },
|
||||
to: { x: WIDTH, z: SPINE_S },
|
||||
// opening would hand the collider a 12 m gap and put the lounge in the
|
||||
// atrium.
|
||||
//
|
||||
// It was `ext-east` and it was the outside of the building. The wing put a
|
||||
// room on the far side of it, so the same glass now looks into a
|
||||
// double-height space instead of onto a street — which is a better thing for
|
||||
// a lounge to look at and cost nothing but a rename. The two openings are
|
||||
// new: a wall you cannot walk through is a wing nobody visits.
|
||||
from: { x: BLOCK_E, z: 0 },
|
||||
to: { x: BLOCK_E, z: SPINE_S },
|
||||
thickness: EXT_THICKNESS,
|
||||
surface: GLASS,
|
||||
openings: [
|
||||
archway(2.6, 2.4), // out of the kitchen
|
||||
archway(9.0, 3.0), // off the corridor, the main way through
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "commons-west-solid",
|
||||
from: { x: BLOCK_E, z: SPINE_S },
|
||||
to: { x: BLOCK_E, z: DEPTH },
|
||||
thickness: EXT_THICKNESS,
|
||||
surface: PAINT,
|
||||
},
|
||||
|
||||
// -- The east wing's envelope ---------------------------------------------
|
||||
//
|
||||
// Two storeys tall, which is what makes the commons a volume rather than a
|
||||
// tall room: `Wall.height` overrides the level's, and the level's is one
|
||||
// storey because every other wall on it is.
|
||||
{
|
||||
id: "ext-east",
|
||||
from: { x: WIDTH, z: 0 },
|
||||
to: { x: WIDTH, z: DEPTH },
|
||||
thickness: EXT_THICKNESS,
|
||||
height: COMMONS_HEIGHT,
|
||||
surface: GLASS,
|
||||
},
|
||||
{
|
||||
id: "ext-east-solid",
|
||||
from: { x: WIDTH, z: SPINE_S },
|
||||
id: "wing-north",
|
||||
from: { x: BLOCK_E, z: 0 },
|
||||
to: { x: WIDTH, z: 0 },
|
||||
thickness: EXT_THICKNESS,
|
||||
height: COMMONS_HEIGHT,
|
||||
surface: GLASS,
|
||||
},
|
||||
{
|
||||
id: "wing-south",
|
||||
from: { x: BLOCK_E, z: DEPTH },
|
||||
to: { x: WIDTH, z: DEPTH },
|
||||
thickness: EXT_THICKNESS,
|
||||
height: COMMONS_HEIGHT,
|
||||
surface: PAINT,
|
||||
// The wing's own way out, which is what lets the stair be an escape stair
|
||||
// rather than a feature. `start` is measured from the wall's `from` end, so
|
||||
// an 1.8 m pair starting at 11.6 finishes at 13.4 with 600 mm to spare —
|
||||
// 12.4 ran 200 mm past the end and `Plan` dropped the whole opening.
|
||||
openings: [doorway(11.6, 1.8, 2.4)],
|
||||
},
|
||||
|
||||
// -- The stair core -------------------------------------------------------
|
||||
{
|
||||
id: "stair-west",
|
||||
from: { x: STAIR_W, z: STAIR_N },
|
||||
to: { x: STAIR_W, z: DEPTH },
|
||||
height: COMMONS_HEIGHT,
|
||||
openings: [doorway(1.2, 1.2, 2.4)],
|
||||
},
|
||||
{
|
||||
id: "stair-north",
|
||||
from: { x: STAIR_W, z: STAIR_N },
|
||||
to: { x: WIDTH, z: STAIR_N },
|
||||
height: COMMONS_HEIGHT,
|
||||
},
|
||||
{
|
||||
id: "ext-south",
|
||||
@@ -557,7 +715,7 @@ const WALLS: Wall[] = [
|
||||
// right on the plan. One window per room that deserves one; the server room
|
||||
// (26.4 → 30.2) deliberately gets none.
|
||||
from: { x: 0, z: DEPTH },
|
||||
to: { x: WIDTH, z: DEPTH },
|
||||
to: { x: BLOCK_E, z: DEPTH },
|
||||
thickness: EXT_THICKNESS,
|
||||
surface: PAINT,
|
||||
openings: [
|
||||
@@ -607,7 +765,7 @@ const WALLS: Wall[] = [
|
||||
// agree about where they meet. The stretch from 8.4 to 14.4 is the back of
|
||||
// the focus booths and is solid for that reason.
|
||||
from: { x: 0, z: SPINE_N },
|
||||
to: { x: WIDTH, z: SPINE_N },
|
||||
to: { x: BLOCK_E, z: SPINE_N },
|
||||
openings: [
|
||||
doorway(1.6), // lobby
|
||||
archway(16.0, 3.0), // the main way off the desk floor
|
||||
@@ -722,7 +880,7 @@ const WALLS: Wall[] = [
|
||||
{
|
||||
id: "front-store",
|
||||
from: { x: X_STORE, z: SPINE_S },
|
||||
to: { x: WIDTH, z: SPINE_S },
|
||||
to: { x: BLOCK_E, z: SPINE_S },
|
||||
openings: [doorway(1.5)],
|
||||
},
|
||||
|
||||
@@ -1203,10 +1361,76 @@ const PROPS: Prop[] = [
|
||||
...scatter("fac-locker", LOCKER, grid(X_STORE + INT_FACE + 0.25, 13.2, 1, 4, 0, 1.3), {
|
||||
rotation: WEST,
|
||||
}),
|
||||
...scatter("fac-shelf", SHELF, grid(WIDTH - EXT_FACE - 0.2, 13.4, 1, 2, 0, 1.0), {
|
||||
...scatter("fac-shelf", SHELF, grid(BLOCK_E - EXT_FACE - 0.2, 13.4, 1, 2, 0, 1.0), {
|
||||
rotation: EAST,
|
||||
}),
|
||||
...scatter("fac-light", TROFFER, grid(32.2, 14.0, 1, 2, 0, 2.4), { elevation: 2.6 }),
|
||||
|
||||
// -- The Commons ----------------------------------------------------------
|
||||
//
|
||||
// Furnished sparsely on purpose. The wing's whole argument is the volume, and
|
||||
// a fourteen-metre room with forty objects in it is a fourteen-metre room you
|
||||
// cannot see. Four trees, two clusters of seating, one long table people
|
||||
// actually work at, and nothing along the glass.
|
||||
...scatter("commons-tree", TREE, [
|
||||
{ x: 36.6, z: 3.2 },
|
||||
{ x: 45.4, z: 4.6 },
|
||||
{ x: 37.4, z: 15.0 },
|
||||
{ x: 44.2, z: 9.8 },
|
||||
]),
|
||||
{
|
||||
id: "commons-rug",
|
||||
kind: RUG,
|
||||
position: { x: 39.4, z: 5.0 },
|
||||
rotation: NORTH,
|
||||
colorKey: "social",
|
||||
},
|
||||
// A ring rather than a row: seating that faces itself is seating people sit
|
||||
// in, and seating in a line against a wall is seating people walk past.
|
||||
...scatter("commons-chair", LOUNGE_CHAIR, [
|
||||
{ x: 38.0, z: 4.2 },
|
||||
{ x: 40.8, z: 4.2 },
|
||||
{ x: 38.0, z: 6.0 },
|
||||
{ x: 40.8, z: 6.0 },
|
||||
]),
|
||||
{ id: "commons-table-01", kind: SIDE_TABLE, position: { x: 39.4, z: 5.1 }, rotation: NORTH },
|
||||
/**
|
||||
* The long table, on the axis of the archway off the corridor.
|
||||
*
|
||||
* Placed where somebody walking out of the block arrives, which is the only
|
||||
* placement rule this room follows. `tera:table.meeting` at its default 2.4 m
|
||||
* is the longest table in the kit; two of them end to end read as one refectory
|
||||
* table, which is what a commons wants and what the kit has no single asset for.
|
||||
*/
|
||||
{ id: "commons-long-01", kind: MEETING_TABLE, position: { x: 39.8, z: 10.4 }, rotation: NORTH },
|
||||
{ id: "commons-long-02", kind: MEETING_TABLE, position: { x: 39.8, z: 12.9 }, rotation: NORTH },
|
||||
...scatter("commons-perch", TASK_CHAIR, [
|
||||
{ x: 38.6, z: 10.4 },
|
||||
{ x: 41.0, z: 10.4 },
|
||||
{ x: 38.6, z: 12.9 },
|
||||
{ x: 41.0, z: 12.9 },
|
||||
]),
|
||||
{
|
||||
id: "commons-display",
|
||||
kind: DISPLAY,
|
||||
// On the stair core's north face, which is the one solid surface in the wing
|
||||
// that everybody walking through it is already looking at.
|
||||
position: { x: 45.4, z: STAIR_N - INT_FACE - DISPLAY_OFFSET },
|
||||
rotation: SOUTH,
|
||||
elevation: 1.1,
|
||||
},
|
||||
/**
|
||||
* Pendants at 6.4 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
|
||||
* its keep: `tera:light.pendant` is authored with its origin at the mounting
|
||||
* plane and all its geometry below, so a number here is a real height and not
|
||||
* an offset from a lid nobody built.
|
||||
*/
|
||||
...scatter("commons-pendant", PENDANT, grid(37.2, 4.0, 3, 3, 4.2, 5.4), {
|
||||
elevation: COMMONS_HEIGHT - 0.6,
|
||||
}),
|
||||
];
|
||||
|
||||
// ---- Zones ----------------------------------------------------------------
|
||||
@@ -1255,8 +1479,500 @@ const ZONES: Zone[] = [
|
||||
colorKey: "team-b",
|
||||
audience: "private",
|
||||
},
|
||||
{ id: "zone-social", name: "Social", outline: rect(SOCIAL_W, 0, WIDTH, SPINE_N), colorKey: "social" },
|
||||
{ id: "zone-social", name: "Social", outline: rect(SOCIAL_W, 0, BLOCK_E, SPINE_N), colorKey: "social" },
|
||||
{ id: "zone-focus", name: "Focus", outline: rect(X_BOOTH_1, BOOTH_N, X_BOOTH_E, SPINE_N), colorKey: "focus" },
|
||||
// Spatial rather than organisational, like "Social" and "Focus" and unlike the
|
||||
// two team zones — anybody standing in the wing can see it is the commons.
|
||||
{
|
||||
id: "zone-commons",
|
||||
name: "Commons",
|
||||
outline: rect(BLOCK_E, 0, WIDTH, DEPTH),
|
||||
colorKey: "social",
|
||||
},
|
||||
];
|
||||
|
||||
// ---- Level 2 ---------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* The upper storey: a studio, a library, three rooms and a balcony.
|
||||
*
|
||||
* **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
|
||||
* 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
|
||||
* over it — only `l2-gallery`, a 4.2 m balcony that reaches out over the void so
|
||||
* the commons can be looked *down into* rather than merely walked through. A
|
||||
* double-height room nobody can stand above is a tall room; the balcony is what
|
||||
* makes it a volume.
|
||||
*
|
||||
* The programme is deliberately the opposite of level 1's. Downstairs is
|
||||
* fifteen rooms, thirty-nine desks and a corridor to tie them together; up here
|
||||
* is one long studio, one library, and three rooms for the things that cannot
|
||||
* happen at a desk. A second floor that repeated the first would have doubled
|
||||
* the area and added nothing to look at.
|
||||
*/
|
||||
|
||||
// The lines level 2 is built on. It shares the block's north band / corridor /
|
||||
// south band rhythm, because the structure below does not move, and divides the
|
||||
// bands differently because the programme is different.
|
||||
const L2_STUDIO_W = 6.4; // landing / studio
|
||||
const L2_LIBRARY_W = 25.2; // studio / library
|
||||
const L2_MEET_A_E = 8.4; // the two meeting rooms
|
||||
const L2_MEET_B_E = 15.2; // meeting room / project room
|
||||
const L2_PROJECT_E = 24.6; // project room / plant
|
||||
|
||||
const L2_ROOMS: Room[] = [
|
||||
// -- North band -----------------------------------------------------------
|
||||
{
|
||||
id: "l2-landing",
|
||||
name: "The Landing",
|
||||
// Where the stair arrives, and the only part of this floor that is
|
||||
// circulation rather than a place to be.
|
||||
outline: rect(0, 0, L2_STUDIO_W, SPINE_N),
|
||||
floor: TERRAZZO,
|
||||
ceiling: null,
|
||||
},
|
||||
{
|
||||
id: "l2-studio",
|
||||
name: "The Studio",
|
||||
// Nineteen metres of unbroken north-lit floor, which is the one thing the
|
||||
// block downstairs cannot offer: level 1's equivalent run is interrupted by
|
||||
// the lobby wall and the booths.
|
||||
outline: rect(L2_STUDIO_W, 0, L2_LIBRARY_W, SPINE_N),
|
||||
floor: CARPET,
|
||||
ceiling: null,
|
||||
},
|
||||
{
|
||||
id: "l2-library",
|
||||
name: "The Library",
|
||||
outline: rect(L2_LIBRARY_W, 0, BLOCK_E, SPINE_N),
|
||||
floor: WOOD,
|
||||
ceiling: null,
|
||||
},
|
||||
|
||||
// -- The corridor ---------------------------------------------------------
|
||||
{
|
||||
id: "l2-corridor",
|
||||
name: "Corridor",
|
||||
outline: rect(0, SPINE_N, BLOCK_E, SPINE_S),
|
||||
floor: CARPET_ACCENT,
|
||||
ceiling: null,
|
||||
},
|
||||
|
||||
// -- South band -----------------------------------------------------------
|
||||
{
|
||||
id: "l2-meet-a",
|
||||
name: "Tiburon",
|
||||
outline: rect(0, SPINE_S, L2_MEET_A_E, DEPTH),
|
||||
floor: CARPET_ACCENT,
|
||||
ceiling: null,
|
||||
},
|
||||
{
|
||||
id: "l2-meet-b",
|
||||
name: "Angel Island",
|
||||
outline: rect(L2_MEET_A_E, SPINE_S, L2_MEET_B_E, DEPTH),
|
||||
floor: CARPET_ACCENT,
|
||||
ceiling: null,
|
||||
},
|
||||
{
|
||||
id: "l2-project",
|
||||
name: "The Project Room",
|
||||
// Concrete and no soft finishes: the room you are allowed to stick things to
|
||||
// the walls of. The workshop downstairs is its equivalent and reads the same
|
||||
// way for the same reason.
|
||||
outline: rect(L2_MEET_B_E, SPINE_S, L2_PROJECT_E, DEPTH),
|
||||
floor: CONCRETE,
|
||||
ceiling: null,
|
||||
},
|
||||
{
|
||||
id: "l2-plant",
|
||||
name: "Plant",
|
||||
// The one room up here with a lid on it, and the same argument as the server
|
||||
// room below: you are never meant to see inside, and a ceiling says so more
|
||||
// cheaply than a sign.
|
||||
outline: rect(L2_PROJECT_E, SPINE_S, BLOCK_E, DEPTH),
|
||||
floor: RAISED_FLOOR,
|
||||
ceiling: { height: 2.6, surface: CEILING_TILE },
|
||||
},
|
||||
|
||||
// -- Over the void --------------------------------------------------------
|
||||
{
|
||||
id: "l2-gallery",
|
||||
name: "The Gallery",
|
||||
outline: rect(BLOCK_E, 2.0, GALLERY_E, 16.0),
|
||||
floor: WOOD,
|
||||
ceiling: null,
|
||||
},
|
||||
];
|
||||
|
||||
const L2_WALLS: Wall[] = [
|
||||
// -- The envelope, repeated ------------------------------------------------
|
||||
//
|
||||
// The same lines as level 1, because the structure below does not move. The
|
||||
// openings are not the same, and that is the point of restating the walls
|
||||
// rather than sharing them: this floor wants glass where the floor below wants
|
||||
// a pier, and a format in which two storeys had to agree about their windows
|
||||
// would be a format that could only describe one storey.
|
||||
{
|
||||
id: "l2-ext-north",
|
||||
from: { x: 0, z: 0 },
|
||||
to: { x: BLOCK_E, z: 0 },
|
||||
thickness: EXT_THICKNESS,
|
||||
surface: PAINT,
|
||||
openings: [
|
||||
pane(1.2, 4.0, 0.75, 2.35),
|
||||
pane(6.4, 4.0, 0.75, 2.35),
|
||||
pane(11.6, 4.0, 0.75, 2.35),
|
||||
pane(16.8, 4.0, 0.75, 2.35),
|
||||
pane(22.0, 4.0, 0.75, 2.35),
|
||||
pane(27.2, 4.0, 0.75, 2.35),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "l2-ext-west",
|
||||
from: { x: 0, z: 0 },
|
||||
to: { x: 0, z: DEPTH },
|
||||
thickness: EXT_THICKNESS,
|
||||
surface: PAINT,
|
||||
openings: [pane(3.0, 3.4), pane(13.4, 2.6)],
|
||||
},
|
||||
{
|
||||
id: "l2-ext-south",
|
||||
from: { x: 0, z: DEPTH },
|
||||
to: { x: BLOCK_E, z: DEPTH },
|
||||
thickness: EXT_THICKNESS,
|
||||
surface: PAINT,
|
||||
openings: [pane(1.4, 5.2), pane(9.4, 4.4), pane(16.0, 6.6), pane(25.4, 3.0)],
|
||||
},
|
||||
|
||||
// -- The edge of the void --------------------------------------------------
|
||||
/**
|
||||
* The east wall of the block, at level 2, with the gallery on the far side.
|
||||
*
|
||||
* Glazed for the same reason level 1's is: the studio looks into the commons,
|
||||
* and a solid wall here would make the balcony a thing you have to go and find
|
||||
* rather than a thing you can see.
|
||||
*/
|
||||
{
|
||||
id: "l2-block-east",
|
||||
from: { x: BLOCK_E, z: 0 },
|
||||
to: { x: BLOCK_E, z: DEPTH },
|
||||
thickness: EXT_THICKNESS,
|
||||
surface: GLASS,
|
||||
openings: [archway(6.0, 3.0), archway(12.0, 2.4)],
|
||||
},
|
||||
/**
|
||||
* The balustrade: a 1.1 m wall around the three open edges of the gallery.
|
||||
*
|
||||
* A wall and not a prop, and this is the load-bearing reason. `Plan` derives
|
||||
* the walk-mode collider from the wall list, so a balustrade authored as
|
||||
* furniture is a balcony you can walk off — and the drop is 4.2 m onto
|
||||
* terrazzo. An opening is a way through iff `sill <= 0 and head >= 1.1`; this
|
||||
* has no openings at all, which is exactly what a balustrade is.
|
||||
*/
|
||||
{
|
||||
id: "l2-gallery-north",
|
||||
from: { x: BLOCK_E, z: 2.0 },
|
||||
to: { x: GALLERY_E, z: 2.0 },
|
||||
height: 1.1,
|
||||
surface: GLASS,
|
||||
},
|
||||
{
|
||||
id: "l2-gallery-east",
|
||||
from: { x: GALLERY_E, z: 2.0 },
|
||||
to: { x: GALLERY_E, z: 16.0 },
|
||||
height: 1.1,
|
||||
surface: GLASS,
|
||||
},
|
||||
{
|
||||
id: "l2-gallery-south",
|
||||
from: { x: BLOCK_E, z: 16.0 },
|
||||
to: { x: GALLERY_E, z: 16.0 },
|
||||
height: 1.1,
|
||||
surface: GLASS,
|
||||
},
|
||||
|
||||
// -- Internal --------------------------------------------------------------
|
||||
{
|
||||
id: "l2-landing-east",
|
||||
from: { x: L2_STUDIO_W, z: 0 },
|
||||
to: { x: L2_STUDIO_W, z: SPINE_N },
|
||||
surface: ACCENT_PAINT,
|
||||
openings: [archway(5.6, 2.6)],
|
||||
},
|
||||
{
|
||||
id: "l2-library-west",
|
||||
from: { x: L2_LIBRARY_W, z: 0 },
|
||||
to: { x: L2_LIBRARY_W, z: SPINE_N },
|
||||
openings: [archway(6.2, 2.4)],
|
||||
},
|
||||
{
|
||||
id: "l2-spine-north",
|
||||
// One wall with three holes, the same arrangement as the floor below and for
|
||||
// the same reason: five walls that have to agree about where they meet is
|
||||
// five chances to be a centimetre out.
|
||||
from: { x: 0, z: SPINE_N },
|
||||
to: { x: BLOCK_E, z: SPINE_N },
|
||||
openings: [doorway(2.4), archway(14.0, 3.0), doorway(29.0)],
|
||||
},
|
||||
{
|
||||
id: "l2-spine-south",
|
||||
from: { x: 0, z: SPINE_S },
|
||||
to: { x: BLOCK_E, z: SPINE_S },
|
||||
openings: [
|
||||
doorway(3.2), // Tiburon
|
||||
doorway(10.4), // Angel Island
|
||||
doorway(18.0, 1.8, 2.4), // the project room, wide enough to carry things through
|
||||
doorway(28.4), // plant
|
||||
],
|
||||
},
|
||||
{
|
||||
id: "l2-meet-divide",
|
||||
from: { x: L2_MEET_A_E, z: SPINE_S },
|
||||
to: { x: L2_MEET_A_E, z: DEPTH },
|
||||
},
|
||||
{
|
||||
id: "l2-project-west",
|
||||
from: { x: L2_MEET_B_E, z: SPINE_S },
|
||||
to: { x: L2_MEET_B_E, z: DEPTH },
|
||||
// A vision panel rather than a window: it looks at the corridor's neighbour
|
||||
// room, so the sill keeps it out of the collider and the head keeps it out
|
||||
// of anybody's eyeline from a seat.
|
||||
openings: [pane(1.2, 2.4, 1.0, 2.2)],
|
||||
},
|
||||
{
|
||||
id: "l2-plant-west",
|
||||
from: { x: L2_PROJECT_E, z: SPINE_S },
|
||||
to: { x: L2_PROJECT_E, z: DEPTH },
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* Two benches of twelve, facing each other across the studio.
|
||||
*
|
||||
* Seat ids are `studio-01` … `studio-24`, restarting at 01 as every bank's do.
|
||||
* They are unique building-wide because the prefix is — `eng`, `ops`, `design`,
|
||||
* `sales` and `lab` are all downstairs — which is the property that matters,
|
||||
* since a `Presence` binds to a seat id and ids are unique per kind across the
|
||||
* whole building rather than per level.
|
||||
*/
|
||||
const L2_DESK_BANKS: DeskBank[] = [
|
||||
{
|
||||
id: "studio",
|
||||
desk: DESK,
|
||||
chair: TASK_CHAIR,
|
||||
origin: { x: 8.4, z: 1.9 },
|
||||
rotation: 0,
|
||||
columns: 6,
|
||||
rows: 2,
|
||||
pitch: 1.7,
|
||||
rowPitch: 0.85,
|
||||
facingRows: true,
|
||||
},
|
||||
{
|
||||
// A second bench is a second bank. One `rowPitch` cannot express both the
|
||||
// 0.85 m that makes two rows meet back to back and the 2.4 m of chair,
|
||||
// aisle and chair between one bench and the next — that is a real limit of
|
||||
// the format and the reason every bench in this file is its own bank.
|
||||
id: "studio-b",
|
||||
desk: DESK,
|
||||
chair: TASK_CHAIR,
|
||||
origin: { x: 8.4, z: 6.1 },
|
||||
rotation: 0,
|
||||
columns: 6,
|
||||
rows: 2,
|
||||
pitch: 1.7,
|
||||
rowPitch: 0.85,
|
||||
facingRows: true,
|
||||
seatPrefix: "studio-b",
|
||||
},
|
||||
];
|
||||
|
||||
const L2_SEATS: Seat[] = [
|
||||
// The library: four at the long table, two in the window.
|
||||
{ id: "library-01", position: { x: 27.4, z: 3.0 }, facing: EAST, pose: "sit" },
|
||||
{ id: "library-02", position: { x: 27.4, z: 4.6 }, facing: EAST, pose: "sit" },
|
||||
{ id: "library-03", position: { x: 30.2, z: 3.0 }, facing: WEST, pose: "sit" },
|
||||
{ id: "library-04", position: { x: 30.2, z: 4.6 }, facing: WEST, pose: "sit" },
|
||||
{ id: "library-05", position: { x: 28.0, z: 8.4 }, facing: NORTH, pose: "sit" },
|
||||
{ id: "library-06", position: { x: 31.0, z: 8.4 }, facing: NORTH, pose: "sit" },
|
||||
|
||||
// Tiburon, eight around a 2.4 m table.
|
||||
{ id: "tiburon-01", position: { x: 3.0, z: 14.0 }, facing: EAST, pose: "sit" },
|
||||
{ id: "tiburon-02", position: { x: 3.0, z: 15.2 }, facing: EAST, pose: "sit" },
|
||||
{ id: "tiburon-03", position: { x: 3.0, z: 16.4 }, facing: EAST, pose: "sit" },
|
||||
{ id: "tiburon-04", position: { x: 5.4, z: 14.0 }, facing: WEST, pose: "sit" },
|
||||
{ id: "tiburon-05", position: { x: 5.4, z: 15.2 }, facing: WEST, pose: "sit" },
|
||||
{ id: "tiburon-06", position: { x: 5.4, z: 16.4 }, facing: WEST, pose: "sit" },
|
||||
{ id: "tiburon-07", position: { x: 4.2, z: 13.4 }, facing: SOUTH, pose: "sit" },
|
||||
{ id: "tiburon-08", position: { x: 4.2, z: 17.0 }, facing: NORTH, pose: "sit" },
|
||||
|
||||
// Angel Island, six.
|
||||
{ id: "angel-01", position: { x: 10.4, z: 14.4 }, facing: EAST, pose: "sit" },
|
||||
{ id: "angel-02", position: { x: 10.4, z: 15.8 }, facing: EAST, pose: "sit" },
|
||||
{ id: "angel-03", position: { x: 12.8, z: 14.4 }, facing: WEST, pose: "sit" },
|
||||
{ id: "angel-04", position: { x: 12.8, z: 15.8 }, facing: WEST, pose: "sit" },
|
||||
{ id: "angel-05", position: { x: 11.6, z: 13.8 }, facing: SOUTH, pose: "sit" },
|
||||
{ id: "angel-06", position: { x: 11.6, z: 16.6 }, facing: NORTH, pose: "sit" },
|
||||
|
||||
// The project room stands up. `pose: "stand"` is the only thing that tells a
|
||||
// consumer how tall to draw an occupant, and people do not sit at a wall of
|
||||
// work in progress.
|
||||
{ id: "project-01", position: { x: 17.4, z: 14.6 }, facing: NORTH, pose: "stand" },
|
||||
{ id: "project-02", position: { x: 19.0, z: 14.6 }, facing: NORTH, pose: "stand" },
|
||||
{ id: "project-03", position: { x: 20.6, z: 14.6 }, facing: NORTH, pose: "stand" },
|
||||
|
||||
// The gallery, looking down into the commons.
|
||||
{ id: "gallery-01", position: { x: 36.0, z: 5.0 }, facing: EAST, pose: "sit" },
|
||||
{ id: "gallery-02", position: { x: 36.0, z: 6.6 }, facing: EAST, pose: "sit" },
|
||||
{ id: "gallery-03", position: { x: 36.0, z: 12.0 }, facing: EAST, pose: "sit" },
|
||||
];
|
||||
|
||||
const L2_PROPS: Prop[] = [
|
||||
// -- The landing ----------------------------------------------------------
|
||||
{ id: "l2-landing-plant", kind: TREE, position: { x: 2.2, z: 2.4 }, rotation: NORTH },
|
||||
...scatter("l2-landing-locker", LOCKER, grid(0 + EXT_FACE + 0.25, 5.0, 1, 3, 0, 1.3), {
|
||||
rotation: WEST,
|
||||
}),
|
||||
...scatter("l2-landing-light", PENDANT, grid(3.2, 3.0, 1, 3, 0, 3.0), { elevation: CEILING }),
|
||||
|
||||
// -- The studio -----------------------------------------------------------
|
||||
//
|
||||
// A monitor per station is not written out here, and deliberately: thirty-nine
|
||||
// monitor props that have to be kept in step with a bank somebody will move
|
||||
// next week is the failure mode the README's "Registering your own assets"
|
||||
// section exists to prevent. Register a desk that builds a desk with a monitor
|
||||
// on it and every station in every bank in the building gets one.
|
||||
...scatter("l2-studio-ped", PEDESTAL, grid(8.4, 3.4, 6, 1, 1.7, 0)),
|
||||
...scatter("l2-studio-part", PARTITION, grid(9.25, 2.3, 5, 1, 1.7, 0)),
|
||||
...scatter("l2-studio-part-b", PARTITION, grid(9.25, 6.5, 5, 1, 1.7, 0)),
|
||||
...scatter("l2-studio-light", TROFFER, grid(8.0, 2.0, 5, 3, 3.4, 3.2), { elevation: CEILING }),
|
||||
{ id: "l2-studio-board", kind: WHITEBOARD, position: { x: 20.0, z: SPINE_N - INT_FACE - BOARD_OFFSET }, rotation: SOUTH, elevation: 1.0 },
|
||||
...scatter("l2-studio-plant", PLANT, [
|
||||
{ x: 7.2, z: 9.4 },
|
||||
{ x: 24.2, z: 9.4 },
|
||||
{ x: 24.2, z: 1.2 },
|
||||
]),
|
||||
|
||||
// -- The library ----------------------------------------------------------
|
||||
...scatter("l2-library-shelf", SHELF, grid(BLOCK_E - EXT_FACE - 0.2, 1.4, 1, 6, 0, 1.0), {
|
||||
rotation: EAST,
|
||||
}),
|
||||
{ id: "l2-library-table", kind: MEETING_TABLE, position: { x: 28.8, z: 3.8 }, rotation: NORTH },
|
||||
...scatter("l2-library-chair", TASK_CHAIR, [
|
||||
{ x: 27.4, z: 3.0 },
|
||||
{ x: 27.4, z: 4.6 },
|
||||
{ x: 30.2, z: 3.0 },
|
||||
{ x: 30.2, z: 4.6 },
|
||||
]),
|
||||
{ id: "l2-library-rug", kind: RUG, position: { x: 29.6, z: 8.0 }, rotation: NORTH, colorKey: "focus" },
|
||||
...scatter("l2-library-lounge", LOUNGE_CHAIR, [
|
||||
{ x: 28.0, z: 8.4 },
|
||||
{ x: 31.0, z: 8.4 },
|
||||
]),
|
||||
{ id: "l2-library-side", kind: SIDE_TABLE, position: { x: 29.5, z: 8.4 }, rotation: NORTH },
|
||||
...scatter("l2-library-light", PENDANT, grid(27.4, 3.8, 2, 1, 2.8, 0), { elevation: CEILING }),
|
||||
|
||||
// -- Tiburon and Angel Island ---------------------------------------------
|
||||
{ id: "l2-tiburon-table", kind: MEETING_TABLE, position: { x: 4.2, z: 15.2 }, rotation: NORTH },
|
||||
...scatter("l2-tiburon-chair", TASK_CHAIR, [
|
||||
{ x: 3.0, z: 14.0 },
|
||||
{ x: 3.0, z: 15.2 },
|
||||
{ x: 3.0, z: 16.4 },
|
||||
{ x: 5.4, z: 14.0 },
|
||||
{ x: 5.4, z: 15.2 },
|
||||
{ x: 5.4, z: 16.4 },
|
||||
{ x: 4.2, z: 13.4 },
|
||||
{ x: 4.2, z: 17.0 },
|
||||
]),
|
||||
{
|
||||
id: "l2-tiburon-display",
|
||||
kind: DISPLAY,
|
||||
position: { x: 4.2, z: SPINE_S + INT_FACE + DISPLAY_OFFSET },
|
||||
rotation: NORTH,
|
||||
elevation: 1.15,
|
||||
},
|
||||
...scatter("l2-tiburon-light", TROFFER, grid(2.8, 14.4, 2, 2, 2.8, 2.0), { elevation: CEILING }),
|
||||
|
||||
{ id: "l2-angel-table", kind: MEETING_TABLE, position: { x: 11.6, z: 15.2 }, rotation: NORTH },
|
||||
...scatter("l2-angel-chair", TASK_CHAIR, [
|
||||
{ x: 10.4, z: 14.4 },
|
||||
{ x: 10.4, z: 15.8 },
|
||||
{ x: 12.8, z: 14.4 },
|
||||
{ x: 12.8, z: 15.8 },
|
||||
{ x: 11.6, z: 13.8 },
|
||||
{ x: 11.6, z: 16.6 },
|
||||
]),
|
||||
{
|
||||
id: "l2-angel-board",
|
||||
kind: WHITEBOARD,
|
||||
position: { x: 11.6, z: SPINE_S + INT_FACE + BOARD_OFFSET },
|
||||
rotation: NORTH,
|
||||
elevation: 1.0,
|
||||
},
|
||||
...scatter("l2-angel-light", TROFFER, grid(10.4, 14.6, 2, 2, 2.4, 2.0), { elevation: CEILING }),
|
||||
|
||||
// -- The project room -----------------------------------------------------
|
||||
...scatter("l2-project-board", WHITEBOARD, grid(17.4, SPINE_S + INT_FACE + BOARD_OFFSET, 3, 1, 3.0, 0), {
|
||||
rotation: NORTH,
|
||||
elevation: 1.0,
|
||||
}),
|
||||
{ id: "l2-project-table", kind: MEETING_TABLE, position: { x: 19.8, z: 16.4 }, rotation: NORTH },
|
||||
...scatter("l2-project-shelf", SHELF, grid(L2_PROJECT_E - INT_FACE - 0.2, 14.0, 1, 2, 0, 1.1), {
|
||||
rotation: EAST,
|
||||
}),
|
||||
...scatter("l2-project-light", TROFFER, grid(17.0, 14.4, 3, 2, 3.2, 2.4), { elevation: CEILING }),
|
||||
|
||||
// -- Plant ----------------------------------------------------------------
|
||||
...scatter("l2-plant-shelf", SHELF, grid(BLOCK_E - EXT_FACE - 0.2, 14.0, 1, 3, 0, 1.1), {
|
||||
rotation: EAST,
|
||||
audience: "private",
|
||||
}),
|
||||
...scatter("l2-plant-light", TROFFER, grid(26.4, 14.8, 2, 1, 2.4, 0), { elevation: 2.6 }),
|
||||
|
||||
// -- The gallery ----------------------------------------------------------
|
||||
//
|
||||
// Furnished as a place to sit rather than as a route, which is what a balcony
|
||||
// over a double-height room is for. Everything is set back from the
|
||||
// balustrade: a chair against a glass rail is a chair nobody chooses.
|
||||
...scatter("l2-gallery-chair", LOUNGE_CHAIR, [
|
||||
{ x: 36.0, z: 5.0 },
|
||||
{ x: 36.0, z: 6.6 },
|
||||
{ x: 36.0, z: 12.0 },
|
||||
], { rotation: EAST }),
|
||||
...scatter("l2-gallery-side", SIDE_TABLE, [
|
||||
{ x: 36.0, z: 5.8 },
|
||||
{ x: 36.0, z: 12.8 },
|
||||
]),
|
||||
...scatter("l2-gallery-plant", PLANT, [
|
||||
{ x: 35.2, z: 3.0 },
|
||||
{ x: 35.2, z: 15.0 },
|
||||
]),
|
||||
];
|
||||
|
||||
const L2_ZONES: Zone[] = [
|
||||
// Spatial, so both audiences get them — the same rule the level below follows.
|
||||
{
|
||||
id: "l2-zone-studio",
|
||||
name: "Studio",
|
||||
outline: rect(L2_STUDIO_W, 0, L2_LIBRARY_W, SPINE_N),
|
||||
colorKey: "team-b",
|
||||
audience: "private",
|
||||
},
|
||||
{
|
||||
id: "l2-zone-quiet",
|
||||
name: "Quiet",
|
||||
outline: rect(L2_LIBRARY_W, 0, BLOCK_E, SPINE_N),
|
||||
colorKey: "focus",
|
||||
},
|
||||
{
|
||||
id: "l2-zone-gallery",
|
||||
name: "Gallery",
|
||||
outline: rect(BLOCK_E, 2.0, GALLERY_E, 16.0),
|
||||
colorKey: "social",
|
||||
},
|
||||
];
|
||||
|
||||
// ---- Viewpoints -----------------------------------------------------------
|
||||
@@ -1283,9 +1999,14 @@ const VIEWPOINTS: Viewpoint[] = [
|
||||
label: "The Whole Floor",
|
||||
shortLabel: "The Floor",
|
||||
levelId: "level-1",
|
||||
focus: { at: { x: 17.0, z: 9.0 }, distance: 32, height: 14, rotation: 0.55 },
|
||||
// Aimed at the middle of the *whole plate* rather than of the block, and
|
||||
// pulled back far enough to hold 48 m of it. Both numbers moved when the
|
||||
// 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 },
|
||||
description:
|
||||
"Thirty-four metres by eighteen, one storey, glazed along the north edge. Everything in this building is somewhere in this frame.",
|
||||
"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.",
|
||||
},
|
||||
{
|
||||
id: "reception",
|
||||
@@ -1327,6 +2048,41 @@ const VIEWPOINTS: Viewpoint[] = [
|
||||
description:
|
||||
"The social corner, where the lounge and the kitchen share a glazed edge and the only wall between them and the desk floor is the one with the archway in it.",
|
||||
},
|
||||
{
|
||||
id: "commons",
|
||||
number: "06",
|
||||
label: "The Commons",
|
||||
shortLabel: "Commons",
|
||||
levelId: "level-1",
|
||||
// Low and looking up the length of the wing, because the thing worth seeing
|
||||
// here is the height. An establishing shot from above would show a big empty
|
||||
// floor and none of what makes it big.
|
||||
focus: { at: { x: 41.0, z: 9.0 }, distance: 15, height: 3.2, rotation: 2.1 },
|
||||
description:
|
||||
"Fourteen metres of floor open all the way to the roof, with the gallery cutting across one side of it. The lounge and the kitchen look into this through the glass that used to be the outside wall.",
|
||||
},
|
||||
{
|
||||
id: "studio",
|
||||
number: "07",
|
||||
label: "The Studio",
|
||||
shortLabel: "Studio",
|
||||
levelId: "level-2",
|
||||
focus: { at: { x: 15.6, z: 4.6 }, distance: 15, height: 4.6, rotation: 0.35 },
|
||||
description:
|
||||
"Level 2: nineteen metres of unbroken north-lit floor and twenty-four seats in two benches. The one run downstairs cannot offer, because the lobby wall and the booths interrupt it.",
|
||||
},
|
||||
{
|
||||
id: "gallery",
|
||||
number: "08",
|
||||
label: "The Gallery",
|
||||
shortLabel: "Gallery",
|
||||
levelId: "level-2",
|
||||
// Standing at the rail rather than behind it, which is the pose that shows
|
||||
// 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 pack -------------------------------------------------------------
|
||||
@@ -1334,10 +2090,6 @@ const VIEWPOINTS: Viewpoint[] = [
|
||||
const LEVEL_1: Level = {
|
||||
id: "level-1",
|
||||
name: "Level 1",
|
||||
// Ground. A second storey would repeat this object with `elevation: 4.2` —
|
||||
// storey height, not ceiling height — and `Plan` adds the offset to every
|
||||
// coordinate it resolves, exactly once, so both levels can go into one scene
|
||||
// group sitting at the origin.
|
||||
elevation: 0,
|
||||
wallHeight: CEILING,
|
||||
wallThickness: INT_THICKNESS,
|
||||
@@ -1352,14 +2104,40 @@ const LEVEL_1: Level = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* The upper storey, at `STOREY` above the ground floor.
|
||||
*
|
||||
* `elevation` is floor-to-*floor* and not floor-to-ceiling, which is the number
|
||||
* people get wrong: 2.8 m would put level 2's slab in level 1's ceiling void.
|
||||
* `Plan` adds this to every coordinate on the level exactly once, so the
|
||||
* `L2_*` section above is authored with its own floor at zero and neither storey
|
||||
* has to know the other's height.
|
||||
*/
|
||||
const LEVEL_2: Level = {
|
||||
id: "level-2",
|
||||
name: "Level 2",
|
||||
elevation: STOREY,
|
||||
wallHeight: CEILING,
|
||||
wallThickness: INT_THICKNESS,
|
||||
wallSurface: PAINT,
|
||||
floorplan: {
|
||||
rooms: L2_ROOMS,
|
||||
walls: L2_WALLS,
|
||||
props: L2_PROPS,
|
||||
deskBanks: L2_DESK_BANKS,
|
||||
seats: L2_SEATS,
|
||||
zones: L2_ZONES,
|
||||
},
|
||||
};
|
||||
|
||||
export const LUMBRIDGE_HQ: Office = {
|
||||
id: "lumbridge-hq",
|
||||
name: "Lumbridge HQ",
|
||||
levels: [LEVEL_1],
|
||||
levels: [LEVEL_1, LEVEL_2],
|
||||
viewpoints: VIEWPOINTS,
|
||||
meta: {
|
||||
description:
|
||||
"The reference office: one level, fifteen rooms, seventy-six seats. Copy this file, change the numbers, keep the seat ids.",
|
||||
"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.",
|
||||
author: "Lumbridge",
|
||||
// The art in this repo is Apache-2.0 with the artistic output additionally
|
||||
// dedicated under CC0-1.0 (CONTRACT.md §3.1). A pack is artistic output, so
|
||||
|
||||
Reference in New Issue
Block a user