af0d4a7d57
**Lights.** A sited office follows the real sun, and the real sun spends
half its time below the horizon — which was producing a technically
correct and completely useless picture: an unlit floor plate at midnight
in a building whose whole premise is that you can see who is at which
desk. `luminaires.ts` brings the diffusers up as the sun goes down and
reports one scalar for how much interior light there is; `withHouseLights`
adds it to the rig. CONTRACT §4's rule that a fitting emits no light is
kept in full — nothing here is a light source, and the rig still has one
owner.
**And they notice you.** A fitting within four metres of somebody walking
underneath brightens and fades back as they leave, which is what an
occupancy-sensed floor actually does at night. They are one `InstancedMesh`
sharing one material, so `emissiveIntensity` cannot vary between them —
`instanceColor` can, but three multiplies it into the diffuse term only, so
six lines of `onBeforeCompile` carry it into the emissive term as well. The
alternative was one mesh per fitting: forty draw calls of ceiling in a
building that spends about twenty on everything.
**Optimus.** A posable Gen-3 humanoid — eleven articulating joints, pale
shells over a dark frame, a black visor — with a walk cycle driven by
*distance travelled* rather than wall-clock, so the feet do not slide when
a robot slows down. Two per floor, derived from the pack's levels, so the
two-storey tower gets four and the hangar gets two without either pack
knowing robots exist. They wander between reachable points using
`Plan.blocked` — the collider the wall split already produces — and they
are deliberately **not** gated on `depth`: the build-time-exclusion rule is
about occupancy, and a robot is nobody.
**Starlinks stop being pixels.** The sixty-four nearest the centre of view
grow real geometry — a flat bus with ONE large solar array, which is the
actual signature and the thing everybody draws symmetrically and wrong —
fading in so there is no pop where a point becomes a mesh. Two draw calls.
The sun for their attitude comes from `solar.ts` and not from the rig,
because `atmosphere.ts` floors the light direction to keep the shadow
camera usable, and a sun ten degrees *down* is exactly the dusk geometry
that makes a pass visible.
**Aircraft** are airliners now — swept wings, nacelles, a fin — instead of
an arrowhead, still one shared geometry facing +Z as `flights.ts` requires.
**Clouds** drift over the board, driven by observed cover, lit by the rig
rather than by themselves.
Four modules were built by subagents and reviewed by another; every one
came back `needs-work` and the reviews were right. Fixed before wiring:
- The walk cycle's arms were a quarter cycle out of step with its legs —
the legs are cosine-shaped and the arms were on `sin`, so at the
instant the left leg reached full forward the left shoulder was at dead
neutral. Uncanny, and hard to name until it is pointed at.
- Every Optimus shell used a `roundedBox` radius of 0.12–0.22, which that
primitive turns into a near-circular cross-section — the figure was
built out of lozenges, not panels. The rest of the library uses
0.02–0.09.
- The cloud material was `transparent` + `DoubleSide` without
`forceSinglePass`, so three rendered it twice per frame *and* bumped
`material.version` on each pass — rebuilding the program cache key
forever, on the one layer that is fill-rate bound.
- `starlinkMesh.dispose()` freed the geometries but not the
`InstancedMesh`es, orphaning their instance buffers on every city
switch.
- The airliner's tailplane roots sat outside the tail cone and hung in
free air over most of their chord.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
85 lines
2.7 KiB
TypeScript
85 lines
2.7 KiB
TypeScript
/**
|
|
* The `tera:` office catalogue — every built-in asset, in one list.
|
|
*
|
|
* Importing this module registers all of them into the shared `kit`, which is
|
|
* what `kit.ts` says that registry is for. A self-hoster who wants their own
|
|
* registry instead calls `registerOfficeAssets(mine)`; one who wants ours plus
|
|
* theirs registers `acme:desk.standing` with `overrides: "tera:desk.workstation"`
|
|
* afterwards and every desk in every pack becomes theirs, with no fork.
|
|
*
|
|
* ### What is deliberately not here
|
|
*
|
|
* There is no `shell.wall`, `shell.door` or `shell.window` (CONTRACT.md §2).
|
|
* Walls are the `Floorplan`'s wall runs and a door or a window is an `Opening`
|
|
* punched out of one; `Plan` hands each solid run left over to the `wallRun`
|
|
* part in `parts.ts`. Shipping door props beside door-shaped holes would put
|
|
* every opening in the scene twice, or — worse, because it is invisible until
|
|
* somebody walks through a wall — leave the collider with no gap where the door
|
|
* is.
|
|
*
|
|
* Seventeen assets is not a furniture catalogue and is not trying to be. It is
|
|
* the set that gets a real floor plate looking like an office: somewhere to
|
|
* work, somewhere to sit, somewhere to meet, somewhere to put things, something
|
|
* to look at, something alive, and light.
|
|
*/
|
|
|
|
import { kit, type AnyAsset, type AssetRegistry } from "../kit.ts";
|
|
import { deskPartition, deskPedestal, deskWorkstation } from "./desks.ts";
|
|
import { plantPotted, plantTall } from "./greenery.ts";
|
|
import { lightPendant, lightTroffer } from "./lighting.ts";
|
|
import { robotOptimus } from "./optimus.ts";
|
|
import { screenMonitor, screenWallDisplay } from "./screens.ts";
|
|
import { seatLounge, seatTaskChair } from "./seating.ts";
|
|
import { storageLocker, storageShelf } from "./storage.ts";
|
|
import { rug, whiteboard } from "./surfaces.ts";
|
|
import { tableMeeting, tableSide } from "./tables.ts";
|
|
|
|
export const OFFICE_ASSETS: readonly AnyAsset[] = [
|
|
deskWorkstation,
|
|
deskPedestal,
|
|
deskPartition,
|
|
seatTaskChair,
|
|
seatLounge,
|
|
tableMeeting,
|
|
tableSide,
|
|
storageShelf,
|
|
storageLocker,
|
|
screenMonitor,
|
|
screenWallDisplay,
|
|
plantPotted,
|
|
plantTall,
|
|
lightPendant,
|
|
lightTroffer,
|
|
robotOptimus,
|
|
rug,
|
|
whiteboard,
|
|
];
|
|
|
|
/** Register the built-in catalogue into a registry. Defaults to the shared one. */
|
|
export function registerOfficeAssets(registry: AssetRegistry = kit): AssetRegistry {
|
|
return registry.registerAll(OFFICE_ASSETS);
|
|
}
|
|
|
|
registerOfficeAssets();
|
|
|
|
export {
|
|
deskPartition,
|
|
deskPedestal,
|
|
deskWorkstation,
|
|
lightPendant,
|
|
lightTroffer,
|
|
robotOptimus,
|
|
plantPotted,
|
|
plantTall,
|
|
rug,
|
|
screenMonitor,
|
|
screenWallDisplay,
|
|
seatLounge,
|
|
seatTaskChair,
|
|
storageLocker,
|
|
storageShelf,
|
|
tableMeeting,
|
|
tableSide,
|
|
whiteboard,
|
|
};
|