@kerros/viewer 0.0.0-stage → 0.1.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +31 -2
- package/dist/adapters/basemap.js +11 -0
- package/dist/adapters/basemap.js.map +1 -0
- package/dist/adapters/persistence.js +121 -0
- package/dist/adapters/persistence.js.map +1 -0
- package/dist/adapters/status.js +18 -0
- package/dist/adapters/status.js.map +1 -0
- package/dist/components/ElevatorPanel.js +120 -0
- package/dist/components/ElevatorPanel.js.map +1 -0
- package/dist/components/Icons.js +57 -0
- package/dist/components/Icons.js.map +1 -0
- package/dist/components/Inspector.js +1184 -0
- package/dist/components/Inspector.js.map +1 -0
- package/dist/components/NavigatePanel.js +301 -0
- package/dist/components/NavigatePanel.js.map +1 -0
- package/dist/components/NavigationGraph.js +234 -0
- package/dist/components/NavigationGraph.js.map +1 -0
- package/dist/components/StructureExplorer.js +510 -0
- package/dist/components/StructureExplorer.js.map +1 -0
- package/dist/components/StructureView.js +286 -0
- package/dist/components/StructureView.js.map +1 -0
- package/dist/components/controls.js +170 -0
- package/dist/components/controls.js.map +1 -0
- package/dist/components/graphLayout.js +27 -0
- package/dist/components/graphLayout.js.map +1 -0
- package/dist/host.js +169 -0
- package/dist/host.js.map +1 -0
- package/dist/i18n.js +88 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.js +171 -0
- package/dist/index.js.map +1 -0
- package/dist/map/CabinMaterials.js +81 -0
- package/dist/map/CabinMaterials.js.map +1 -0
- package/dist/map/CabinMirror.js +43 -0
- package/dist/map/CabinMirror.js.map +1 -0
- package/dist/map/Doors.js +80 -0
- package/dist/map/Doors.js.map +1 -0
- package/dist/map/ElevatorCabin.js +93 -0
- package/dist/map/ElevatorCabin.js.map +1 -0
- package/dist/map/FixtureLights.js +117 -0
- package/dist/map/FixtureLights.js.map +1 -0
- package/dist/map/MapCanvas.js +2161 -0
- package/dist/map/MapCanvas.js.map +1 -0
- package/dist/map/Passenger.js +69 -0
- package/dist/map/Passenger.js.map +1 -0
- package/dist/map/SceneLayer.js +1534 -0
- package/dist/map/SceneLayer.js.map +1 -0
- package/dist/map/UndergroundContext.js +153 -0
- package/dist/map/UndergroundContext.js.map +1 -0
- package/dist/map/ambience.js +194 -0
- package/dist/map/ambience.js.map +1 -0
- package/dist/map/architecture.js +305 -0
- package/dist/map/architecture.js.map +1 -0
- package/dist/map/bathMusic.js +92 -0
- package/dist/map/bathMusic.js.map +1 -0
- package/dist/map/cameraAim.js +33 -0
- package/dist/map/cameraAim.js.map +1 -0
- package/dist/map/elevators.js +56 -0
- package/dist/map/elevators.js.map +1 -0
- package/dist/map/excavation.js +52 -0
- package/dist/map/excavation.js.map +1 -0
- package/dist/map/exteriors.js +25 -0
- package/dist/map/exteriors.js.map +1 -0
- package/dist/map/features.js +218 -0
- package/dist/map/features.js.map +1 -0
- package/dist/map/fences.js +29 -0
- package/dist/map/fences.js.map +1 -0
- package/dist/map/journey.js +112 -0
- package/dist/map/journey.js.map +1 -0
- package/dist/map/levels.js +6 -0
- package/dist/map/levels.js.map +1 -0
- package/dist/map/lighting.js +142 -0
- package/dist/map/lighting.js.map +1 -0
- package/dist/map/loadBasemap.js +26 -0
- package/dist/map/loadBasemap.js.map +1 -0
- package/dist/map/materials.js +183 -0
- package/dist/map/materials.js.map +1 -0
- package/dist/map/poolLighting.js +39 -0
- package/dist/map/poolLighting.js.map +1 -0
- package/dist/map/projection.js +24 -0
- package/dist/map/projection.js.map +1 -0
- package/dist/map/rampGeometry.js +38 -0
- package/dist/map/rampGeometry.js.map +1 -0
- package/dist/map/route.js +107 -0
- package/dist/map/route.js.map +1 -0
- package/dist/map/stairSurfaces.js +115 -0
- package/dist/map/stairSurfaces.js.map +1 -0
- package/dist/map/surfaces.js +136 -0
- package/dist/map/surfaces.js.map +1 -0
- package/dist/map/textures.js +95 -0
- package/dist/map/textures.js.map +1 -0
- package/dist/map/underground.js +34 -0
- package/dist/map/underground.js.map +1 -0
- package/dist/map/walk.js +433 -0
- package/dist/map/walk.js.map +1 -0
- package/dist/map/walkContext.js +46 -0
- package/dist/map/walkContext.js.map +1 -0
- package/dist/map/walkDimensions.js +7 -0
- package/dist/map/walkDimensions.js.map +1 -0
- package/dist/map/walkJourney.js +85 -0
- package/dist/map/walkJourney.js.map +1 -0
- package/dist/map/walkSurfaces.js +106 -0
- package/dist/map/walkSurfaces.js.map +1 -0
- package/dist/map/wallJoins.js +70 -0
- package/dist/map/wallJoins.js.map +1 -0
- package/dist/map/water.js +274 -0
- package/dist/map/water.js.map +1 -0
- package/dist/model/authoring.js +80 -0
- package/dist/model/authoring.js.map +1 -0
- package/dist/model/boundaries.js +548 -0
- package/dist/model/boundaries.js.map +1 -0
- package/dist/model/coverage.js +30 -0
- package/dist/model/coverage.js.map +1 -0
- package/dist/model/document.js +52 -0
- package/dist/model/document.js.map +1 -0
- package/dist/model/doors.js +47 -0
- package/dist/model/doors.js.map +1 -0
- package/dist/model/factory.js +56 -0
- package/dist/model/factory.js.map +1 -0
- package/dist/model/geometry.js +394 -0
- package/dist/model/geometry.js.map +1 -0
- package/dist/model/inference.js +182 -0
- package/dist/model/inference.js.map +1 -0
- package/dist/model/materials.js +11 -0
- package/dist/model/materials.js.map +1 -0
- package/dist/model/mutations.js +157 -0
- package/dist/model/mutations.js.map +1 -0
- package/dist/model/navigation.js +275 -0
- package/dist/model/navigation.js.map +1 -0
- package/dist/model/ontology.js +109 -0
- package/dist/model/ontology.js.map +1 -0
- package/dist/model/passages.js +5 -0
- package/dist/model/passages.js.map +1 -0
- package/dist/model/portals.js +42 -0
- package/dist/model/portals.js.map +1 -0
- package/dist/model/precision.js +11 -0
- package/dist/model/precision.js.map +1 -0
- package/dist/model/project.js +17 -0
- package/dist/model/project.js.map +1 -0
- package/dist/model/ramps.js +10 -0
- package/dist/model/ramps.js.map +1 -0
- package/dist/model/roomNavigation.js +87 -0
- package/dist/model/roomNavigation.js.map +1 -0
- package/dist/model/routeClearance.js +72 -0
- package/dist/model/routeClearance.js.map +1 -0
- package/dist/model/spaces.js +104 -0
- package/dist/model/spaces.js.map +1 -0
- package/dist/model/stairGeometry.js +40 -0
- package/dist/model/stairGeometry.js.map +1 -0
- package/dist/model/stairTraversal.js +48 -0
- package/dist/model/stairTraversal.js.map +1 -0
- package/dist/model/topology.js +63 -0
- package/dist/model/topology.js.map +1 -0
- package/dist/model/types.js +35 -0
- package/dist/model/types.js.map +1 -0
- package/dist/model/validate.js +240 -0
- package/dist/model/validate.js.map +1 -0
- package/dist/model/vertical.js +129 -0
- package/dist/model/vertical.js.map +1 -0
- package/dist/model/walls.js +71 -0
- package/dist/model/walls.js.map +1 -0
- package/dist/styles.css +4931 -0
- package/dist/theme/index.js +34 -0
- package/dist/theme/index.js.map +1 -0
- package/dist/types/adapters/basemap.d.ts +2 -0
- package/dist/types/adapters/persistence.d.ts +29 -0
- package/dist/types/adapters/status.d.ts +4 -0
- package/dist/types/components/ElevatorPanel.d.ts +18 -0
- package/dist/types/components/Icons.d.ts +8 -0
- package/dist/types/components/Inspector.d.ts +38 -0
- package/dist/types/components/NavigatePanel.d.ts +27 -0
- package/dist/types/components/NavigationGraph.d.ts +10 -0
- package/dist/types/components/StructureExplorer.d.ts +8 -0
- package/dist/types/components/StructureView.d.ts +22 -0
- package/dist/types/components/controls.d.ts +52 -0
- package/dist/types/components/graphLayout.d.ts +9 -0
- package/dist/types/i18n.d.ts +85 -0
- package/dist/types/import/analysisPreview.d.ts +27 -0
- package/dist/types/import/brief.d.ts +22 -0
- package/dist/types/import/checkpoint.d.ts +49 -0
- package/dist/types/import/instructions.d.ts +7 -0
- package/dist/types/import/usage.d.ts +10 -0
- package/dist/types/map/CabinMaterials.d.ts +18 -0
- package/dist/types/map/CabinMirror.d.ts +13 -0
- package/dist/types/map/Doors.d.ts +11 -0
- package/dist/types/map/ElevatorCabin.d.ts +20 -0
- package/dist/types/map/FixtureLights.d.ts +35 -0
- package/dist/types/map/MapCanvas.d.ts +87 -0
- package/dist/types/map/Passenger.d.ts +18 -0
- package/dist/types/map/SceneLayer.d.ts +306 -0
- package/dist/types/map/UndergroundContext.d.ts +18 -0
- package/dist/types/map/ambience.d.ts +29 -0
- package/dist/types/map/architecture.d.ts +8 -0
- package/dist/types/map/bathMusic.d.ts +14 -0
- package/dist/types/map/cameraAim.d.ts +20 -0
- package/dist/types/map/elevators.d.ts +16 -0
- package/dist/types/map/excavation.d.ts +9 -0
- package/dist/types/map/exteriors.d.ts +3 -0
- package/dist/types/map/features.d.ts +33 -0
- package/dist/types/map/fences.d.ts +4 -0
- package/dist/types/map/journey.d.ts +36 -0
- package/dist/types/map/levels.d.ts +4 -0
- package/dist/types/map/lighting.d.ts +103 -0
- package/dist/types/map/loadBasemap.d.ts +4 -0
- package/dist/types/map/materials.d.ts +38 -0
- package/dist/types/map/poolLighting.d.ts +11 -0
- package/dist/types/map/projection.d.ts +9 -0
- package/dist/types/map/rampGeometry.d.ts +8 -0
- package/dist/types/map/route.d.ts +59 -0
- package/dist/types/map/stairSurfaces.d.ts +29 -0
- package/dist/types/map/surfaces.d.ts +36 -0
- package/dist/types/map/textures.d.ts +8 -0
- package/dist/types/map/underground.d.ts +30 -0
- package/dist/types/map/walk.d.ts +232 -0
- package/dist/types/map/walkContext.d.ts +11 -0
- package/dist/types/map/walkDimensions.d.ts +5 -0
- package/dist/types/map/walkJourney.d.ts +33 -0
- package/dist/types/map/walkSurfaces.d.ts +27 -0
- package/dist/types/map/wallJoins.d.ts +6 -0
- package/dist/types/map/water.d.ts +12 -0
- package/dist/types/model/authoring.d.ts +38 -0
- package/dist/types/model/boundaries.d.ts +41 -0
- package/dist/types/model/coverage.d.ts +8 -0
- package/dist/types/model/document.d.ts +9 -0
- package/dist/types/model/doors.d.ts +19 -0
- package/dist/types/model/factory.d.ts +5 -0
- package/dist/types/model/geometry.d.ts +99 -0
- package/dist/types/model/host.d.ts +154 -0
- package/dist/types/model/inference.d.ts +46 -0
- package/dist/types/model/live.d.ts +60 -0
- package/dist/types/model/materials.d.ts +28 -0
- package/dist/types/model/mutations.d.ts +178 -0
- package/dist/types/model/navigation.d.ts +70 -0
- package/dist/types/model/ontology.d.ts +43 -0
- package/dist/types/model/passages.d.ts +2 -0
- package/dist/types/model/portals.d.ts +9 -0
- package/dist/types/model/precision.d.ts +11 -0
- package/dist/types/model/project.d.ts +8 -0
- package/dist/types/model/ramps.d.ts +7 -0
- package/dist/types/model/roomNavigation.d.ts +15 -0
- package/dist/types/model/routeClearance.d.ts +11 -0
- package/dist/types/model/spaces.d.ts +46 -0
- package/dist/types/model/stairGeometry.d.ts +27 -0
- package/dist/types/model/stairTraversal.d.ts +8 -0
- package/dist/types/model/topology.d.ts +14 -0
- package/dist/types/model/types.d.ts +369 -0
- package/dist/types/model/validate.d.ts +38 -0
- package/dist/types/model/vertical.d.ts +145 -0
- package/dist/types/model/walls.d.ts +71 -0
- package/dist/types/schema/index.d.ts +25 -0
- package/dist/types/theme/index.d.ts +55 -0
- package/dist/types/viewer/FloorViewer.d.ts +76 -0
- package/dist/types/viewer/ViewerWorkspace.d.ts +2 -0
- package/dist/types/viewer/host.d.ts +11 -0
- package/dist/types/viewer/index.d.ts +2 -0
- package/dist/types/viewer/panels.d.ts +12 -0
- package/dist/viewer/FloorViewer.js +104 -0
- package/dist/viewer/FloorViewer.js.map +1 -0
- package/dist/viewer/ViewerWorkspace.js +370 -0
- package/dist/viewer/ViewerWorkspace.js.map +1 -0
- package/dist/viewer/panels.js +35 -0
- package/dist/viewer/panels.js.map +1 -0
- package/package.json +58 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SceneLayer.js","sources":["../../../../src/map/SceneLayer.ts"],"sourcesContent":["import { makeDoor } from './Doors';\nimport { fenceGeometry } from './fences';\nimport * as THREE from 'three';\nimport polygonClipping from 'polygon-clipping';\nimport {\n MercatorCoordinate,\n type CustomLayerInterface,\n type Map as MapLibreMap,\n type CustomRenderMethodInput,\n} from 'maplibre-gl';\nimport type { Floor, MaterialKind, Point, ProjectDocument, Ring, SiteObject, Slope } from '../model/types';\nimport type { Route } from '../model/navigation';\nimport { legStepIndices, ROUTE_COLOR, routeTrackImage, TRACK_PIXELS, TRACK_TILE } from './route';\nimport {\n add as addPoint,\n barrierEnds,\n closeRing,\n objectArea,\n objectPosition,\n objectRotation,\n openRing,\n rectangle,\n ringArea,\n rotate,\n toLngLat,\n} from '../model/geometry';\nimport { distance, pointInRing } from '../model/geometry';\nimport { floorOutline, mainAxis } from '../model/walls';\nimport { COLORS, objectRings, type WallPiece, wallPieces } from './features';\nimport {\n type Flight,\n flightRun,\n type FlightRun,\n flights,\n flightsAt,\n isVertical,\n reaches,\n servedFloors,\n shaftVoids,\n type VoidOptions,\n type StairModel,\n stairModel,\n} from '../model/vertical';\nimport type { StatusReading } from '../model/live';\nimport { makeFixture, makeRoof } from './architecture';\nimport { MaterialLibrary } from './materials';\nimport { EXTERIOR_PRESETS } from '../model/materials';\nimport type { MapStyleOptions } from '../theme';\nimport { exteriorWalls } from './exteriors';\nimport { mergeGeometries } from 'three/addons/utils/BufferGeometryUtils.js';\nimport { hitEntity, metricUVs, OUTSIDE, splitWallFace, SurfaceBatch } from './surfaces';\nimport { excavationRings } from './excavation';\nimport { floorIndex, MAX_CAGE_LEVELS, type UndergroundView, undergroundView } from './underground';\nimport { UndergroundCage, undergroundPit } from './UndergroundContext';\nimport { includeSceneDepth, walkNearPlane } from './projection';\nimport { syncLightingCamera } from './projection';\nimport type { SurfaceFinish } from './textures';\nimport { ambient, FIXED, type Sun, sunlight } from './lighting';\nimport { FixtureLights } from './FixtureLights';\nimport { EYE } from './walk';\nimport { tallSpaceContext } from './walkSurfaces';\nimport { walkVoidContext, walkConnectionContext } from './walkContext';\nimport { rampJoins } from '../model/ramps';\nimport { rampVoids, rampSections } from './rampGeometry';\nexport { rampJoins } from '../model/ramps';\nexport { rampVoids } from './rampGeometry';\nimport { applyPoolCaustics, makePool, makeWaterSlide } from './water';\nimport { cabinDimensions, cabinFloorVoids, elevatorDoorWidth, elevatorWalls } from './elevators';\nimport { CabinMaterials } from './CabinMaterials';\nimport { CabinMirror, REFLECTION_BODY } from './CabinMirror';\nimport { makeCabinDoor, makeElevatorCabin } from './ElevatorCabin';\nimport { Passenger } from './Passenger';\nimport { stairGeometry, spiralGeometry } from '../model/stairGeometry';\n\n// Building geometry floats slightly above the basemap so slabs never z-fight with map tiles.\n// Each floor gets an opaque slab; rooms sit on top of it with enough clearance to stay artifact-free.\n// Areas on one floor are routinely nested: a parking bay inside an aisle inside a deck plate, a\n// meeting room inside an open-plan zone. Drawn at the same base and height they are exactly coplanar,\n// so the depth buffer cannot separate them and which one wins flickers as the camera moves. Stagger\n// them by footprint: the smaller (more specific) area sits a few millimetres above the larger one it\n// lies within — far below anything visible at building scale, far above depth-buffer precision.\nconst COPLANAR_STEP = 0.007;\nexport const nestingLift = (area: number) => COPLANAR_STEP * (area > 2000 ? 0 : area > 200 ? 1 : area > 20 ? 2 : 3);\n// How far the contact shading rises off a slab, and how dark it gets right at the junction.\nconst AO_RISE = 0.85,\n AO_FLOOR = 0.58;\n// Re-exported: they are declared in levels.ts so the flat plan can read them without three.js.\nexport { LIFT, SLAB } from './levels';\nimport { LIFT, SLAB } from './levels';\nconst ROOM = 0.05,\n GROUND = 0.06;\n/** Head clearance over the eye. A ceiling you can see the top of is not a ceiling. */\nconst HEAD_CLEAR = 0.35;\n/** How much of the storey in focus everything stacked above it must leave, and how much the storeys\n * under it leave of one another. The per-storey ghost strength is solved from these and the level\n * count — see ghostAlpha. Below is the harder read (it comes through the focus's own plate as well)\n * and so is allowed to be the stronger layer. */\nconst FOCUS_SEEN = 0.62,\n UNDER_SEEN = 0.3;\n/** The envelope and the partitions of the storeys not in focus: the things a stack is looked THROUGH\n * rather than at. Flat, and not a share of the plates' strength, because the case has a job of its\n * own — saying where the building is and how it is banded — that does not get easier or harder with\n * the level count. A plate is one layer between the eye and what is under it; the façade is a solid\n * band at every one of seventeen storeys, two faces deep, covering the whole plan, and at the\n * plates' strength it closed the building into a brick box. Glass, not masonry. */\nconst CASE_ALPHA = 0.055;\n/** And the floor under a shaft's ghosted upper run — see lift(). */\nconst SHAFT_GHOST = 0.17;\n\n/** How far an absolutely-placed piece of geometry has to move to join the rest of the scene.\n *\n * Geometry arrives in two coordinate systems. Most of it is placed relative to the level in focus,\n * which is what lets a cutaway sit on the map and a walk stand on the map's own ground plane. The\n * rest carries the elevation the document authored: a ramp's slope, the parcel and the fences out\n * of doors, the excavation and its cage. Nothing reconciled the two, so walking a P1 deck put the\n * ramps 12.6 m under the walker and left the pavement level with a fifth-floor shop. This is the\n * one number that carries an authored elevation into the frame everything else is drawn in. The\n * stacked view is already drawn at authored elevations, so there it is nothing. */\nexport const sceneGround = (stack: boolean, rebase: number, activeElevation: number) =>\n stack ? 0 : rebase - activeElevation;\n\n/** Where an authored elevation ends up on screen, once the view's depth mapping has had its say.\n *\n * `undergroundView` compresses a shaft deeper than 96 m so a 400 m one can be looked at, and its\n * header asks every consumer to share that one transform. They did not: the stack compressed its\n * geometry vertex by vertex while a single-floor cutaway rebased to the compressed depth and then\n * added raw deltas to it, which put a level 140 m under the one in focus 44 m into the sky. This is\n * the mapping the plate, the flights climbing through it, the excavation's strata and the cage all\n * go through. A walk is the one view it has nothing to say to: inside one storey there is no depth\n * to compress, and the storey has been moved onto the map's ground plane anyway. */\nexport const sceneElevation = (view: UndergroundView, walk: boolean, z: number) =>\n walk ? z - (view.active?.elevation ?? 0) : view.elevation(z);\n\n/** The underside of a walked storey's ceiling, above the storey's own datum.\n *\n * It is the next slab's underside, not the storey height less a slab: fixtures are authored against\n * the storey — the garage's 3.1 m luminaires, its 4.2 m pillars — and a lid a third of a metre low\n * had them poking through it. And a storey the document drew too low for a person to stand in must\n * still get a ceiling above the eye rather than one you look down onto: the 1.6 m entresol put its\n * glowing plane at 1.42 m, a good half metre under the walker's eye. */\nexport const walkSoffit = (rebase: number, height: number) =>\n Math.max(rebase + height + LIFT, rebase + LIFT + SLAB + EYE + HEAD_CLEAR);\n\n/** A mezzanine shares the surrounding hall's roof. Its own partial footprint cannot close the\n * space seen beyond the gallery edge. Other floors keep their own ceiling. */\nexport function walkCeiling(project: ProjectDocument, floorId: string): { floor: Floor; soffit: number } | undefined {\n const active = project.floors.find(f => f.id === floorId);\n if (!active) return;\n const host = active.mezzanine\n ? project.floors\n .filter(\n f =>\n !f.mezzanine &&\n f.buildingId === active.buildingId &&\n f.elevation < active.elevation &&\n f.elevation + f.height > active.elevation,\n )\n .sort((a, b) => b.elevation - a.elevation)[0]\n : undefined;\n const floor = host ?? active;\n return { floor, soffit: walkSoffit(0, floor.elevation + floor.height - active.elevation) };\n}\n\n/** Coordinates a clipper can close a ring with. Two plates drawn to the same edge arrive here\n * differing in the fifteenth decimal, and polygon-clipping answers that by losing the ring. */\nconst snapRing = (ring: Ring): Ring =>\n ring.map(p => [Math.round(p[0] * 1e4) / 1e4, Math.round(p[1] * 1e4) / 1e4] as Point);\n\n/** The single plate a storey is drawn as when it is drawn as a shell — the ceiling you look down\n * onto from the storey above — with the stairwells punched through it.\n *\n * Only the storey's top-level areas go in. A parking deck is one plate carrying four hundred bays\n * drawn on it as zones; unioning every one of them is the input polygon-clipping's sweep line gives\n * up on, and the caller's catch then left the deck with no slab at all. The bays are inside the\n * plate anyway, so they say nothing about where the storey reaches. Sloped areas keep their own\n * geometry: flattening their footprints into this plate seals the ramp with a horizontal lid.\n *\n * A storey drawn as rooms rather than as a zone has no single plate, and `floorOutline` already\n * knows how to make one: rooms plus the walls between them, snapped and cached. */\nexport function shellPlate(\n project: ProjectDocument,\n floorId: string,\n primary?: Set<string>,\n voidOptions?: VoidOptions,\n): Ring[][] {\n const index = floorIndex(project);\n const own = index.objects.get(floorId) ?? [];\n const zones = own.filter(o => o.kind === 'zone' && !o.parentId && !o.slope && o.rings?.length);\n // A zone keeps all its rings: the -1A gallery is a loop around the atrium, and dropping its hole\n // would floor the void it exists to ring.\n const plates: Ring[][] = zones.length\n ? zones.map(o => o.rings!.map(r => snapRing(closeRing(r))))\n : floorOutline(project, floorId).map(r => [snapRing(closeRing(r))]);\n const input = plates;\n if (!input.length) return [];\n try {\n let merged = polygonClipping.union(input[0], ...input.slice(1)) as unknown as Ring[][];\n // A shaft that carries on past this storey goes through its floor, and a slab drawn over it is\n // a lid on the flight below.\n const voids = [...shaftVoids(project, floorId, primary, voidOptions), ...rampVoids(project, floorId)];\n if (voids.length)\n merged = polygonClipping.difference(\n merged as never,\n ...voids.map(v => [snapRing(v)] as never),\n ) as unknown as Ring[][];\n return merged;\n } catch {\n // Snapping is not a guarantee, and a storey with no slab reads as a storey that is not there.\n // Fall back to the largest authored plate without inventing a horizontal surface over ramps.\n const largest = index.outlines.get(floorId)?.rings;\n return largest ? [largest.map(r => closeRing(r))] : [];\n }\n}\n/** Milliseconds between frames of a permanent animation — 24 fps, a step band's own rate. */\nconst LOOP_FRAME = 42;\n/** The one rig id the route owns, so a rebuild can drop its own and leave every other alone. */\nconst ROUTE_RIG = 'route:track';\nconst wallBase = (floorId: string | null) => (floorId ? LIFT + SLAB : GROUND);\n\n/** Do two rings come near enough each other to be worth clipping? Bounding boxes, which is coarse on\n * purpose: a box that overlaps where the shapes do not costs one clip that gives the area back\n * unchanged. What it replaces — a corner-in-ring test each way — was enough while every void was a\n * shaft landing inside one area, and wrong for a ramp, which is a forty-metre strip crossing the\n * aisles at right angles with no corner of anything inside anything. Those aisles kept their whole\n * plate and bridged the trench cut under them. */\nconst boxesMeet = (a: Ring, b: Ring) => {\n const span = (ring: Ring, axis: 0 | 1) => {\n let lo = Infinity,\n hi = -Infinity;\n for (const p of ring) {\n if (p[axis] < lo) lo = p[axis];\n if (p[axis] > hi) hi = p[axis];\n }\n return [lo, hi];\n };\n for (const axis of [0, 1] as const) {\n const [alo, ahi] = span(a, axis),\n [blo, bhi] = span(b, axis);\n if (ahi < blo || bhi < alo) return false;\n }\n return true;\n};\n\n/** An escalator step: 0.4 m of going and a 0.2 m face, the world over. These are properties of the\n * machine rather than of the drawing — a manufacturer's step is the same step in every building —\n * so they are fixed here while the pitch, which the plan really does decide, is not. */\nconst STEP_GOING = 0.4,\n STEP_RISE = 0.2;\n\n/** How far a landing plate stands over the floor it belongs to. A comb plate drawn at its true\n * thickness stood a fifth of a metre proud of both storeys, so you stepped up onto a block at the\n * foot of every escalator and down off one at its head; drawn exactly flush it fights the plate for\n * the same pixels. A threshold's worth is neither. */\nconst PLATE_LIP = 0.02;\n\n/** The steps of one escalator flight, bottom first.\n *\n * `at` is how far up the run a step stands, measured in plan metres from the foot of the incline;\n * `base` is how far above the foot its underside sits. The going is 0.4 m stretched to fill the\n * incline exactly, so the band leaves no sliver at the foot, and the riser is whatever the rise\n * divided by the count comes to — a flight the plan has drawn too short shows as the steep stair it\n * is instead of as a smooth ramp that hides the fact. */\nfunction escalatorSteps(rise: number, incline: number): { at: number; base: number; going: number; face: number }[] {\n // Capped: a very long flight is read at a glance, not counted, and every step is a draw call's\n // worth of geometry in a scene that may hold a bank of them on seventeen storeys.\n const count = Math.max(2, Math.min(40, Math.round(incline / STEP_GOING)));\n const going = incline / count;\n // An escalator's risers are closed — a cleated face runs from one tread down to the next — so the\n // face has to be at least as deep as the pitch it is set at. Drawn at the machine's own 0.2 m on\n // an incline steeper than the machine's own, the band opened into a gap under every nose and read\n // as an outdoor fire stair.\n const face = Math.max(STEP_RISE, rise / count);\n return Array.from({ length: count }, (_, i) => ({\n at: going * (i + 0.5),\n // The band hangs a riser below the slope line: the foot step's top is level with the lower comb\n // plate, which is where a step really does emerge, and the head of the run stops a riser short\n // of the upper one. That last riser is where the band's travel goes — a cycle puts every step\n // where its neighbour was, so the step that climbs past the last visible one has to finish\n // inside the head housing rather than above a landing that is now flush with the floor.\n base: (rise * i) / count - face,\n going,\n face,\n }));\n}\n\n/** A part of the scene that moves: its own geometry, outside the merged batch, animated toward a\n * target at a fixed speed. Everything else is welded into one buffer per material — which is what\n * makes a tall building cheap to draw and impossible to move a single piece of. */\ninterface Rig {\n id: string;\n group: THREE.Group;\n /** Where it is heading, in whatever unit the part measures itself in — metres of elevation for a\n * lift car, 0..1 open for a door leaf. */\n target: number;\n /** Units per second. A lift runs at about 1.5 m/s; a door takes about a second to swing. */\n speed: number;\n /** Runs forever, wrapping at the target rather than stopping there — an escalator's steps, which\n * are identical and one pitch apart, so a wrap is invisible and the stair never stops moving. */\n loop?: boolean;\n apply: (group: THREE.Group, value: number) => void;\n}\nexport class SceneLayer implements CustomLayerInterface {\n id = 'kerros-3d';\n type = 'custom' as const;\n renderingMode = '3d' as const;\n private map?: MapLibreMap;\n private renderer?: THREE.WebGLRenderer;\n private scene = new THREE.Scene();\n private camera = (() => {\n const camera = new THREE.Camera();\n camera.layers.enableAll(); // lighting layers plus the reflected passenger\n camera.layers.disable(REFLECTION_BODY);\n return camera;\n })();\n private worldToClip = new THREE.Matrix4();\n private clipToWorld = new THREE.Matrix4();\n private transform = new THREE.Matrix4();\n private center!: MercatorCoordinate;\n private unit = 1;\n private project?: ProjectDocument;\n private stack = false;\n private walking = false;\n /** The walked floor has lamps of its own. Then the walk hands the interior over to them and\n * turns the general ceiling light down; a floor without any keeps the general light, or it is\n * a dark floor with a bright lid. */\n private lampLit = false;\n private poolLitOnly = false;\n private poolOverview = false;\n /** Per-storey ghost strength for the things a stack is FOR — the floor plates that carry each\n * storey's plan — on the storeys ABOVE the one in focus. Shared out across however many of them\n * the stack layers up between the eye and the focus. */\n private ghostAlpha = 0.17;\n /** And for the storeys UNDER the one in focus, which are read through the active plate as well as\n * through everything above it and need the strength to survive both. Keeping the two apart is\n * also what lets the active plate be drawn between them — see the render-order pass. */\n private underAlpha = 0.27;\n private activeFloor: string | null = null;\n private hovered: string | null = null;\n private rebase = 0;\n /** See sceneGround: what an authored elevation has to be shifted by to join the scene. */\n private ground = 0;\n private growth = 1;\n private growthStart = 0;\n private materials = new MaterialLibrary();\n private cabinMaterials?: CabinMaterials;\n private passenger?: Passenger;\n private cabinFinishes() {\n return (this.cabinMaterials ??= new CabinMaterials(this.renderer!));\n }\n wave() {\n this.passenger?.wave(performance.now() / 1000);\n this.map?.triggerRepaint();\n }\n private fixtureLights?: FixtureLights;\n private waterTime = { value: 0 };\n private hasWater = false;\n private batch = new SurfaceBatch();\n private highlight = new THREE.Group();\n private selected: string | null = null;\n /** Where the sun stands over this project right now, and whether that counts as evening. */\n private sunState: Sun = FIXED.day;\n private statuses: Map<string, StatusReading> | null = null;\n private excavation = false;\n /** Only the part of the feed the scene is built from — where the cars are and whether doors stand\n * open. A tone changing from normal to alarm recolours a marker and must not rebuild the scene. */\n private liftSignature = '';\n /** Per-floor stairwell cut-outs; cleared with the scene. */\n private voidCache = new Map<string, Ring[]>();\n /** Moving parts, rebuilt with the scene each update — see `rig`. */\n private rigs: Rig[] = [];\n /** Where each moving part has got to, carried ACROSS rebuilds. The geometry is disposed with the\n * scene like everything else; this is not, or every lift car would jump back to the bottom of its\n * shaft on any edit, and every open door would slam. */\n private rigState = new Map<string, number>();\n /** Whether the last animation frame moved anything that casts a shadow. */\n private shadowsMoved = false;\n private lastFrame = 0;\n private revision = 0;\n private depthScale = 1;\n private buried = false;\n private presentedElevation = (z: number) => z;\n private cage = new UndergroundCage();\n private sun?: THREE.DirectionalLight;\n /** The two lights that are not the sun, kept so the scene can be re-lit without being rebuilt. */\n private skyLight?: THREE.HemisphereLight;\n private roomLight?: THREE.HemisphereLight;\n private route: Route | null = null;\n private routeStep: number | null = null;\n private routeGroup: THREE.Group | null = null;\n private routeTile: THREE.DataTexture | null = null;\n private mapStyle: MapStyleOptions = {};\n setMapStyle(style?: MapStyleOptions) {\n this.mapStyle = style ?? {};\n }\n private xyCache = new Map<string, Point>();\n private markerCache = new Map<string, { x: number; y: number; visible: boolean }>();\n // Whether each marker is hidden behind geometry. Screen position is cheap and recomputed every\n // frame; this is a raycast against the whole model and must NOT be. It survives camera movement and\n // is only re-derived once the camera settles (or the scene is rebuilt).\n private occlusionCache = new Map<string, boolean>();\n private previousProjection = new THREE.Matrix4();\n private previousScale = 0;\n private previousSize = '';\n private pickables: THREE.Object3D[] = [];\n private clipBounds = new THREE.Box3();\n private clipBoundsDirty = true;\n onAdd(map: MapLibreMap, gl: WebGLRenderingContext | WebGL2RenderingContext) {\n this.map = map;\n this.renderer = new THREE.WebGLRenderer({\n canvas: map.getCanvas(),\n context: gl as WebGL2RenderingContext,\n antialias: true,\n });\n this.renderer.autoClear = false;\n this.renderer.shadowMap.enabled = true;\n this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;\n this.renderer.shadowMap.autoUpdate = false;\n // Filmic rolloff instead of a hard clip: bright façades keep their detail instead of blowing out\n // to flat white, and the shadow side keeps colour. Exposure is nudged up to compensate for the\n // slightly darker midtones ACES gives, so the model still sits in the basemap's brightness range.\n // Khronos PBR Neutral, not ACES. ACES is a *film* look: it crushes midtones towards grey and\n // desaturates hard, which on an architectural scene of pale interiors over a pale basemap left\n // every surface the same washed neutral. Measured on the Stockmann stack it was eating 29% of\n // the scene's saturation, and a plate with a clear blue cast came back perfectly colourless.\n this.renderer.toneMapping = THREE.NeutralToneMapping;\n // Slightly under 1. The basemap underneath is not tone-mapped, so it always renders at full\n // strength; pulling the scene down is what separates a pale floor plate from a pale map. 0.9\n // keeps that separation while letting interiors stay bright — 0.82 read as overcast concrete,\n // and the authored room pastels were the first thing it crushed.\n this.renderer.toneMappingExposure = 0.9;\n }\n /** A tiny procedural sky/ground gradient, prefiltered for image-based lighting. Without an\n * environment every MeshStandardMaterial is lit by two lights alone and reads flat; with one, every\n * surface picks up sky above and bounced ground below, which is most of what makes 3D look solid.\n * Built once per lighting mood and cached — PMREM generation is not cheap. */\n private envCache = new Map<string, THREE.WebGLRenderTarget>();\n private environmentMap(evening: boolean): THREE.Texture | null {\n const key = evening ? 'evening' : 'day';\n const cached = this.envCache.get(key);\n if (cached || !this.renderer) return cached?.texture ?? null;\n const canvas = document.createElement('canvas');\n canvas.width = 512;\n canvas.height = 256;\n const c = canvas.getContext('2d')!;\n const g = c.createLinearGradient(0, 0, 0, 256);\n if (evening) {\n g.addColorStop(0, '#22293f');\n g.addColorStop(0.42, '#5d5570');\n g.addColorStop(0.52, '#c08a5f');\n g.addColorStop(1, '#241f1c');\n } else {\n g.addColorStop(0, '#719dcc');\n g.addColorStop(0.35, '#c0d5e5');\n g.addColorStop(0.49, '#f6eedf');\n g.addColorStop(0.54, '#b3ada0');\n g.addColorStop(1, '#605f55');\n }\n c.fillStyle = g;\n c.fillRect(0, 0, 512, 256);\n // Broad sky openings add directional reflections without a downloaded HDR panorama.\n for (const [x, y, radius] of [\n [110, 83, 65],\n [370, 58, 44],\n ]) {\n const cloud = c.createRadialGradient(x, y, 0, x, y, radius);\n cloud.addColorStop(0, evening ? 'rgba(249,188,139,.42)' : 'rgba(255,252,239,.8)');\n cloud.addColorStop(1, 'rgba(255,255,255,0)');\n c.fillStyle = cloud;\n c.fillRect(x - radius, y - radius, radius * 2, radius * 2);\n }\n const equirect = new THREE.CanvasTexture(canvas);\n equirect.mapping = THREE.EquirectangularReflectionMapping;\n equirect.colorSpace = THREE.SRGBColorSpace;\n const pmrem = new THREE.PMREMGenerator(this.renderer);\n const target = pmrem.fromEquirectangular(equirect);\n equirect.dispose();\n pmrem.dispose();\n // PMREM leaves its own GL state behind; hand the context back to MapLibre the way it expects it.\n this.renderer.resetState();\n this.envCache.set(key, target);\n return target.texture;\n }\n /** Move the existing lights to where a new sun puts them, without touching the geometry. Valid\n * only while the dusk treatment is unchanged — see the caller. */\n private relight(project: ProjectDocument, floorId: string | null, sun: Sun) {\n const air = ambient(\n sun,\n this.poolOverview ? { kelvin: 6500, level: 1 } : project.floors.find(f => f.id === floorId)?.light,\n );\n this.scene.environmentIntensity = this.poolLitOnly ? 0 : air.environment;\n this.skyLight?.color.set(air.sky);\n this.skyLight?.groundColor.set(air.ground);\n if (this.skyLight) this.skyLight.intensity = this.poolLitOnly ? 0 : air.hemisphere;\n this.roomLight?.color.set(air.interior);\n this.roomLight?.groundColor.set(air.interiorBounce);\n if (this.roomLight) this.roomLight.intensity = air.interiorLevel * (this.walking && this.lampLit ? 0.45 : 1);\n const beam = sunlight(sun);\n if (this.sun) {\n this.sun.color.set(beam.color);\n this.sun.intensity = this.poolLitOnly ? 0 : beam.intensity;\n this.sun.position.set(...beam.position);\n this.fitShadowCamera();\n }\n this.refreshShadows();\n this.map?.triggerRepaint();\n }\n /** Redraw every shadow map on the next frame: the sun's, and each lamp's. Shadows are drawn on\n * demand, and each light says for itself whether it is owed a redraw — the sun's map is one\n * 2048² pass over the whole model and a lamp's is six, so a lamp swapping under a walker must\n * not cost the sun's as well. This is the \"everything changed\" case. */\n private refreshShadows() {\n if (!this.renderer) return;\n if (this.sun) this.sun.shadow.needsUpdate = true;\n this.fixtureLights?.invalidate();\n this.renderer.shadowMap.needsUpdate = true;\n }\n /** Point the sun at the model and shrink its shadow frustum to fit. A fixed +/-140 m box spends\n * most of a 2048 map on empty ground: a small building got a handful of texels and its shadows\n * came out as soft mush. Fitting to the real extent keeps texel density high whatever the scale. */\n private fitShadowCamera() {\n const light = this.sun;\n if (!light) return;\n const bounds = new THREE.Box3();\n this.scene.traverse(o => {\n if (o instanceof THREE.Mesh && o.castShadow) bounds.expandByObject(o);\n });\n if (bounds.isEmpty()) return;\n const centre = bounds.getCenter(new THREE.Vector3());\n const size = bounds.getSize(new THREE.Vector3());\n light.target.position.copy(centre);\n light.target.updateMatrixWorld();\n // Keep the light's direction, just re-seat it above the model's centre far enough to clear it.\n const reach = Math.max(size.x, size.y, size.z) || 1;\n const direction = light.position.clone().normalize();\n light.position.copy(centre).addScaledVector(direction, reach * 1.6 + 40);\n light.updateMatrixWorld();\n // Fit in light space, including where the tallest corners project onto the ground. A low\n // evening sun can throw shadows far outside the building's footprint.\n const camera = light.shadow.camera;\n light.shadow.updateMatrices(light);\n const shadowBounds = new THREE.Box3();\n for (const x of [bounds.min.x, bounds.max.x])\n for (const y of [bounds.min.y, bounds.max.y])\n for (const z of [bounds.min.z, bounds.max.z]) {\n const corner = new THREE.Vector3(x, y, z);\n shadowBounds.expandByPoint(corner.clone().applyMatrix4(camera.matrixWorldInverse));\n if (!this.buried && z > 0) {\n corner.addScaledVector(direction, -z / direction.z);\n shadowBounds.expandByPoint(corner.applyMatrix4(camera.matrixWorldInverse));\n }\n }\n Object.assign(camera, {\n left: shadowBounds.min.x - 3,\n right: shadowBounds.max.x + 3,\n top: shadowBounds.max.y + 3,\n bottom: shadowBounds.min.y - 3,\n near: Math.max(0.5, -shadowBounds.max.z - 10),\n far: -shadowBounds.min.z + 10,\n });\n camera.updateProjectionMatrix();\n }\n private xy(p: Point): Point {\n const key = `${p[0]},${p[1]}`,\n cached = this.xyCache.get(key);\n if (cached) return cached;\n const m = MercatorCoordinate.fromLngLat(toLngLat(p, this.project!.origin));\n const result: Point = [(m.x - this.center.x) / this.unit, -(m.y - this.center.y) / this.unit];\n this.xyCache.set(key, result);\n return result;\n }\n /** Several extrusions welded into one moving part. An escalator's step band is twenty boxes that\n * travel together, and twenty meshes per flight — times a bank of four, times the flights in\n * view — is a draw call apiece for something that moves as one thing. Merged, it is one. */\n private parts(\n pieces: { rings: Point[][]; base: number; height: number }[],\n color: string,\n shadows = true,\n tread?: { across: Point; width: number; going: number },\n ): THREE.Group {\n const geometries = pieces.map(({ rings, base, height }) => {\n const shape = new THREE.Shape(rings[0].map(p => new THREE.Vector2(...this.xy(p))));\n shape.holes = rings.slice(1).map(r => new THREE.Path(r.map(p => new THREE.Vector2(...this.xy(p)))));\n const geometry = new THREE.ExtrudeGeometry(shape, { depth: height, bevelEnabled: false, steps: 1 });\n geometry.translate(0, 0, base);\n metricUVs(geometry);\n const positions = geometry.getAttribute('position');\n if (tread) {\n geometry.computeBoundingBox();\n const center = geometry.boundingBox!.getCenter(new THREE.Vector3());\n const uv = geometry.getAttribute('uv'),\n normal = geometry.getAttribute('normal'),\n [ax, ay] = tread.across;\n for (let i = 0; i < positions.count; i++) {\n const x = positions.getX(i) - center.x,\n y = positions.getY(i) - center.y;\n const v =\n Math.abs(normal.getZ(i)) > 0.5\n ? (-x * ay + y * ax) / tread.going + 0.5\n : 0.2 + (0.6 * (positions.getZ(i) - geometry.boundingBox!.min.z)) / Math.max(0.001, height);\n uv.setXY(i, (x * ax + y * ay) / tread.width + 0.5, v);\n }\n }\n for (let i = 0; i < positions.count; i++) positions.setZ(i, this.present(positions.getZ(i)));\n geometry.computeVertexNormals();\n return geometry.index ? geometry.toNonIndexed() : geometry;\n });\n const merged = geometries.length === 1 ? geometries[0] : mergeGeometries(geometries)!;\n const mesh = new THREE.Mesh(merged, tread ? this.materials.escalator() : this.materials.solid(color));\n mesh.castShadow = shadows;\n mesh.receiveShadow = true;\n const group = new THREE.Group();\n group.add(mesh);\n return group;\n }\n /** Register a moving part. Called while the scene is being built; the geometry is fresh each time\n * and the position it has reached is not, so a car mid-ride keeps riding across an edit.\n *\n * `settled` seeds the value the first time a part is ever seen, so opening a document does not\n * send every lift travelling up from the basement to wherever it actually is. */\n private rig(id: string, group: THREE.Group, target: number, speed: number, apply: Rig['apply'], loop = false) {\n if (!this.rigState.has(id)) this.rigState.set(id, loop ? 0 : target);\n apply(group, this.rigState.get(id)!);\n this.scene.add(group);\n this.rigs.push({ id, group, target, speed, apply, loop });\n }\n /** Advance every moving part toward its target. Returns true while anything is still moving, which\n * is what keeps asking the map to repaint — MapLibre draws on demand, so without that a ride would\n * advance one frame per mouse move. */\n private animate(seconds: number): boolean {\n let moving = false;\n // A looping part never settles, so it must not drag the shadow map with it: re-rendering every\n // caster in the building on every frame, forever, to follow an escalator step is the one cost\n // that would make a permanent animation not worth having. Loops cast no shadow of their own.\n this.shadowsMoved = false;\n for (const r of this.rigs) {\n const at = this.rigState.get(r.id) ?? r.target;\n if (r.loop) {\n const next = (at + r.speed * seconds) % r.target;\n this.rigState.set(r.id, next);\n r.apply(r.group, next);\n moving = true;\n continue;\n }\n if (Math.abs(at - r.target) < 1e-4) {\n if (at !== r.target) this.rigState.set(r.id, r.target);\n continue;\n }\n const step = r.speed * seconds;\n const next = Math.abs(r.target - at) <= step ? r.target : at + Math.sign(r.target - at) * step;\n this.rigState.set(r.id, next);\n r.apply(r.group, next);\n moving = true;\n this.shadowsMoved = true;\n }\n return moving;\n }\n /** Ask for a repaint at the loop rate rather than at once, coalescing the requests so a dozen\n * escalators still only cost one frame between them. */\n private loopTimer?: ReturnType<typeof setTimeout>;\n private paintSoon() {\n if (this.loopTimer) return;\n this.loopTimer = setTimeout(() => {\n this.loopTimer = undefined;\n this.map?.triggerRepaint();\n }, LOOP_FRAME);\n }\n /** One vertex, mapped by the view's depth transform — see sceneElevation. Geometry is built at\n * the elevations the document authored, so this is the last thing that touches a z before it\n * reaches the buffer. It ran in the stacked view only, which left a deep cutaway drawing its\n * plate at the compressed depth and everything around it at the real one. */\n private present(z: number) {\n return this.buried && !this.walking ? this.presentedElevation(z) : z;\n }\n private surface(\n rings: Point[][],\n base: number,\n height: number,\n color: string,\n id: string,\n material?: SurfaceFinish,\n // True for the shared per-storey plate strength; a number for a surface whose own storey has\n // asked for a different one — see ghostStrength.\n ghost: boolean | number = false,\n // Bake contact shading into the lower part of the surface. Where a wall meets a floor there is\n // almost no sky reaching the junction, and without that darkening every wall looks like it is\n // hovering a millimetre above the slab rather than standing on it.\n ao = false,\n override?: THREE.MeshStandardMaterial,\n // Out of doors, and so out of reach of the building's own ceiling lighting. The parcel, the\n // landscaping, a fence: lit by the sky and nothing else, whatever the lamps inside are doing.\n outdoor = false,\n interiorFace?: [Point, Point] | null,\n horizontalAxis?: Point,\n ) {\n // An area a void has swallowed whole — a parking bay lying under the ramp that runs over it — has\n // no plate left to draw, and asking for the first of no rings took the rest of the storey down\n // with it.\n if (!rings.length) return;\n const shape = new THREE.Shape(rings[0].map(p => new THREE.Vector2(...this.xy(p))));\n shape.holes = rings.slice(1).map(r => new THREE.Path(r.map(p => new THREE.Vector2(...this.xy(p)))));\n const geometry =\n height > 0.005\n ? new THREE.ExtrudeGeometry(shape, {\n depth: height,\n bevelEnabled: false,\n steps: ao && !ghost ? Math.min(24, Math.max(1, Math.ceil(height / 0.35))) : 1,\n })\n : new THREE.ShapeGeometry(shape);\n geometry.translate(0, 0, base);\n metricUVs(geometry, horizontalAxis);\n // Computed before any depth compression, so the gradient follows real metres off the floor.\n if (ao && !ghost) {\n const positions = geometry.getAttribute('position');\n const shades = new Float32Array(positions.count * 3);\n for (let i = 0; i < positions.count; i++) {\n const above = Math.max(0, Math.min(1, (positions.getZ(i) - base) / AO_RISE));\n const shade = AO_FLOOR + (1 - AO_FLOOR) * above ** 0.55;\n shades[i * 3] = shades[i * 3 + 1] = shades[i * 3 + 2] = shade;\n }\n geometry.setAttribute('color', new THREE.BufferAttribute(shades, 3));\n }\n if (this.buried && !this.walking && this.depthScale < 1) {\n const positions = geometry.getAttribute('position');\n for (let i = 0; i < positions.count; i++) positions.setZ(i, this.present(positions.getZ(i)));\n geometry.computeVertexNormals();\n }\n const surfaceMaterial =\n override ??\n (ghost\n ? this.materials.ghost(color, typeof ghost === 'number' ? ghost : this.ghostAlpha)\n : material\n ? this.materials.get(material, color)\n : this.materials.solid(color));\n const face = interiorFace && splitWallFace(geometry, interiorFace.map(p => this.xy(p)) as [Point, Point]);\n if (face) {\n const plaster = this.materials.get('plaster', '#eceae5');\n this.batch.add(face, ao && !ghost ? this.materials.shaded(plaster) : plaster, id, outdoor);\n }\n this.batch.add(geometry, ao && !ghost ? this.materials.shaded(surfaceMaterial) : surfaceMaterial, id, outdoor);\n }\n /** A sloped area (garage ramp, loading incline): the plate's own footprint, but each vertex lifted\n * to its elevation along the slope axis, then given thickness along -Z so the deck reads solid\n * from below. Depth compression is applied per-vertex, exactly as for flat surfaces. */\n private slopedSurface(\n o: SiteObject,\n slope: Slope,\n lift: number,\n thickness: number,\n color: string,\n ghost: boolean | number = false,\n ) {\n for (const rings of rampSections(o.rings!, slope)) {\n const shape = new THREE.Shape(rings[0].map(p => new THREE.Vector2(...this.xy(p))));\n shape.holes = rings.slice(1).map(r => new THREE.Path(r.map(p => new THREE.Vector2(...this.xy(p)))));\n const geometry = new THREE.ExtrudeGeometry(shape, { depth: thickness, bevelEnabled: false });\n geometry.translate(0, 0, -thickness); // extrude downward: the driving surface is the top face\n metricUVs(geometry);\n // Ride the slope in scene space: Mercator is conformal, so at building scale xy() is an affine\n // similarity and projecting onto the transformed axis matches slopeElevation() in local metres.\n const [ax, ay] = this.xy(slope.axis[0]),\n [bx, by] = this.xy(slope.axis[1]);\n const dx = bx - ax,\n dy = by - ay,\n len2 = dx * dx + dy * dy;\n const positions = geometry.getAttribute('position');\n for (let i = 0; i < positions.count; i++) {\n const t = len2\n ? Math.max(0, Math.min(1, ((positions.getX(i) - ax) * dx + (positions.getY(i) - ay) * dy) / len2))\n : 0;\n // getZ is 0 on the driving surface and -thickness underneath, so the deck keeps its thickness.\n positions.setZ(i, this.present(positions.getZ(i) + slope.high + (slope.low - slope.high) * t + lift));\n }\n geometry.computeVertexNormals();\n this.batch.add(\n geometry,\n ghost\n ? this.materials.ghost(color, typeof ghost === 'number' ? ghost : this.ghostAlpha)\n : this.materials.solid(color),\n o.id,\n );\n }\n }\n /** The façade envelope for a set of levels: each level's slab, its exterior walls with their\n * authored finish, and the glazing punched into them. Interior partitions are deliberately left\n * out — from outside they are hidden work, and they used to produce seams along the façade. */\n private envelope(\n project: ProjectDocument,\n levels: Map<string, Floor>,\n exterior: Set<string>,\n finishes: Map<string, { color: string; material?: MaterialKind }>,\n ) {\n for (const o of project.objects) {\n const fl = levels.get(o.floorId ?? '');\n if (!fl) continue;\n if (o.kind === 'zone' && o.rings) this.surface(o.rings, fl.elevation + LIFT, SLAB, '#c8c5bd', o.id);\n if (o.kind === 'window' && o.barrierId && exterior.has(o.barrierId)) this.opening(project, o, fl.elevation);\n }\n for (const p of wallPieces(project, null, true))\n if (levels.has(p.floorId ?? '') && exterior.has(p.id)) {\n const finish = finishes.get(p.id)!;\n this.surface([p.ring], p.base + wallBase(p.floorId), p.height - p.base, finish.color, p.id, finish.material);\n }\n }\n private opening(project: ProjectDocument, o: SiteObject, z: number) {\n const position = objectPosition(project, o),\n rotation = objectRotation(project, o);\n if (o.kind === 'window') {\n const barrier = project.barriers.find(b => b.id === o.barrierId);\n const height = Math.min(o.height, (barrier?.height ?? o.height + 0.85) - 0.85);\n if (height <= 0) return;\n const base = z + wallBase(o.floorId) + 0.85,\n rim = Math.min(0.08, height / 3, o.width / 3);\n const depth = Math.max(0.16, (barrier?.thickness ?? 0.2) + 0.035);\n const frame = this.materials.metal('#b4b9ba');\n // An occupied room's windows are transparent panes, not randomly illuminated facade panels.\n const glass = this.materials.glass(this.sunState.evening);\n const side = (\n offset: number,\n width: number,\n bottom: number,\n h: number,\n material: THREE.MeshStandardMaterial,\n d = depth,\n ) => {\n const delta = rotate([offset, 0], rotation);\n this.surface(\n [rectangle([position[0] + delta[0], position[1] + delta[1]], width, d, rotation)],\n bottom,\n h,\n '#ffffff',\n o.id,\n undefined,\n false,\n false,\n material,\n );\n };\n side(0, o.width + 0.08, base - 0.04, 0.065, this.materials.get('stone', '#b9b6ac'), depth + 0.12);\n side(0, o.width, base, rim, frame);\n side(0, o.width, base + height - rim, rim, frame);\n for (const sign of [-1, 1]) side((sign * (o.width - rim)) / 2, rim, base + rim, height - rim * 2, frame);\n side(0, o.width - rim * 2, base + rim, height - rim * 2, glass, 0.018);\n const panes = Math.max(1, Math.ceil(o.width / 1.45));\n for (let i = 1; i < panes; i++)\n side(-o.width / 2 + (i * o.width) / panes, 0.045, base + rim, height - rim * 2, frame);\n } else if (o.kind === 'stairs') {\n this.shaft(project, o, z, position, rotation);\n } else if (o.kind === 'elevator') {\n this.lift(project, o, z, position, rotation);\n } else if (['door', 'gate'].includes(o.kind)) {\n this.leaf(project, o, z, position, rotation);\n } else {\n this.surface(\n objectRings({ ...o, position, rotation }),\n z + wallBase(o.floorId),\n Math.min(o.height, 3),\n o.color ?? COLORS[o.kind] ?? '#bfcac7',\n o.id,\n );\n }\n }\n /** A door as a leaf in a frame, standing open when the feed says it is.\n *\n * In 3D a door had been a slab filling its whole opening — a door you could never walk through and\n * that looked identical whether it was open, closed or unmonitored. The plan has drawn the swing\n * for a long time; this is the same statement in three dimensions, hinged the same way, so the two\n * views agree about which side it opens from.\n *\n * Unknown status means shut. The plan can draw the architectural swing symbol for \"a door is here\n * and this is how it opens\" because a symbol is allowed to be about the door rather than about its\n * state; a solid leaf in space is not, so it stays in the frame until something says otherwise. */\n private leaf(project: ProjectDocument, o: SiteObject, z: number, position: Point, rotation: number) {\n const barrier = project.barriers.find(b => b.id === o.barrierId);\n const thickness = barrier?.thickness ?? 0.2;\n const base = z + wallBase(o.floorId);\n const height = Math.min(o.height, (barrier?.height ?? o.height) - 0.02);\n const model = makeDoor(o, thickness, height, this.materials);\n const at = this.xy(position),\n along = this.xy(addPoint(position, rotate([1, 0], rotation)));\n const angle = Math.atan2(along[1] - at[1], along[0] - at[0]);\n const place = (group: THREE.Group) => {\n group.position.set(at[0], at[1], this.present(base));\n group.scale.z = this.buried && !this.walking ? this.depthScale : 1;\n group.rotation.z = angle;\n };\n // The wall pieces already contain the header; another solid here duplicates its faces.\n place(model.frame);\n for (const leftover of this.batch.addObject(model.frame, o.id)) this.scene.add(leftover);\n model.frame.traverse(child => {\n if (child instanceof THREE.Mesh) child.geometry.dispose();\n });\n const status = this.statuses?.get(o.feedId ?? '');\n model.panels.forEach(({ group, setOpen }, index) => {\n place(group);\n this.rig(`${o.id}:leaf:${o.doorType ?? 'hinged'}:${index}`, group, status?.open ? 1 : 0, 1.4, (_g, value) =>\n setOpen(value),\n );\n });\n }\n /** The inward-facing edge of an exterior wall.\n *\n * Which face is the inside is not a property of the wall — it is a question about the building\n * around it — so it is answered the only way it can be: step off the wall each way and see which\n * side lands within the floor's footprint. A wall with no footprint to be inside of (an outbuilding\n * wall, a fence read as exterior) has no interior face. */\n private interiorFace(project: ProjectDocument, piece: WallPiece, floorId: string | null): [Point, Point] | null {\n const outline = floorOutline(project, piece.floorId ?? floorId);\n if (!outline.length) return null;\n const ring = openRing(piece.ring);\n if (ring.length < 3) return null;\n const wall = project.barriers.find(b => b.id === piece.id);\n if (!wall || wall.thickness < 0.03) return null;\n const [start, end] = barrierEnds(project, wall);\n const length = distance(start, end),\n ux = (end[0] - start[0]) / length,\n uy = (end[1] - start[1]) / length;\n // Joined pieces are trapezoids at corners. Find the actual long faces parallel to the wall,\n // rather than treating a mitred end as another long side or inferring thickness from it.\n for (let i = 0; i < ring.length; i++) {\n const a = ring[i],\n b = ring[(i + 1) % ring.length],\n len = distance(a, b);\n if (len < 0.05 || Math.abs((b[0] - a[0]) * uy - (b[1] - a[1]) * ux) > 1e-6 * len) continue;\n const nx = (b[1] - a[1]) / len,\n ny = -(b[0] - a[0]) / len;\n const mid: Point = [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];\n const probe: Point = [mid[0] + nx * 0.3, mid[1] + ny * 0.3];\n if (!outline.some(r => pointInRing(probe, r))) continue;\n return [a, b];\n }\n return null;\n }\n /** An area's rings with the shafts that climb through its level, and the ramps that drive through\n * it, cut out of them.\n *\n * `through` says which plate is being cut: a floor is open where something arrives up through it,\n * a ceiling where something sets off up through it. They are not the same holes — the bottom of a\n * run departs without arriving and the top arrives without departing — and on a criss-cross\n * escalator bank they are at opposite ends of the same box.\n *\n * `wells` is whether a stairwell may be punched at all — a hole onto a storey nobody is drawing\n * is worse than no hole. A ramp is not subject to it: what is under a ramp's hole is the ramp.\n *\n * Cheap when there is nothing to cut, which is the usual case: a floor with no shaft through it\n * gets its own rings back untouched, and one with a shaft pays a clip only for the areas the\n * shaft actually lands in. */\n private withVoids(\n project: ProjectDocument,\n rings: Ring[],\n floorId: string,\n primary: Set<string>,\n through: 'floor' | 'ceiling' = 'floor',\n wells = true,\n ): Ring[][] {\n const key = `${floorId}|${through}|${wells}`;\n let voids = this.voidCache.get(key);\n if (!voids) {\n // Above ground nothing under the street is drawn, flights included, so a hole cut for one\n // would open onto the basemap with nothing coming up through it.\n voids = wells\n ? shaftVoids(project, floorId, primary, { through, lowest: this.buried || this.walking ? -Infinity : -0.01 })\n : [];\n voids = [...voids, ...rampVoids(project, floorId, through)];\n if (through === 'floor')\n voids = [\n ...voids,\n ...project.objects.filter(o => o.floorId === floorId && o.water && o.rings?.length).map(o => o.rings![0]),\n // In POV the car supplies its own floor, including at the lowest landing. Stairwell\n // cuts are disabled when no lower storey is drawn; leaving the room finish here put\n // carpet or bath tiles above the car's floor and made the cabin look like a pool.\n ...(this.walking ? cabinFloorVoids(project, floorId, primary) : []),\n ];\n this.voidCache.set(key, voids);\n }\n if (!voids.length || !rings.length) return rings.length ? [rings] : [];\n const hits = voids.filter(v => boxesMeet(v, rings[0]));\n if (!hits.length) return rings.length ? [rings] : [];\n try {\n const cut = polygonClipping.difference(\n [rings.map(r => closeRing(r))] as never,\n ...hits.map(v => [v] as never),\n ) as unknown as Ring[][];\n return cut;\n } catch {\n return rings.length ? [rings] : []; // degenerate shaft footprint: an uncut floor beats no floor\n }\n }\n /** A stair, spiral or escalator, drawn as the climb it actually makes.\n *\n * The flights come from the levels the document says the shaft serves, not from whatever storey\n * happens to sit above it, and each is drawn at the elevation of the level it leaves — so the\n * flight arriving at the level you are standing on is there, coming up through the floor, instead\n * of being filed invisibly under the storey below. */\n private shaft(project: ProjectDocument, o: SiteObject, z: number, position: Point, rotation: number) {\n const color = o.color ?? COLORS[o.kind] ?? '#bfcac7';\n const own = project.floors.find(f => f.id === o.floorId)?.elevation ?? 0;\n const all = flights(project, o);\n const model = stairModel(project, o);\n // Every flight when the whole stack is on show; otherwise the two you could touch from here —\n // the one arriving at this level and the one leaving it. Drawing all of them in a single-floor\n // view hangs a ladder of treads through storeys that are not being drawn.\n const near = this.stack\n ? all\n : (() => {\n const { up, down } = flightsAt(project, o, this.activeFloor);\n return [down, up].filter((f): f is Flight => !!f);\n })();\n if (!near.length) {\n // Serves one level only: there is no climb to draw, and a plate is the honest picture.\n this.surface(objectRings({ ...o, position, rotation }), z + wallBase(o.floorId), 0.18, color, o.id);\n return;\n }\n // A shaft is exempt from the below-grade skip — it is filed under the lowest level it serves and\n // would otherwise vanish from every storey above — but that exemption let it draw its whole body.\n // On an above-ground view nothing under the street is drawn, so a garage flight climbed out of\n // bare basemap with no deck at either end of it. Clamp the shaft to the levels the view builds.\n const drawn = this.buried || this.walking ? near : near.filter(f => f.from.elevation > -0.01);\n if (!drawn.length) return;\n for (const flight of drawn) {\n const base = z + (flight.from.elevation - own) + wallBase(o.floorId);\n if (model === 'spiral') {\n this.spiral(o, position, base, flight.rise, color);\n continue;\n }\n const index = all.indexOf(flight);\n // A criss-cross bank lands every flight where the next one starts, so the two of them asked\n // for the same landing and drew it twice, in the same place, at the same height. One plate per\n // level: the flight above puts its foot plate there, so the one below leaves its head bare.\n const shared = index + 1 < all.length && drawn.includes(all[index + 1]);\n this.flight(o, flightRun(project, o, flight.rise, model, index), base, flight.rise, color, model, !shared);\n }\n }\n /** A straight climb: treads for a stair, a ribbed deck between flat landing plates for an\n * escalator. Both run along the object's own depth axis, which is where the plan put them. */\n private flight(\n o: SiteObject,\n run: FlightRun,\n base: number,\n rise: number,\n color: string,\n model: StairModel,\n /** Draw the landing at the head of this flight. False where the flight above starts here and\n * puts its own plate on the same level — see the criss-cross bank in shaft(). */\n head = true,\n ) {\n const { at, half, pad, incline, topT, footT, rotation } = run;\n if (model === 'escalator') {\n // Landing plates at both ends, then the incline between them. A real escalator has about a\n // metre of flat comb plate at each end; without them the deck spears into the floor. The\n // incline is only as long as the rise needs at the machine's own 30° — see flightRun — so the\n // plate at the foot takes whatever run is left over rather than the climb being flattened out\n // to fill the box.\n const band = escalatorSteps(rise, incline);\n const going = band[0].going,\n face = band[0].face,\n riser = rise / band.length;\n // The comb plate the band runs into: deeper than a step's face, because the step that has just\n // left the head of a moving band has to go somewhere and inside that plate is where — see the\n // spare steps below. Its TOP is the storey's floor, not its underside: a landing standing a\n // fifth of a metre proud is a block you step up onto and then down off again.\n const comb = Math.max(0.24, riser + 0.06);\n const foot = half - footT;\n // And the foot plate is deep enough to bury the spare step waiting under it.\n this.surface(\n [rectangle(at(footT + foot / 2), o.width, foot, rotation)],\n base - (riser + face + 0.08),\n riser + face + 0.08 + PLATE_LIP,\n color,\n o.id,\n );\n if (head)\n this.surface(\n [rectangle(at(topT - pad / 2), o.width, pad, rotation)],\n base + rise - comb,\n comb + PLATE_LIP,\n color,\n o.id,\n );\n // The truss the steps ride on: the old smooth deck, dropped clear of the step band so it reads\n // as the machine under the stair rather than as the surface you walk on.\n const body = { ...o, rings: [rectangle(at((topT + footT) / 2), o.width, incline, rotation)] } as SiteObject;\n this.slopedSurface(body, { axis: [at(topT), at(footT)], high: base + rise, low: base }, -face, 0.3, '#9aa5a1');\n const tread = (step: { at: number; base: number }) => ({\n rings: [rectangle(at(footT - step.at), o.width - 0.12, going * 1.02, rotation)],\n base: base + step.base,\n height: face,\n });\n // Which way the machine runs, and whether it is running at all. The object says which way it\n // was built to carry you; a feed may say it has been reversed for the evening peak, and may\n // say it has been stopped — and a stopped escalator is a stair, so its steps stand still.\n const reading = this.statuses?.get(o.feedId ?? '');\n const way = (reading?.travel ?? o.travel ?? 'up') === 'down' ? -1 : 1;\n const running = reading?.running ?? true;\n // Standing on one storey there are at most two flights in view, so they can move. In the\n // stacked view there are all of them, on every level of the building at once — dozens of bands\n // asking for a repaint every frame to animate something a few pixels wide — so there the band\n // is welded into the batch with everything else and simply stands still. A stopped escalator\n // takes the same path: nothing to animate, so nothing asks for a frame.\n const a = this.xy(at(0)),\n across = this.xy(addPoint(at(0), rotate([1, 0], rotation)));\n const finish = {\n across: [across[0] - a[0], across[1] - a[1]] as Point,\n width: o.width - 0.12,\n going: going * 1.02,\n };\n if (this.stack || !running) {\n const steps = this.parts(band.map(tread), color, false, finish);\n steps.userData.entityId = o.id;\n this.scene.add(steps);\n } else {\n // The band travels exactly one step per cycle. Every step is identical and one pitch from\n // the next, so a wrap back to the start puts each one exactly where its neighbour was and\n // the stair never appears to stop.\n //\n // The ends are the whole difficulty. A rigid band gains a step at one end of its travel and\n // loses one at the other, and a step that pops into being in open air is what a moving\n // staircase must never look like. So it carries one spare below the foot — it starts the\n // cycle under the foot plate and climbs out from beneath it, which is what a real escalator\n // does anyway — and at the head the step that has climbed past the last visible one finishes\n // its cycle inside the comb plate, which is why that plate is deeper than a step's face: it\n // is the head housing the band runs into. A descending band is the same picture upside down,\n // so its spare waits in the head housing instead.\n //\n const spare =\n way > 0 ? { at: -going / 2, base: -riser - face } : { at: incline + going / 2, base: rise - face };\n const group = this.parts([spare, ...band].map(tread), color, false, finish);\n // One step's travel, in scene space, taken by projecting two plan points rather than by\n // rebuilding the rotation here: `xy` is the only thing that knows which way plan north\n // points on screen, and asking it twice is cheaper than being wrong about the frame.\n const foot = this.xy(at(0)),\n next = this.xy(at(-going * way));\n const dz = this.present(base + riser * way) - this.present(base);\n this.rig(\n `${o.id}:steps:${Math.round(base * 100)}`,\n group,\n 1,\n // Half a metre a second along the incline is an ordinary escalator — a step a second.\n 0.5 / Math.hypot(going, riser),\n (g, v) => g.position.set((next[0] - foot[0]) * v, (next[1] - foot[1]) * v, dz * v),\n true,\n );\n }\n // Balustrades: a waist-high blade either side, following the same incline.\n for (const sign of [-1, 1]) {\n const side = [sign * (o.width / 2 - 0.06), 0] as Point;\n const offset = rotate(side, rotation);\n const mid = at((topT + footT) / 2);\n const rail = {\n ...o,\n rings: [rectangle([mid[0] + offset[0], mid[1] + offset[1]], 0.1, incline, rotation)],\n } as SiteObject;\n this.slopedSurface(\n rail,\n {\n axis: [\n [at(topT)[0] + offset[0], at(topT)[1] + offset[1]],\n [at(footT)[0] + offset[0], at(footT)[1] + offset[1]],\n ],\n high: base + rise + 0.95,\n low: base + 0.95,\n },\n 0,\n 0.08,\n '#8f9a96',\n );\n }\n return;\n }\n const geometry = stairGeometry(o, run, rise, model);\n for (const landing of geometry.landings)\n this.surface([landing.ring], base + landing.height - 0.06, 0.1, color, o.id, o.material);\n for (const lane of geometry.lanes) {\n const dx = lane.head[0] - lane.foot[0],\n dy = lane.head[1] - lane.foot[1];\n const going = Math.hypot(dx, dy) / lane.steps;\n const rotation = (Math.atan2(dy, dx) * 180) / Math.PI - 90;\n for (let i = 0; i < lane.steps; i++) {\n const t = (i + 0.5) / lane.steps;\n this.surface(\n [rectangle([lane.foot[0] + dx * t, lane.foot[1] + dy * t], lane.width, going * 1.02, rotation)],\n base + lane.base + (lane.rise * i) / lane.steps,\n lane.rise / lane.steps + 0.04,\n color,\n o.id,\n o.material,\n );\n }\n }\n }\n\n /** A lift: the shaft as tall as the levels it serves, its doors on the level you are standing on,\n * and the car where the feed says it is.\n *\n * It used to be a 1.2 m box — shorter than the doors it was supposed to contain — because the\n * generic object path capped elevators there to stop them blocking the view. A lift is not\n * furniture: it is a hole through the building, and drawing it as one is the only way the plan\n * shows that floors 2 and 7 are on the same shaft. Above the level in focus it turns to ghost, so\n * it reads as continuing without becoming a column in front of everything else. */\n private lift(project: ProjectDocument, o: SiteObject, z: number, position: Point, rotation: number) {\n const color = o.color ?? COLORS[o.kind] ?? '#bfcac7';\n const own = project.floors.find(f => f.id === o.floorId)?.elevation ?? 0;\n const levels = servedFloors(project, o);\n const base = z + wallBase(o.floorId);\n const rel = (f: Floor) => z + (f.elevation - own) + wallBase(o.floorId);\n const active = project.floors.find(f => f.id === this.activeFloor);\n if (levels.length < 2) {\n this.surface(objectRings({ ...o, position, rotation }), base, Math.min(o.height, 2.4), color, o.id);\n return;\n }\n // Above ground, no lower than the map plane. A lift running up from a garage is filed under P3\n // and exempt from the below-grade skip so that it shows on every storey it serves — but that\n // exemption had it stand its shell down to -21 m over a basemap with no building around it.\n const stood = this.buried ? levels : levels.filter(f => f.elevation > -0.01);\n const lowest = stood[0] ?? levels[0];\n const bottom = Math.max(rel(levels[0]), this.buried ? -Infinity : z - own + wallBase(o.floorId));\n const top = rel(levels[levels.length - 1]) + (levels[levels.length - 1].height ?? o.height);\n // Split at the level in focus: solid to the head of this storey, ghost for whatever is above it.\n const cut = active ? Math.min(top, z + (active.elevation - own) + wallBase(o.floorId) + (active.height ?? 3)) : top;\n const shell = (from: number, to: number, ghost: boolean | number) => {\n if (to - from < 0.05) return;\n for (const [face, turn] of [\n ['front', 0],\n ['right', 90],\n ['back', 180],\n ['left', 270],\n ] as const) {\n const across = turn % 180 ? o.depth : o.width,\n depth = turn % 180 ? o.width : o.depth;\n const gap = elevatorDoorWidth(o, turn),\n spin = rotation + turn;\n const strip = (x: number, width: number, low: number, high: number) => {\n if (high <= low) return;\n const at = rotate([x, depth / 2 - 0.045], spin);\n this.surface(\n [rectangle([position[0] + at[0], position[1] + at[1]], width, 0.09, spin)],\n low,\n high - low,\n ghost ? color : '#b4bab7',\n o.id,\n undefined,\n ghost,\n );\n };\n if (!(o.doorSides ?? ['front']).includes(face)) {\n strip(0, across, from, to);\n continue;\n }\n for (const sign of [-1, 1]) strip((sign * (across + gap)) / 4, (across - gap) / 2, from, to);\n let low = from;\n for (const floor of levels) {\n const landing = rel(floor),\n head = Math.min(2.3, floor.height - 0.35);\n if (landing + head <= from || landing >= to) continue;\n strip(0, gap, low, Math.min(to, landing));\n low = Math.max(low, landing + head);\n }\n strip(0, gap, low, to);\n }\n };\n shell(bottom, cut, false);\n // Not at the plates' strength. A shaft is one thin column, not a layer over the plan, so it pays\n // none of the veil the stacked storeys are sharing out — and on a tall building that share falls\n // low enough to erase it, which takes with it the one thing in the stack that says how the\n // storeys are joined.\n if (!this.walking) shell(cut, top, Math.max(this.ghostAlpha, SHAFT_GHOST));\n // The landing doors, on the storey in focus, facing the way the lift is turned. Two leaves that\n // part: closed unless the feed says this car is standing here with its doors open.\n const reading = this.statuses?.get(o.feedId ?? '');\n const carFloor = reading?.targetFloorId ?? reading?.carFloorId ?? null;\n // The car rides to the level the feed names, or waits at the bottom of its shaft — which is what\n // an idle lift actually does. Its target is an ELEVATION, not a floor: the ride takes as long as\n // the distance, so eight storeys is a longer journey than one.\n const carAt = levels.find(f => f.id === carFloor && (this.buried || f.elevation > -0.01)) ?? lowest;\n const carHeight = Math.min(2.5, carAt.height - 0.35);\n const cabin = {\n ...o,\n position,\n rotation,\n ...cabinDimensions(o),\n };\n const floorRing = rectangle(position, cabin.width, cabin.depth, rotation);\n const detailed = this.walking && active?.id === carAt.id;\n const car = detailed\n ? makeElevatorCabin(cabin, carHeight, this.cabinFinishes(), active?.code ?? active?.name ?? '', !!reading?.moving)\n : this.parts(\n [\n { rings: [floorRing], base: 0, height: 0.1 },\n { rings: [floorRing], base: carHeight, height: 0.08 },\n ...elevatorWalls(cabin, true).map(ring => ({ rings: [ring], base: 0.1, height: carHeight - 0.1 })),\n ],\n '#dfe6e3',\n );\n if (detailed) {\n const at = this.xy(position),\n along = this.xy([\n position[0] + Math.cos((rotation * Math.PI) / 180),\n position[1] + Math.sin((rotation * Math.PI) / 180),\n ]);\n car.position.set(at[0], at[1], 0);\n car.rotation.z = Math.atan2(along[1] - at[1], along[0] - at[0]);\n }\n // Match the host's trip duration. An arrived reading must not leave the visible car travelling\n // for another twenty seconds while its controls already offer an open door.\n if (reading?.carFloorId && !reading.targetFloorId) this.rigState.set(`${o.id}:car`, rel(carAt));\n const carSpeed =\n reading?.carTravelSeconds && reading.carTravelSeconds > 0\n ? Math.max(\n 1.5,\n Math.abs(rel(carAt) - (this.rigState.get(`${o.id}:car`) ?? rel(carAt))) / reading.carTravelSeconds,\n )\n : 1.5;\n this.rig(`${o.id}:car`, car, rel(carAt), carSpeed, (g, v) => {\n g.position.z = this.present(v) - this.present(0);\n // Remote parked cars must not float above a single-storey POV shell.\n g.visible = !this.walking || !!reading?.moving || !!reading?.targetFloorId || active?.id === carAt.id;\n });\n if (active && levels.some(f => f.id === active.id)) {\n const head = Math.min(2.3, (active.height ?? 3) - 0.35);\n // Doors open only once the car is standing here. A feed that says \"open\" while the car is four\n // floors away is describing something that cannot happen, and drawing it would be a lie about\n // the building; the host sends `open` when the lift arrives.\n const arrived = Math.abs((this.rigState.get(`${o.id}:car`) ?? rel(carAt)) - rel(active)) < 0.25;\n const doorsOpen = !!reading?.open && arrived;\n // A level the shaft merely passes has no doors at all — it is not in `levels`, so this is\n // skipped there and the void is all you see. A car that opens on more than one face lists\n // them; the default is the front, which is what nearly every lift does.\n for (const face of o.doorSides ?? ['front']) {\n // Each face turns the leaves a further quarter-turn and measures across the matching side.\n const turn = { front: 0, right: 90, back: 180, left: 270 }[face];\n const spin = rotation + turn;\n // The leaves live behind the jamb, with their visible geometry clipped to the opening.\n // Translating a full leaf in front of the facade made it slide outside the shaft.\n const out = (turn % 180 === 0 ? o.depth : o.width) / 2 - 0.13;\n const local = rotate([0, out], spin),\n origin: Point = [position[0] + local[0], position[1] + local[1]];\n const at = this.xy(origin),\n along = this.xy([origin[0] + Math.cos((spin * Math.PI) / 180), origin[1] + Math.sin((spin * Math.PI) / 180)]);\n for (const sign of [-1, 1]) {\n const door = makeCabinDoor(elevatorDoorWidth(o, turn), head, sign, this.cabinFinishes());\n door.group.position.set(at[0], at[1], this.present(rel(active) + 0.015));\n door.group.rotation.z = Math.atan2(along[1] - at[1], along[0] - at[0]);\n door.group.scale.z = (this.present(rel(active) + head) - this.present(rel(active))) / head;\n this.rig(`${o.id}:door:${face}:${sign}`, door.group, doorsOpen ? 1 : 0, 2.5, (_g, v) => door.update(v));\n }\n }\n }\n }\n /** A spiral: wedge treads winding around a central pole.\n *\n * Its exits are wherever it is served — a spiral passing three levels with a landing on each is\n * one object serving three floors, which the document could already say and nothing drew. */\n private spiral(o: SiteObject, position: Point, base: number, rise: number, color: string) {\n const geometry = spiralGeometry(o, position, rise);\n for (const step of geometry.wedges)\n this.surface([closeRing(step.ring)], base + step.height - 0.07, 0.07, color, o.id);\n this.surface([rectangle(position, geometry.inner * 2, geometry.inner * 2, 0)], base, rise, '#9aa3a0', o.id);\n }\n\n update(\n project: ProjectDocument,\n floorId: string | null,\n stack: boolean,\n selected: string | null,\n sun: Sun = FIXED.day,\n statuses: Map<string, StatusReading> | null = null,\n excavation = false,\n /** Walk mode: put the floor being walked on the map's own ground plane. MapLibre's camera cannot\n * go below that plane, so a basement drawn at its true depth would be unreachable on foot. */\n walk = false,\n ) {\n // Everything below still asks \"is it evening?\" — that question has an answer, it just is not a\n // switch any more. The sun's own angle and strength are read from `sun` where they matter.\n const evening = sun.evening;\n const liftSignature = statuses\n ? [...statuses.values()]\n .filter(\n r =>\n r.carFloorId !== undefined ||\n r.targetFloorId !== undefined ||\n r.open !== undefined ||\n r.running !== undefined ||\n r.travel,\n )\n .map(\n r =>\n `${r.feedId}:${r.carFloorId ?? ''}:${r.targetFloorId ?? ''}:${r.carTravelSeconds ?? ''}:${r.open ?? ''}:${r.moving ?? ''}:${r.running ?? ''}:${r.travel ?? ''}`,\n )\n .sort()\n .join('|')\n : '';\n if (walk && this.activeFloor !== floorId) {\n for (const id of this.rigState.keys()) if (id.endsWith(':car') || id.includes(':door:')) this.rigState.delete(id);\n }\n this.statuses = statuses;\n const settled =\n this.project === project &&\n this.stack === stack &&\n this.walking === walk &&\n this.activeFloor === floorId &&\n this.liftSignature === liftSignature &&\n this.excavation === excavation &&\n this.scene.children.length > 0;\n if (settled && this.sunState === sun) {\n if (this.selected !== selected) {\n this.selected = selected;\n this.refreshHighlight();\n }\n return;\n }\n // The sun moves every ten minutes, and a building does not change when it does. Rebuilding a\n // seventeen-storey model — or a hundred-level one — to move a light would freeze the map on a\n // timer for no reason, so when the sun is the only thing that has moved, only the lights move.\n // Crossing into or out of dusk is the exception: that turns lamps on, changes the glazing and\n // recolours the contact shadows, none of which live in a light.\n if (settled && this.sunState.evening === sun.evening) {\n this.sunState = sun;\n this.relight(project, floorId, sun);\n if (this.selected !== selected) {\n this.selected = selected;\n this.refreshHighlight();\n }\n return;\n }\n if (this.project !== project) this.xyCache.clear();\n this.voidCache.clear();\n this.disposeScene();\n // The groups went with the scene; where their parts had got to did not.\n clearTimeout(this.loopTimer);\n this.loopTimer = undefined;\n this.rigs = [];\n this.project = project;\n this.stack = stack;\n this.walking = walk;\n this.lampLit =\n !!walk && !!floorId && project.objects.some(o => o.floorId === floorId && o.kind === 'light' && !!o.light);\n const poolLighting =\n project.floors.find(f => f.id === floorId)?.light?.level === 0 &&\n project.objects.some(o => o.floorId === floorId && !!o.water);\n this.poolLitOnly = walk && poolLighting;\n this.poolOverview = !walk && poolLighting;\n this.activeFloor = floorId;\n this.selected = selected;\n this.sunState = sun;\n this.liftSignature = liftSignature;\n this.excavation = excavation;\n this.revision++;\n // Standing in it, most of a floor is behind you and a lamp's shadow reaches twelve metres:\n // batch the floor in cells so the frustum and the shadow passes can leave the rest alone. From\n // above, everything is in the frame and one mesh per material is cheapest.\n this.batch.chunk = walk ? 20 : 0;\n const exterior = exteriorWalls(project);\n const index = floorIndex(project),\n floors = index.floors;\n const buildings = new Map(project.buildings.map(b => [b.id, b]));\n const barriers = new Map(project.barriers.map(b => [b.id, b]));\n const finishes = new Map(\n project.barriers.map(b => {\n const preset = buildings.get(floors.get(b.floorId ?? '')?.buildingId ?? '')?.exteriorPreset;\n return [\n b.id,\n exterior.has(b.id)\n ? preset\n ? EXTERIOR_PRESETS[preset]\n : b.material\n ? { material: b.material, color: b.color ?? '#c8c3b7' }\n : EXTERIOR_PRESETS.limestone\n : {\n material: b.material ?? (b.kind === 'wall' ? ('plaster' as const) : undefined),\n // An interior wall is plastered, and plaster is near-white. COLORS.wall is the grey\n // a wall is DRAWN in — a stroke on a plan has to read against a pale floor, so it is\n // mid-grey by necessity — and standing that grey up as a surface, shaded and with\n // contact shadow at its foot, made every partition read as bare concrete. A fence\n // keeps its drawn colour: it has no plaster and is not a room's wall.\n color: b.color ?? (b.kind === 'wall' ? '#eef0f3' : COLORS[b.kind]),\n },\n ];\n }),\n );\n const view = undergroundView(project, floorId, stack),\n activeF = view.active,\n buried = view.buried;\n this.buried = buried;\n this.depthScale = view.depthScale;\n this.presentedElevation = view.elevation;\n // The datum a cutaway builds its geometry about: the level in focus, at the depth the DOCUMENT\n // gives it, because present() is what maps a depth for the screen and it wants authored metres\n // to work on. Rebasing to the compressed depth here and then adding raw deltas to it was the\n // two-mappings bug: the plate landed where the camera aims and everything referred to it did not.\n this.rebase = stack || walk ? 0 : (activeF?.elevation ?? 0);\n // What an authored elevation has to be shifted by to land in the frame the rest of the scene is\n // drawn in — see sceneGround. Zero in every view but a walk, which is the one that moves the\n // level in focus away from where the document put it.\n const ground = sceneGround(stack, this.rebase, activeF?.elevation ?? 0);\n this.ground = ground;\n // Deep stacks show the complete structure with detail on the selected floor. Building every\n // room and fitting hundreds of metres into a city camera wasted work on hidden geometry.\n //\n // Only where the depth mapping is actually compressing something. Counting levels said yes to\n // Stockmann's seventeen storeys, which are drawn at their true depths and fit on the screen\n // perfectly well, so \"All floors\" from any basement threw away fourteen above-ground storeys\n // and drew wire rings where the building was.\n const structureOverview = buried && stack && view.compressed && !!activeF;\n const outlineOnly = new Set(\n structureOverview ? view.levels.filter(f => f.elevation > activeF!.elevation).map(f => f.id) : [],\n );\n // Storeys UNDER the one in focus are drawn as a shell: exterior walls and one slab, nothing\n // inside. Looking down a stack you cannot see a lower storey's partitions through its own\n // ceiling anyway, so building them is geometry nobody sees — and on a tall building it is most\n // of the scene. The shell still says where the storey is and how far it reaches.\n const shellBelow = new Set(\n stack && activeF\n ? view.levels.filter(f => f.buildingId === activeF.buildingId && f.elevation < activeF.elevation).map(f => f.id)\n : [],\n );\n this.center = MercatorCoordinate.fromLngLat(toLngLat([0, 0], project.origin));\n this.unit = this.center.meterInMercatorCoordinateUnits();\n this.transform\n .makeTranslation(this.center.x, this.center.y, 0)\n .scale(new THREE.Vector3(this.unit, -this.unit, this.unit));\n // Budget the light so an up-facing surface lands near its own albedo instead of well past it.\n // Hemisphere + environment + sun previously summed to roughly 2x on a horizontal plate, so every\n // mid tone clipped toward white and a whole floor read as paper however its colours were authored.\n // Image-based lighting is here for specular life on surfaces, not to flood the scene with fill:\n // pushed up it washes the model to paper-white and flattens the very shading it is meant to add.\n // Keep it low, keep the sun strong, and the model gains depth instead of losing it.\n // The level in focus decides what the interior light is, because that is the level you are\n // looking into. A stack is lit by the one in focus too: they are usually the same building with\n // the same fit-out, and lighting seventeen storeys three different colours at once would say\n // something about the building that is not true.\n // Inspection lighting keeps the overview readable when the authored room has only submerged\n // fixtures. Those lights and their shadow passes are reserved for walking mode.\n const air = ambient(\n sun,\n this.poolOverview ? { kelvin: 6500, level: 1 } : project.floors.find(f => f.id === floorId)?.light,\n );\n // Walking, the eye is inside and adapted to the inside. The exposure that keeps a plan legible\n // from above is set against the basemap — a small pale plate over a pale map — and at eye level\n // that same plate fills the lower half of the frame and clips to white. A clipped floor has no\n // contrast left to give: it is the flat grey field you see when you stand in one. Stopping down\n // is what an eye does on the way through the door, and it hands the range back to the floor.\n // Standing inside, the eye is adapted to the inside. The exposure that keeps a plan legible from\n // above is set against the basemap — a small pale plate over a pale map — and at eye level that\n // same plate fills the lower half of the frame and clips to white. A clipped floor has no\n // contrast left to give: it is the flat grey field you see when you stand in one.\n if (this.renderer) this.renderer.toneMappingExposure = walk ? 0.68 : 0.9;\n this.scene.environment = this.environmentMap(evening);\n this.scene.environmentRotation.set(Math.PI / 2, 0, 0);\n this.scene.environmentIntensity = this.poolLitOnly ? 0 : air.environment;\n const sky = new THREE.HemisphereLight(air.sky, air.ground, this.poolLitOnly ? 0 : air.hemisphere);\n sky.position.set(0, 0, 1);\n sky.layers.enableAll();\n this.scene.add(sky);\n this.skyLight = sky;\n // The building's own lighting, which does not care what the sun is doing. Offices, shop floors\n // and garages burn their lights around the clock, and Kerros draws buildings from the inside —\n // so a storey in section at midnight is lit by this and stays readable, while outside goes dark.\n // A ceiling light lands most of itself on the floor, so the floor comes out the brightest plane\n // in the room — which is true of the light and false of the picture, because a real floor is the\n // darkest one. Looking down into a cutaway that does not matter; the plate is a small patch in a\n // big frame. At eye level it is half the frame, and it blew out. Walking, the lamps come down and\n // the luminous ceiling carries the reading of a lit interior instead.\n const room = new THREE.HemisphereLight(\n air.interior,\n air.interiorBounce,\n walk && this.lampLit ? air.interiorLevel * 0.45 : air.interiorLevel,\n );\n room.position.set(0, 0, 1);\n this.scene.add(room);\n this.roomLight = room;\n const beam = sunlight(sun);\n const light = new THREE.DirectionalLight(beam.color, this.poolLitOnly ? 0 : beam.intensity);\n light.position.set(...beam.position);\n // A dim, cool fill from the opposite quarter. Real interiors and streets bounce light back into\n // the shadow side; without it every unlit façade collapses to the same dead tone.\n const fill = new THREE.DirectionalLight(\n evening ? '#7f90bd' : '#cfe0f2',\n this.poolLitOnly ? 0 : evening ? 0.16 : 0.18,\n );\n fill.layers.enableAll();\n fill.position.set(evening ? -80 : 85, evening ? 60 : 55, 45);\n this.scene.add(fill);\n light.layers.enableAll();\n light.castShadow = true;\n light.shadow.autoUpdate = false; // redrawn by refreshShadows(), not by every lamp that moves\n light.shadow.mapSize.set(2048, 2048);\n light.shadow.bias = -0.00015;\n light.shadow.normalBias = 0.025;\n // The frustum is fitted to the finished model below; this is only a safe starting box.\n Object.assign(light.shadow.camera, { left: -140, right: 140, top: 140, bottom: -140, near: 1, far: 500 });\n this.scene.add(light);\n this.scene.add(light.target);\n this.sun = light;\n // A level is below grade if its own floor sits under 0 — used to keep buried levels out of the\n // above-ground views (see the visibility rules below).\n const belowGrade = (fid: string | null) => !!fid && (floors.get(fid)?.elevation ?? 0) < 0;\n // Is there anything under the level in focus, in its own building? Only then does its plate have\n // to be see-through — on a ground floor or a single-storey site it stays solid.\n const levelsBelowActive =\n !!activeF && view.levels.some(f => f.buildingId === activeF.buildingId && f.elevation < activeF.elevation);\n // Ghosts do not sort and do not cancel: each layer multiplies into the next, so the strength\n // that lets a house's two storeys read through one another turns a tower into a solid block.\n //\n // The share used to be 1/levels clamped into [0.17, 0.38], which stops sharing at six levels and\n // hands seventeen the same 0.17 it hands six — measured on Stockmann, every one of the seventeen\n // drew at the floor of the clamp. n layers at a each pass (1-a)^n of whatever is behind them, so\n // the only arithmetic that means anything on a tall building is to fix what must come through\n // and solve for a. And to count each side of the storey in focus separately, because the two\n // sides are asked for different things: what is ABOVE stands between the eye and the focus and\n // has to leave most of it, while what is BELOW is already behind the focus's own half-clear\n // plate and needs the strength to show through it. One number for both is why picking a low\n // floor of a tall building used to bury it under everything it was picked out of.\n const share = (transmit: number, levels: number) =>\n Math.max(0.035, Math.min(0.38, 1 - transmit ** (1 / Math.max(1, levels))));\n this.ghostAlpha = share(FOCUS_SEEN, view.levels.filter(f => f.elevation > (activeF?.elevation ?? 0)).length);\n this.underAlpha = share(UNDER_SEEN, view.levels.filter(f => f.elevation < (activeF?.elevation ?? 0)).length);\n /** How strongly a storey that is not the one in focus draws — and, since a batch is cut by\n * material, which side of the active plate its geometry ends up being drawn on. `kase` is the\n * envelope and the partitions, which are looked through rather than at. */\n const ghostStrength = (fid: string | null | undefined, kase = false) =>\n kase\n ? CASE_ALPHA\n : activeF && (floors.get(fid ?? '')?.elevation ?? 0) < activeF.elevation\n ? this.underAlpha\n : this.ghostAlpha;\n // An entresol is a partial level — a gallery ringing a void — so on its own it is a thin loop\n // floating over nothing. The storey it overlooks is what gives it something to be above, and in\n // 2D the plan has always drawn that; 3D showed the loop alone. Carry the level below with it.\n const under =\n activeF?.mezzanine && !stack\n ? project.floors\n .filter(f => f.buildingId === activeF.buildingId && f.elevation < activeF.elevation)\n .sort((a, b) => b.elevation - a.elevation)[0]\n : undefined;\n // The mirror of `under`, and the reason a hall never showed the gallery hanging in it: a\n // mezzanine sits INSIDE the storey below it, so from the ground floor the entresol is a level\n // nothing draws and the twelve flights climbing to it end in mid-air. A mezzanine whose datum\n // falls within the active storey belongs to it, seen from below.\n //\n // Mezzanines only. A gallery drawn tall enough to stand in can reach past its host storey's\n // head, and taking every level that starts inside the storey would then hang the whole floor\n // above it over the hall as well.\n const over =\n activeF && !stack\n ? project.floors.filter(\n f =>\n f.mezzanine &&\n f.buildingId === activeF.buildingId &&\n f.id !== activeF.id &&\n f.elevation > activeF.elevation &&\n f.elevation < activeF.elevation + activeF.height,\n )\n : [];\n // The storeys a single-floor view draws beneath the one in focus, as a façade envelope: their\n // slabs, their exterior walls and their glazing. A mezzanine's carried level is left out — it is\n // drawn in full above, and drawing it again put a second uncut slab and a second set of windows\n // through the first.\n const lower = new Map(\n !stack && !walk && activeF\n ? view.levels\n .filter(fl => fl.elevation >= 0 && fl.elevation < activeF.elevation && fl.id !== under?.id)\n .map(fl => [fl.id, fl] as const)\n : [],\n );\n // Below grade there is no envelope to fall back on: the cutaway drew the deck in focus and\n // nothing under it, so every ramp and every arriving flight ended in mid-air over bedrock.\n // Shell the storey immediately below, the way the stack shells the ones beneath its focus.\n const belowShell =\n buried && !stack && !walk && activeF\n ? view.levels\n .filter(f => f.elevation < activeF.elevation && f.id !== under?.id)\n .sort((a, b) => b.elevation - a.elevation)[0]\n : undefined;\n // Every storey this view actually builds below the one in focus.\n const spanningObjects = walk ? tallSpaceContext(project, floorId) : [];\n const contextFloors = new Set(spanningObjects.map(o => o.floorId).filter(Boolean) as string[]);\n const atrium =\n walk && activeF && floorId ? walkVoidContext(project, activeF, walkCeiling(project, floorId)!.floor) : undefined;\n const connections =\n walk && activeF\n ? walkConnectionContext(project, activeF, index.primary).filter(\n f => f.id !== under?.id && !over.some(o => o.id === f.id) && !contextFloors.has(f.id),\n )\n : [];\n const connectionIds = new Set(connections.map(f => f.id));\n const structuralLevels = [...new Map([...(atrium?.levels ?? []), ...connections].map(f => [f.id, f])).values()];\n const drawnLevels = new Set<string>(\n [...shellBelow, ...lower.keys(), ...contextFloors, under?.id, belowShell?.id, floorId].filter(\n Boolean,\n ) as string[],\n );\n /** Does a hole in this level's plate open onto a storey that is drawn? A stairwell punched\n * through a floor with nothing under it is not a stairwell: on the ground floor all twelve of\n * them opened straight onto the basemap. The stack draws every storey, so there it always is. */\n const punchWells = (fid: string) =>\n this.walking ||\n stack ||\n view.levels.some(f => f.elevation < (floors.get(fid)?.elevation ?? 0) && f.id !== fid && drawnLevels.has(f.id));\n /** Where a floor's geometry is built, before present() maps it for the screen: the elevation the\n * document authored in a cutaway, and the height above the walked storey in a walk. Out of doors\n * is grade, which is `ground` away from the floor being walked. */\n const relative = (fid: string | null) =>\n fid\n ? this.rebase + ((floors.get(fid)?.elevation ?? activeF?.elevation ?? 0) - (activeF?.elevation ?? 0))\n : ground;\n // Transform the drawing axis through the site's bearing and Mercator frame. Shared UVs\n // keep adjacent rooms in register without rotating the cached material for other levels.\n const floorAxes = new Map<string, Point>();\n const floorAxis = (id: string | null): Point | undefined => {\n if (!id) return;\n let axis = floorAxes.get(id);\n if (!axis) {\n const a = this.xy([0, 0]),\n b = this.xy(rotate([1, 0], mainAxis(project, id)));\n const length = distance(a, b);\n axis = [(b[0] - a[0]) / length, (b[1] - a[1]) / length];\n floorAxes.set(id, axis);\n }\n return axis;\n };\n /** Where an authored depth is shown, for the geometry that is placed outright rather than built\n * and then presented: the excavation face and the cage. Same mapping present() puts the model\n * through, or the soil and the plate standing in it disagree about how deep the storey is. */\n const shown = (z: number) => sceneElevation(view, walk, z);\n const visibleObjects = stack\n ? project.objects\n : // Deduplicated: a shaft filed under the storey below reaches this one, and the carried\n // levels bring their own copy of the same object.\n [\n ...new Map(\n [\n ...(index.objects.get(null) ?? []),\n ...(under ? (index.objects.get(under.id) ?? []) : []),\n ...over.flatMap(f => index.objects.get(f.id) ?? []),\n ...spanningObjects,\n // Openings in the carried walls need their doors and glazing as well.\n ...connections.flatMap(f =>\n (index.objects.get(f.id) ?? []).filter(o => o.kind === 'door' || o.kind === 'window'),\n ),\n ...(floorId ? (index.objects.get(floorId) ?? []) : []),\n // A stair that climbs to this level belongs on it, even though it is filed under the\n // one it starts from. Without this the flight you are standing at the top of is not\n // drawn.\n ...(floorId ? (index.reaching.get(floorId) ?? []) : []),\n // And a driveway that surfaces belongs to the street as much as to the deck it leaves.\n // It is filed on the deck, so the site view — which iterates the site's own objects —\n // never saw it, and the garage came out with no mouth at the kerb.\n ...(floorId === null\n ? project.objects.filter(o => o.slope && Math.max(o.slope.high, o.slope.low) >= -0.01)\n : []),\n // A ramp is a floor that is two floors. It is filed on the deck it leaves, so the deck\n // it arrives at drew nothing: from P2 the ramp down from P1 stopped existing, and a\n // car came up out of a plate with no way onto it. Both decks it joins, then — the\n // levels its own slope starts and ends at, rather than every storey the incline passes\n // through. The driveway out to Mannerheimintie crosses -4.2, -6.6 and -9 a hundred\n // metres away under the street, and it has nothing to do with any of them.\n ...(activeF\n ? project.objects.filter(\n o =>\n rampJoins(o, activeF.elevation) && floors.get(o.floorId ?? '')?.buildingId === activeF.buildingId,\n )\n : []),\n ].map(o => [o.id, o] as const),\n ).values(),\n ];\n for (const o of visibleObjects) {\n if (buried && (o.floorId === null || (activeF && floors.get(o.floorId)?.buildingId !== activeF.buildingId)))\n continue;\n // The mirror of the rule above: standing above ground you cannot see through the earth, so\n // below-grade levels stay hidden until you go down to one. The excavation is only dug when\n // you are buried, so without this a basement — and especially a garage that sprawls past the\n // tower — hangs over the surrounding streets with no ground around it.\n // A shaft is the exception: it is filed under the lowest level it serves, which for a lift\n // running from a garage is below grade, and skipping it there would hide the whole shaft from\n // every storey above. It stands where it reaches, so it is judged by the level in focus.\n // And a driveway that surfaces is the second: a ramp climbing out of the garage belongs to the\n // street as much as to the deck it leaves, so on the site view it is drawn diving into the\n // ground where it really does. Hiding it left the garage with no mouth and the kerb with an\n // unexplained gap in it.\n const surfaces = floorId === null && !!o.slope && Math.max(o.slope.high, o.slope.low) >= -0.01;\n if (\n !buried &&\n belowGrade(o.floorId) &&\n !connectionIds.has(o.floorId!) &&\n !(isVertical(o.kind) && reaches(project, o, floorId)) &&\n !surfaces\n )\n continue;\n // A twin of a shaft already drawn from its lowest level. One lift, one shaft.\n if (isVertical(o.kind) && !index.primary.has(o.id)) continue;\n // A shaft is filed under the LOWEST level it serves, and every rule that hides a storey under\n // the one in focus was hiding the shafts with it: the store's twelve cores are filed on Herkku\n // and the garage's on P3, so \"All floors\" showed a building of punched stairwells with nothing\n // in them unless you happened to be standing on one of those two levels. A shaft is not on a\n // storey, it is between them — exempt, the way an exterior wall already is.\n const spanning = isVertical(o.kind);\n if (o.floorId && outlineOnly.has(o.floorId) && !spanning) continue;\n // A storey under the one in focus keeps its PLAN and loses its fit-out. It used to lose both:\n // the shell replaced every level below with one union slab in one flat grey, which on\n // Stockmann turned ten storeys of plan into ten identical rectangles — and a mode called \"All\n // floors\" that shows none of them is the whole complaint. The plates are what a doll's house\n // is for, and they are also the cheap half: a retail storey is a plate and a room, and even\n // an office fit-out is a hundred flat shapes against its hundreds of extruded partitions.\n // Partitions and fittings stay dropped, because looking down through a stack a partition is a\n // smear and the plate is the thing that says what the storey is.\n // Not on a stack deep enough to be compressed: structureOverview exists precisely so that a\n // hundred-metre shaft does not build every bay on every deck, and there the shell slab goes on\n // standing in for the plans.\n const planPlate = !structureOverview && (o.kind === 'room' || o.kind === 'zone' || !!o.slope);\n if (o.floorId && shellBelow.has(o.floorId) && !spanning && !planPlate) continue;\n if (structureOverview && o.floorId !== floorId && o.kind !== 'zone') continue;\n const z = stack ? (floors.get(o.floorId ?? '')?.elevation ?? 0) : relative(o.floorId);\n const indoorFinish = o.floorId !== null && (o.kind === 'room' || o.kind === 'zone');\n // Stacked view reads as a doll's house: every storey but the selected one turns translucent,\n // and the active level keeps its authored colours at full strength inside the glassy stack.\n //\n // Storeys below used to stay solid, which sounds right and is not: a solid plate hides the one\n // beneath it, so a seventeen-level building rendered as a single shelf in a closed brick box\n // and \"All floors\" showed exactly one. Whatever is below has to be see-through as well, or\n // there is nothing to see through to.\n //\n // And a ghost keeps the colour it was authored in. `ghost` darkens rather than tints precisely\n // so that it can — the comment on it says as much — but every ghosted plate was arriving here\n // already repainted the one neutral the carried levels under a cutaway want, so seventeen\n // storeys came out the same grey and the stack could not tell you that any of them differed.\n const activeLevel = floorId !== null && o.floorId === floorId;\n const ghosted = !!(stack && floorId !== null && o.floorId && o.floorId !== floorId);\n // A plate is the plan; anything standing up on a storey you are not looking at is in the way.\n const ghostFill = ghosted && ghostStrength(o.floorId, !(o.kind === 'room' || o.kind === 'zone'));\n // Looking down a stack, the active storey's plate is a lid over everything beneath it: pick the\n // top floor and the ones below vanish, however faithfully they are drawn. Only its own plate\n // has to give — its walls stay solid, so the level still reads as the one in focus.\n const lidsOverBelow = stack && activeLevel && levelsBelowActive;\n const color =\n this.mapStyle.objectColor?.(o) ??\n (activeLevel || ghosted\n ? (o.color ?? COLORS[o.kind] ?? '#e6e8e1')\n : indoorFinish && !o.material\n ? // A carried level under a cutaway is background: one neutral, so it reads as context\n // for the storey in focus rather than competing with it.\n '#e5e4df'\n : (o.color ?? COLORS[o.kind] ?? '#e6e8e1'));\n if (o.water && o.rings?.length) {\n if (!ghosted) {\n this.scene.add(\n makePool(o, pt => this.xy(pt), this.present(z + LIFT + SLAB), this.materials, this.waterTime, walk),\n );\n this.hasWater = walk;\n }\n continue;\n }\n if (o.slide) {\n if (!ghosted)\n this.scene.add(makeWaterSlide(o, pt => this.xy(pt), this.present(z + LIFT + SLAB), this.materials));\n continue;\n }\n if (o.kind === 'fixture' || o.kind === 'landscape') {\n if (ghosted) continue;\n const fixture = makeFixture(\n o,\n pt => this.xy(pt),\n z + (o.floorId ? LIFT + SLAB : GROUND),\n this.materials,\n evening,\n );\n if (buried && !walk && z < 0) {\n const base = fixture.position.z,\n height = Math.max(o.height, 0.01);\n fixture.position.z = this.present(base);\n fixture.scale.z = (this.present(base + height) - this.present(base)) / height;\n }\n // Fold the fixture's boxes into the shared batch rather than adding a group of loose meshes:\n // each one was its own draw call and its own buffer upload, and a floor of parked cars or\n // desks runs to thousands of them.\n for (const leftover of this.batch.addObject(fixture, o.id, o.floorId === null)) this.scene.add(leftover);\n continue;\n }\n if (o.rings && o.slope) {\n // A sloped deck carries its own authored elevations, so it ignores the floor's plate height\n // and has to be brought into the scene's frame by hand — see sceneGround.\n //\n // Ghosted too, in the stack. A ramp is a storey's plan as much as its deck is, and skipping\n // it left the driveway out of every level but the one in focus — the shell slab used to\n // carry the ramp's footprint flat, and now that the storey draws its own plates it has to\n // draw its own slopes with them or the garage loses its way in and out.\n this.slopedSurface(o, o.slope, LIFT + SLAB + ground, SLAB, color, ghostFill);\n // Wheel curbs follow the incline and its flat aprons; both ends stay open for turning.\n const [head, foot] = o.slope.axis;\n const axisLength = distance(head, foot);\n const ring = closeRing(o.rings[0]);\n for (let i = 1; i < ring.length; i++) {\n const a = ring[i - 1],\n b = ring[i],\n length = distance(a, b);\n const along =\n ((b[0] - a[0]) * (foot[0] - head[0]) + (b[1] - a[1]) * (foot[1] - head[1])) / (length * axisLength);\n if (!Number.isFinite(along) || Math.abs(along) < 0.98) continue;\n const edge = {\n ...o,\n rings: [\n rectangle(\n [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2],\n length,\n 0.18,\n (Math.atan2(b[1] - a[1], b[0] - a[0]) * 180) / Math.PI,\n ),\n ],\n };\n this.slopedSurface(edge, o.slope, LIFT + SLAB + ground + 0.16, 0.16, '#c7bd91', ghostFill);\n }\n continue;\n }\n if (o.rings) {\n if (o.kind === 'building' && floorId !== null) continue;\n const indoor = o.floorId !== null,\n elevated = ['office', 'container'].includes(o.kind);\n const base =\n z +\n (indoor\n ? (o.kind === 'room' ? LIFT + SLAB + 0.015 : LIFT) + nestingLift(objectArea(o))\n : o.kind === 'parcel'\n ? 0.02\n : GROUND);\n const height = elevated ? o.height : indoor ? (o.kind === 'room' ? ROOM : SLAB) : 0.04;\n // Clipping can split an aisle into separate polygons; each keeps its own holes.\n const plates =\n indoor && o.floorId\n ? this.withVoids(project, o.rings, o.floorId, index.primary, 'floor', punchWells(o.floorId))\n : [o.rings];\n for (const plate of plates)\n this.surface(\n plate,\n base,\n height,\n color,\n o.id,\n // The floor you are standing on used to be the one surface with no finish at all, which left\n // the largest expanse in the frame as flat untextured colour. Give it the same plaster as\n // the levels below — it is subtle enough not to compete with the plan, and without it a\n // whole storey reads as paper.\n ghosted ? undefined : (o.material ?? (indoorFinish ? 'plaster' : undefined)),\n ghostFill,\n false,\n lidsOverBelow && indoorFinish\n ? this.materials.plate(color)\n : // Walking, the floor is the one surface that can say where the light is, and only\n // because you see it along rather than down onto it.\n walk && indoorFinish && !ghosted && o.material !== 'carpet'\n ? this.materials.polished(this.materials.get(o.material ?? 'plaster', color))\n : undefined,\n !indoor,\n undefined,\n floorAxis(o.floorId),\n );\n } else if (['stairs', 'elevator', 'turnstile', 'door', 'gate', 'window'].includes(o.kind)) {\n // A door or a window belongs to its own storey and is left to it when that storey is only a\n // ghost. A shaft belongs to all of them at once, and the rule that skipped every ghosted\n // opening was the last one hiding the stairs from \"All floors\": it stays, at full strength,\n // because it is the one thing in the stack that says how the storeys are joined.\n if (!ghosted || spanning) this.opening(project, o, z);\n } else if (['office', 'container', 'storage'].includes(o.kind)) {\n this.surface(\n objectRings(o),\n z + wallBase(o.floorId),\n o.height,\n color,\n o.id,\n ghosted ? undefined : o.material,\n ghostFill,\n false,\n undefined,\n o.floorId === null,\n );\n }\n }\n // One slab per shell storey — the ceiling you look down onto — merged from its top-level plates\n // so a wing or a ramp is included and the interior divisions are not. One surface, one union,\n // per storey: the whole point of the shell is that it costs a fraction of the real floor.\n //\n // The cutaway's one shelled storey, and a compressed stack's. An ordinary stack no longer shells\n // the levels below its focus: they draw their own plates and their own ramps now, so the union\n // would be the same ground covered a second time — in one flat grey over the colours that had\n // just been recovered.\n for (const fid of [...(structureOverview ? shellBelow : []), ...(belowShell ? [belowShell.id] : [])]) {\n // Standing above ground you cannot see through the earth, and the object and wall loops both\n // say so — but the shell did not, so ghost slabs for the basements hung under the streets.\n if (!buried && belowGrade(fid)) continue;\n const z = stack ? (floors.get(fid)?.elevation ?? 0) : relative(fid);\n for (const pg of shellPlate(project, fid, index.primary, { lowest: buried ? -Infinity : -0.01 }))\n this.surface(pg, z + LIFT + SLAB, SLAB, '#e5e4df', `shell:${fid}`, undefined, stack && ghostStrength(fid));\n }\n // Walk mode gets a lid. An open-topped floor plate is not a room: the light has nothing to come\n // off, the floor runs away to the horizon and a shop floor reads as grey tarmac. The ceiling is\n // most of what makes an interior look like an interior from inside it. Cutaway keeps its open\n // top — looking down into a storey is the whole point of that view.\n //\n // Drawn per area rather than as one unioned lid, which is how it was first written and how the\n // shell slab still is. polygon-clipping's sweep line gives up on a real office fit-out — the\n // demo's 134-room level throws \"Unable to find segment … in SweepLine tree\" — and the union's\n // only fallback is no ceiling at all, which is exactly what a storey full of rooms got. Each\n // area's own rings already describe its shape, and withVoids already punches the stairwells\n // through them; nesting keeps a room's ceiling a hair below the zone's, which is coplanar-safe\n // and is also true of every fit-out inside a bigger space.\n if (walk && floorId && activeF) {\n // The underside of the storey above, and never below the walker's own eye — see walkSoffit.\n const { floor: ceilingFloor, soffit } = walkCeiling(project, floorId)!;\n // Lit by how much the floor's lamps are ON, not by how hard they are working. The room light\n // dims as daylight comes in, and tying the soffit to that made the ceiling go dark at noon —\n // the one time of day a room is unmistakably bright. A ceiling is the source, so it is the\n // brightest plane in the room or it is not a ceiling.\n const lit = this.materials.luminous('#f0f1ee', air.interior, 0.8 * (activeF.light?.level ?? 1), 'ceiling');\n const tiled = this.materials.luminous('#f2f3ef', air.interior, 0.7 * (activeF.light?.level ?? 1), 'tile');\n const tallRoofs = spanningObjects.filter(\n o => o.ceilingHeight && o.rings?.length && (floors.get(o.floorId!)?.elevation ?? 0) < activeF.elevation,\n );\n const openCeiling = (rings: Ring[][]) => {\n if (!atrium?.ceilingOpenings.length) return rings;\n try {\n return polygonClipping.difference(\n rings as never,\n ...atrium.ceilingOpenings.map(r => [r] as never),\n ) as unknown as Ring[][];\n } catch {\n return rings;\n }\n };\n for (const o of [...(index.objects.get(ceilingFloor.id) ?? []), ...tallRoofs]) {\n if (!o.rings?.length || (o.kind !== 'room' && o.kind !== 'zone')) continue;\n if (o.water || o.slope) continue;\n if (!o.ceilingHeight && tallRoofs.some(hall => pointInRing(o.position, hall.rings![0]))) continue;\n const roof =\n o.ceilingHeight !== undefined\n ? walkSoffit(\n 0,\n (floors.get(o.floorId!)?.elevation ?? activeF.elevation) + o.ceilingHeight - activeF.elevation,\n )\n : soffit;\n for (const plate of openCeiling(this.withVoids(project, o.rings, ceilingFloor.id, index.primary, 'ceiling')))\n this.surface(\n plate,\n roof - nestingLift(objectArea(o)),\n SLAB,\n '#f0f1ee',\n `ceiling:${o.id}`,\n undefined,\n false,\n false,\n o.material === 'tile' ? tiled : lit,\n false,\n undefined,\n floorAxis(ceilingFloor.id),\n );\n }\n // The wells the stairs and escalators climb through are punched out of the lid, and only this\n // storey is built — so through each one you looked straight at the sky. What is up a well is\n // the storey above: put its ceiling over the well, a storey higher and unlit, so the flight\n // climbs into a building rather than out of one.\n //\n // The storey above is the first one that starts at or past this storey's head, not simply the\n // next level up: a mezzanine hanging inside this storey is drawn in the room with you, and\n // taking its lid for the well head would have put the cap below the ceiling it is capping.\n const overhead = project.floors\n .filter(\n f =>\n f.buildingId === activeF.buildingId && f.elevation >= ceilingFloor.elevation + ceilingFloor.height - 0.01,\n )\n .sort((a, b) => a.elevation - b.elevation)[0];\n const wellHead = Math.max(\n soffit + SLAB,\n overhead ? walkSoffit(relative(overhead.id), overhead.height) : soffit + activeF.height,\n );\n const wells = shaftVoids(project, ceilingFloor.id, index.primary, {\n through: 'ceiling',\n lowest: buried ? -Infinity : -0.01,\n });\n if (!structuralLevels.length)\n for (const [i, well] of wells.entries())\n this.surface([well], wellHead, SLAB, '#d9dad6', `well:${floorId}:${i}`);\n // Complete structural plates support the surfaces visible through the atrium. Isolated well\n // caps looked like floating furniture, while ghost shafts continued into an otherwise empty sky.\n for (const level of structuralLevels) {\n if (level.id === under?.id || over.some(f => f.id === level.id) || contextFloors.has(level.id)) continue;\n const z = relative(level.id);\n const finish = (index.objects.get(level.id) ?? []).find(\n o => o.kind === 'zone' && !o.parentId && !o.slope && o.material,\n );\n for (const plate of shellPlate(project, level.id, index.primary, { lowest: -Infinity }))\n this.surface(\n plate,\n z + LIFT,\n SLAB,\n finish?.color ?? '#deddd6',\n `atrium-plate:${level.id}`,\n finish?.material ?? 'plaster',\n false,\n false,\n undefined,\n false,\n undefined,\n floorAxis(level.id),\n );\n if (connectionIds.has(level.id) && !atrium?.levels.some(f => f.id === level.id)) {\n // A whole ceiling and the surrounding walls replace the floating cap over each well.\n // Keep holes toward the active floor; the far side of this context is capped until visited.\n for (const ring of floorOutline(project, level.id))\n for (const plate of level.elevation < activeF.elevation\n ? this.withVoids(project, [ring], level.id, index.primary, 'ceiling')\n : [[ring]])\n this.surface(\n plate,\n walkSoffit(z, level.height),\n SLAB,\n '#e4e2db',\n `connection-ceiling:${level.id}`,\n 'ceiling',\n );\n }\n }\n if (atrium?.roof)\n for (const ring of floorOutline(project, atrium.roof.id))\n this.surface(\n [ring],\n relative(atrium.roof.id) + atrium.roof.height + LIFT,\n SLAB,\n '#e4e2db',\n `atrium-roof:${atrium.roof.id}`,\n 'ceiling',\n );\n }\n // A carried level brings its walls too, or its rooms read as floating colour — the level below a\n // mezzanine, and the mezzanine hanging inside the storey you are looking at.\n const allPieces = [\n ...wallPieces(project, floorId, stack),\n ...(under ? wallPieces(project, under.id, false) : []),\n ...over.flatMap(f => wallPieces(project, f.id, false)),\n // Distant atrium levels retain their authored envelope and open railings. A synthetic\n // wall around every outline ring incorrectly sealed the hole from floor to ceiling.\n ...structuralLevels\n .filter(f => f.id !== under?.id && !over.some(o => o.id === f.id) && !contextFloors.has(f.id))\n .flatMap(f =>\n wallPieces(project, f.id).filter(\n p => connectionIds.has(f.id) || exterior.has(p.id) || barriers.get(p.id)?.kind === 'fence',\n ),\n ),\n ...[...contextFloors]\n .filter(id => id !== under?.id && !over.some(f => f.id === id))\n .flatMap(id =>\n wallPieces(project, id, false).filter(piece =>\n spanningObjects.some(\n o => o.floorId === id && o.rings?.length && piece.ring.some(pt => pointInRing(pt, o.rings![0])),\n ),\n ),\n ),\n ];\n for (const p of allPieces) {\n if (buried && (p.floorId === null || (activeF && floors.get(p.floorId)?.buildingId !== activeF.buildingId)))\n continue;\n if (!buried && belowGrade(p.floorId) && !connectionIds.has(p.floorId!)) continue;\n if (p.floorId && outlineOnly.has(p.floorId)) continue;\n if (p.floorId && shellBelow.has(p.floorId) && !exterior.has(p.id)) continue;\n if (structureOverview && p.floorId !== floorId && !exterior.has(p.id)) continue;\n const finish = finishes.get(p.id)!;\n const barrier = barriers.get(p.id)!;\n // Enclose the service gap between a suspended ceiling and the next structural slab. It\n // becomes visible while climbing; without this perimeter band the basement exposes sky.\n const own = floors.get(p.floorId ?? '');\n if (walk && own && !own.mezzanine && exterior.has(p.id) && p.height >= own.height - SLAB - 0.01) {\n const next = project.floors\n .filter(f => f.buildingId === own.buildingId && !f.mezzanine && f.elevation > own.elevation)\n .sort((a, b) => a.elevation - b.elevation)[0];\n const gap = next ? next.elevation - own.elevation - p.height - SLAB : 0;\n if (gap > 0.01)\n this.surface(\n [p.ring],\n relative(p.floorId) + wallBase(p.floorId) + p.height,\n gap,\n finish.color,\n `plenum:${p.id}`,\n finish.material,\n );\n }\n // Every wall but the active floor's turns translucent in the stacked view — including the\n // storeys *below*, which used to stay solid. \"Cutaway\" has to actually cut something away: with\n // eight solid storeys of brick under the selected floor, a seventeen-level building showed one\n // plate inside a closed box, and the mode that promises all floors delivered none of them.\n //\n // Translucent was not nearly enough on its own. A wall is an extruded solid, so a sight line\n // crosses two of its faces, and the façade band of seventeen storeys stands between the camera\n // and every plate in the building — at the plates' own strength that measured out as a closed\n // brick box with a plate floating in it. The envelope gets the case budget instead: strong\n // enough to say where the building is and how it is banded, weak enough to see the floors.\n const wallGhost =\n stack && floorId !== null && !!p.floorId && p.floorId !== floorId && ghostStrength(p.floorId, true);\n if (barrier.kind === 'fence') {\n const [a, b] = barrierEnds(project, barrier).map(pt => this.xy(pt)) as [Point, Point];\n const geometry = fenceGeometry(\n a,\n b,\n p.ring.map(pt => this.xy(pt)),\n p.base + wallBase(p.floorId) + (stack ? 0 : relative(p.floorId)),\n p.height - p.base,\n barrier.thickness,\n );\n const positions = geometry.getAttribute('position');\n for (let i = 0; i < positions.count; i++) positions.setZ(i, this.present(positions.getZ(i)));\n geometry.computeVertexNormals();\n this.batch.add(\n geometry,\n wallGhost ? this.materials.ghost(finish.color, wallGhost) : this.materials.metal(finish.color),\n p.id,\n p.floorId === null,\n );\n continue;\n }\n this.surface(\n [p.ring],\n p.base + wallBase(p.floorId) + (stack ? 0 : relative(p.floorId)),\n p.height - p.base,\n finish.color,\n p.id,\n wallGhost ? undefined : finish.material,\n wallGhost,\n // Only where a wall actually starts at its floor. A piece that begins part-way up — the strip\n // over a door, say — has no junction to darken and would just get a dirty smear.\n p.base < 0.01,\n undefined,\n // A fence or a garden wall stands out of doors and is lit like the ground it stands on.\n p.floorId === null,\n // Assign plaster to the actual inner face. A separate skin competed with brick in the\n // depth buffer, especially at oblique angles and through the long hall.\n exterior.has(p.id) && !wallGhost && finish.material && !['plaster', 'tile'].includes(finish.material)\n ? this.interiorFace(project, p, floorId)\n : null,\n );\n }\n // Roofs cover their building in the site view and stacked view; cutaways expose the interior.\n if (!buried && (stack || floorId === null))\n for (const b of project.buildings)\n if (b.roof && (!stack || !activeF || b.id !== activeF.buildingId)) {\n const roof = makeRoof(b.roof, pt => this.xy(pt), b.id, this.materials);\n for (const leftover of this.batch.addObject(roof, b.id, true)) this.scene.add(leftover);\n }\n // Only the lower envelope is needed beneath a cutaway. Keep its authored façade and glazing;\n // interior partitions and duplicate ceiling plates were both hidden work and sources of seams.\n if (lower.size) this.envelope(project, lower, exterior, finishes);\n // The site view has to show the site. Until now only *authored* roof geometry drew here, so a\n // building whose roof was never modelled — which is most of them — disappeared completely and the\n // parcel read as an empty lot. Build the massing from the floor stack instead: the same façade\n // envelope used beneath a cutaway, capped at each building's roofline.\n if (!stack && floorId === null && !buried) {\n const aboveGround = new Map(project.floors.filter(fl => fl.elevation >= 0).map(fl => [fl.id, fl]));\n this.envelope(project, aboveGround, exterior, finishes);\n for (const b of project.buildings) {\n if (b.roof) continue; // an authored roof is better than a flat cap; leave it to makeRoof\n const top = project.floors\n .filter(fl => fl.buildingId === b.id && fl.elevation >= 0)\n .sort((x, y) => x.elevation - y.elevation)\n .at(-1);\n const rings = top && index.outlines.get(top.id)?.rings;\n if (top && rings) this.surface(rings, top.elevation + top.height, SLAB, '#747976', b.id, 'roof');\n }\n }\n // Excavate around the whole below-grade complex (all deck plates plus any ramps reaching the\n // surface), not just the active floor's plate — otherwise a garage or driveway that extends past\n // the tower footprint hangs in open air with no soil around it.\n //\n // Not while walking. The pit and the cage are the two things drawn at authored elevations that a\n // shift cannot rescue: the pit's cut face runs from the level in focus up to grade, and it is\n // grade the walk has moved away from — shifting the pit would stand the soil and its veil in the\n // room around the walker, and the cage's rings would cross him at ankle and head height. Both\n // are ways of looking AT a buried building from outside it; inside it they have nothing to say.\n if (buried && excavation && !walk) {\n const outline = index.outlines.get(activeF?.id ?? view.levels[0]?.id ?? '');\n const excavation = excavationRings(project, view.levels, stack ? Infinity : activeF?.elevation);\n const rings = excavation.length ? excavation : outline?.rings?.[0] ? [openRing(outline.rings[0])] : [];\n const split = shown(activeF?.elevation ?? 0);\n // The cut has to reach whatever the view actually draws below the floor in focus — the shelled\n // storey under it, and any ramp running down off the plate — or the ramp ends in mid-air and\n // the deck below stands inside bedrock. An arbitrary six metres did neither. The stacked view\n // already cuts to the bottom of the deepest level.\n const reach = Math.min(\n split,\n belowShell ? shown(belowShell.elevation) : split,\n ...(index.objects.get(floorId ?? '') ?? [])\n .filter(o => o.slope)\n .map(o => shown(Math.min(o.slope!.low, o.slope!.high))),\n );\n const bottom = stack ? shown(view.levels.reduce((z, f) => Math.min(z, f.elevation), 0)) - 2.5 : reach - 2.5;\n // Every below-grade slab leaves a stratum line on the cut face, so levels you are not standing\n // on still read in section.\n const strata = view.levels.filter(f => f.elevation < 0).map(f => shown(f.elevation));\n for (const local of rings) {\n // A little breathing room avoids coplanar soil and exterior walls.\n const ring = local.map(pt => this.xy(pt));\n const cx = ring.reduce((n, p) => n + p[0], 0) / ring.length,\n cy = ring.reduce((n, p) => n + p[1], 0) / ring.length;\n this.scene.add(\n undergroundPit(\n ring.map<Point>(([x, y]) => [cx + (x - cx) * 1.025, cy + (y - cy) * 1.025]),\n split,\n bottom,\n strata,\n ),\n );\n }\n }\n if (buried && activeF && excavation && !walk && (!stack || structureOverview)) {\n // A basement section needs reference decks up to grade. Tracing every roof storey over\n // a garage cutaway creates a tall wireframe unrelated to the inspected excavation.\n const above = view.levels\n .filter(f => f.elevation > activeF.elevation && (stack || f.elevation <= 0))\n .sort((a, b) => a.elevation - b.elevation);\n const stride = Math.max(1, Math.ceil((above.length - 1) / (MAX_CAGE_LEVELS - 1)));\n const samples = above.filter((_, i) => i % stride === 0 || i === above.length - 1);\n const rings: THREE.Vector3[][] = [];\n let columns: Point[] = [],\n widest = 0;\n for (const fl of samples) {\n const envelope = index.outlines.get(fl.id);\n if (!envelope) continue;\n const ring = openRing(envelope.rings![0]);\n rings.push(ring.map(pt => new THREE.Vector3(...this.xy(pt), shown(fl.elevation) + LIFT)));\n // The corners the cage stands on are the building's, so they come from its widest storey —\n // and never from a mezzanine, which is a gallery inside a storey and not the storey. Taken\n // from the first level above instead, Herkku caged a hundred-and-ten-metre building in the\n // four corners of the forty-metre -1A gallery standing inside it.\n const area = fl.mezzanine ? 0 : Math.abs(ringArea(ring));\n if (columns.length && area <= widest) continue;\n widest = area;\n const step = Math.max(1, Math.ceil(ring.length / 16));\n columns = ring.filter((_, i) => i % step === 0).map(pt => this.xy(pt));\n }\n const topFl = above.at(-1);\n this.cage.configure(\n rings,\n columns,\n shown(activeF.elevation) + LIFT,\n topFl ? shown(topFl.elevation + (stack ? topFl.height : 0)) : 0,\n evening,\n );\n this.cage.setBearing(this.map?.getBearing() ?? 0);\n this.scene.add(this.cage);\n }\n const fixtureBase = this.present((stack ? (activeF?.elevation ?? 0) : relative(floorId)) + LIFT + SLAB);\n if (walk && floorId) {\n const fixtures = [...(index.objects.get(floorId) ?? []), ...spanningObjects]\n .filter(o => o.kind === 'light' && o.light)\n .map(o => (o.floorId === floorId ? o : { ...o, height: o.height + relative(o.floorId) }));\n if (fixtures.length)\n this.fixtureLights = new FixtureLights(this.scene, fixtures, pt => this.xy(pt), fixtureBase, this.materials);\n }\n if (walk) {\n this.passenger = new Passenger(this.cabinFinishes().environment);\n this.scene.add(this.passenger);\n }\n this.batch.finish(this.scene);\n if (this.hasWater && floorId)\n applyPoolCaustics(this.scene, project, floorId, point => this.xy(point), fixtureBase, this.waterTime);\n // Sort the stack around the storey in focus. This is the thing that was actually hiding it.\n //\n // A batch merges everything sharing a material into one mesh at the scene origin, so three.js's\n // painter sort — which orders transparent objects by their origin's view depth — sees every mesh\n // at the same depth and falls through to the order they were created in. The active storey's\n // plate is transparent AND keeps depthWrite on (it has to occlude its own walls' hidden faces),\n // and it happened to be created before the ghost meshes. It therefore stamped the depth buffer\n // over its whole footprint before a single ghost was drawn, and every storey underneath was\n // depth-rejected: sixteen plans, built, blended with nothing, thrown away. \"All floors\" showed\n // one floor because the other sixteen were behind a depth test they could not pass.\n //\n // Nothing here can sort per fragment — a merged mesh is one draw — but a stack does not need it\n // to: the one plane everything is either above or below is the active plate. So the ghosts under\n // it draw first, the plate over them, and the ghosts above it last, which is back-to-front for\n // the only camera this view has. Ghosts write no depth, so ordering them occludes nothing; it\n // only decides what blends over what. A mesh that straddles the plate — a shaft running the\n // height of the building — goes under it, where it belongs for most of its length.\n if (stack && activeF)\n for (const mesh of this.scene.children)\n if (mesh instanceof THREE.Mesh) {\n const material = Array.isArray(mesh.material) ? mesh.material[0] : mesh.material;\n if (!material.transparent || material.depthWrite) continue;\n mesh.geometry.computeBoundingBox();\n mesh.renderOrder = (mesh.geometry.boundingBox?.min.z ?? 0) >= this.present(activeF.elevation) ? 1 : -1;\n }\n if (!buried) {\n // Receive shadows on the actual map without replacing its roads, labels or ground colour.\n const bounds = new THREE.Box3().setFromObject(this.scene);\n if (!bounds.isEmpty()) {\n const size = bounds.getSize(new THREE.Vector3()),\n center = bounds.getCenter(new THREE.Vector3());\n const reach = Math.max(24, size.z * 4);\n const shadowPlane = new THREE.Mesh(\n new THREE.PlaneGeometry(size.x + reach * 2, size.y + reach * 2),\n new THREE.ShadowMaterial({\n color: evening ? '#282637' : '#3d4950',\n // A weak sun casts a weak shadow. Held at a fixed darkness, a midwinter noon threw a\n // shadow as black as midsummer's across a city it was barely lighting.\n opacity: evening ? 0.34 : 0.1 + 0.2 * air.day,\n depthWrite: false,\n }),\n );\n // It is the ground, so it lies where the ground lies: at grade, which a walk has moved.\n shadowPlane.position.set(center.x, center.y, ground + 0.012);\n shadowPlane.layers.set(OUTSIDE);\n shadowPlane.receiveShadow = true;\n shadowPlane.raycast = () => {};\n this.scene.add(shadowPlane);\n }\n }\n this.fitShadowCamera();\n this.scene.add(this.highlight);\n this.refreshHighlight();\n this.pickables = [];\n this.scene.traverse(object => {\n if (!(object instanceof THREE.Mesh)) return;\n const materials = Array.isArray(object.material) ? object.material : [object.material];\n if (!materials.some(m => m.visible && (!m.transparent || m.depthWrite))) return;\n if (object.userData.entityId || object.userData.entityIds || object.userData.spans) this.pickables.push(object);\n });\n this.buildRoute(); // disposeScene swept the previous route group's resources with the scene\n this.refreshShadows();\n this.map?.triggerRepaint();\n }\n /** Show/replace the 3D route. When only the active step changed, restyle materials in place;\n * otherwise rebuild the route group. Route state is retained across update() rebuilds — every\n * rebuild re-runs buildRoute with FRESH materials, because disposeScene disposes all mesh\n * materials and a cached material would die silently on the next floor switch. */\n setRoute(route: Route | null, activeStep: number | null = null) {\n if (route === this.route && activeStep === this.routeStep && (this.routeGroup !== null || !route)) return;\n const restyleOnly = route !== null && route === this.route && this.routeGroup !== null;\n this.route = route;\n this.routeStep = activeStep;\n if (restyleOnly) this.restyleRoute();\n else this.buildRoute();\n this.map?.triggerRepaint();\n }\n /** The track's texture already carries the green and the white kerb, so the material's own colour\n * stays white and only emphasis separates the step being walked from the rest of the path. A\n * route is one route: dimming the other steps says \"later\", where recolouring them would say\n * \"different\". */\n private routeStyle(step: number) {\n return { opacity: this.routeStep === null || step === this.routeStep ? 1 : 0.5 };\n }\n private restyleRoute() {\n this.routeGroup?.traverse(o => {\n if (o instanceof THREE.Mesh)\n (o.material as THREE.MeshBasicMaterial).opacity = this.routeStyle(o.userData.step as number).opacity;\n });\n }\n private buildRoute() {\n this.clipBoundsDirty = true;\n // update() clears every rig before it rebuilds, but setRoute() rebuilds on its own — without\n // this, changing destination leaves the old rig scrolling a texture on a disposed group.\n this.rigs = this.rigs.filter(r => r.id !== ROUTE_RIG);\n this.rigState.delete(ROUTE_RIG);\n if (this.routeGroup) {\n this.routeGroup.removeFromParent();\n this.routeGroup.traverse(o => {\n if (o instanceof THREE.Mesh) {\n o.geometry.dispose();\n (o.material as THREE.Material).dispose();\n }\n });\n this.routeTile?.dispose();\n this.routeTile = null;\n this.routeGroup = null;\n }\n const route = this.route,\n project = this.project;\n if (!route || !project) return;\n const floors = floorIndex(project).floors,\n activeF = floors.get(this.activeFloor ?? '');\n // Same visibility predicates as the plates: buried hides outdoor legs and other buildings;\n // the cutaway shows only the active floor (+ outdoor); the stack shows every floor.\n const visible = (fid: string | null) => {\n if (!this.buried && fid && (floors.get(fid)?.elevation ?? 0) < 0) return false;\n if (this.buried && (fid === null || (activeF && floors.get(fid ?? '')?.buildingId !== activeF.buildingId)))\n return false;\n if (!this.stack && fid !== null && fid !== this.activeFloor) return false;\n return true;\n };\n const zOf = (fid: string | null) =>\n fid === null\n ? // Out of doors is grade, and a walk has moved grade — see sceneGround.\n this.ground + GROUND + 0.05\n : this.present((this.stack ? (floors.get(fid)?.elevation ?? 0) : this.rebase) + LIFT + SLAB + ROOM + 0.07);\n const group = new THREE.Group();\n const steps = legStepIndices(route);\n // One texture for the whole route, tiled along it by the ribbon's metre-counting UVs. Built per\n // build rather than cached: disposeScene sweeps the group with the scene, and a shared texture\n // that outlived one of those would be disposed under the next route.\n const tile = new THREE.DataTexture(\n new Uint8Array(routeTrackImage(this.mapStyle.routeActive ?? ROUTE_COLOR).data.buffer),\n TRACK_PIXELS[0],\n TRACK_PIXELS[1],\n THREE.RGBAFormat,\n );\n tile.wrapS = THREE.RepeatWrapping;\n tile.colorSpace = THREE.SRGBColorSpace;\n // Mipmapped and anisotropic: the track runs away to the horizon at eye level, and the far half of\n // it is all grazing angle — which is where a sharp tile stops being sharp and starts sparkling.\n tile.generateMipmaps = true;\n tile.minFilter = THREE.LinearMipmapLinearFilter;\n tile.magFilter = THREE.LinearFilter;\n tile.anisotropy = Math.min(8, this.renderer?.capabilities.getMaxAnisotropy() ?? 1);\n tile.needsUpdate = true;\n const mesh = (geometry: THREE.BufferGeometry, step: number, tracked = true) => {\n const m = new THREE.Mesh(\n geometry,\n new THREE.MeshBasicMaterial({\n color: tracked ? '#ffffff' : (this.mapStyle.routeActive ?? ROUTE_COLOR),\n map: tracked ? tile : null,\n opacity: this.routeStyle(step).opacity,\n transparent: true,\n depthWrite: false,\n side: THREE.DoubleSide,\n }),\n );\n m.renderOrder = 10;\n m.raycast = () => {};\n m.userData.step = step;\n group.add(m);\n };\n let run: { step: number; fid: string | null; points: Point[] } | null = null;\n const flush = () => {\n if (run && run.points.length > 1 && visible(run.fid)) {\n // 1.4 m of track. At 0.44 m the route was a stripe drawn on the floor; at eye level in walk\n // mode a stripe is something you stand beside, and a track is something you stand on.\n const g = this.ribbonGeometry(run.points, zOf(run.fid), 0.7);\n if (g) mesh(g, run.step);\n }\n run = null;\n };\n for (let i = 0; i < route.legs.length; i++) {\n const leg = route.legs[i],\n step = steps[i];\n if (leg.edge.kind === 'stairs' || leg.edge.kind === 'elevator') {\n flush();\n const [x, y] = this.xy(leg.from.position);\n if (this.stack) {\n // subtle shaft connector between the presented floor elevations\n if (!visible(leg.from.floorId) && !visible(leg.to.floorId)) continue;\n const z1 = zOf(leg.from.floorId),\n z2 = zOf(leg.to.floorId);\n const g = new THREE.CylinderGeometry(0.14, 0.14, Math.abs(z2 - z1) || 0.1, 10);\n g.rotateX(Math.PI / 2);\n g.translate(x, y, (z1 + z2) / 2);\n mesh(g, step, false);\n } else if (leg.from.floorId === this.activeFloor || leg.to.floorId === this.activeFloor) {\n // shaft marker disc on the visible floor\n const g = new THREE.CylinderGeometry(0.8, 0.8, 0.05, 28);\n g.rotateX(Math.PI / 2);\n g.translate(x, y, zOf(this.activeFloor) + 0.02);\n mesh(g, step, false);\n }\n continue;\n }\n const fid = leg.from.floorId === leg.to.floorId ? leg.from.floorId : (leg.from.floorId ?? leg.to.floorId);\n if (!run || run.step !== step || run.fid !== fid) {\n flush();\n run = { step, fid, points: [leg.from.position] };\n }\n run.points.push(leg.to.position);\n }\n flush();\n if (!group.children.length) {\n tile.dispose();\n return;\n }\n this.routeGroup = group;\n this.routeTile = tile;\n // Scrolling the tile IS the animation: one tile per TRACK_TILE metres, so a full cycle is one\n // arrow's worth of travel and the band never appears to jump. Negative, because u grows towards\n // the destination and the arrows have to march that way rather than back down the corridor.\n this.rig(\n ROUTE_RIG,\n group,\n 1,\n 0.55, // cycles a second: one arrow-length every ~1.8 s, a walking pace rather than a barber's pole\n (_, v) => {\n tile.offset.x = -v;\n },\n true,\n );\n this.scene.add(group); // raycast is a no-op and userData carries no entityId, so pickables ignore the ribbon\n }\n /** Flat mitred triangle-strip ribbon at a constant z, in scene metres. */\n private ribbonGeometry(points: Point[], z: number, half: number): THREE.BufferGeometry | null {\n const pts: Point[] = [];\n for (const p of points) {\n const q = this.xy(p);\n if (!pts.length || Math.hypot(q[0] - pts[pts.length - 1][0], q[1] - pts[pts.length - 1][1]) > 0.01) pts.push(q);\n }\n if (pts.length < 2) return null;\n const positions: number[] = [],\n uvs: number[] = [],\n indices: number[] = [];\n // u counts metres walked, not vertices: the arrows have to be evenly spaced along the path, and\n // a long straight run and a tight corner are the same number of vertices and very different\n // distances. v crosses the ribbon, so the texture's own top and bottom edges are the track's.\n let run = 0;\n for (let i = 0; i < pts.length; i++) {\n if (i) run += Math.hypot(pts[i][0] - pts[i - 1][0], pts[i][1] - pts[i - 1][1]);\n const prev = pts[Math.max(0, i - 1)],\n next = pts[Math.min(pts.length - 1, i + 1)];\n const dx = next[0] - prev[0],\n dy = next[1] - prev[1],\n len = Math.hypot(dx, dy) || 1;\n let nx = -dy / len,\n ny = dx / len,\n w = half;\n if (i > 0 && i < pts.length - 1) {\n const d1x = pts[i][0] - pts[i - 1][0],\n d1y = pts[i][1] - pts[i - 1][1],\n l1 = Math.hypot(d1x, d1y) || 1;\n const d2x = pts[i + 1][0] - pts[i][0],\n d2y = pts[i + 1][1] - pts[i][1],\n l2 = Math.hypot(d2x, d2y) || 1;\n const mx = -(d1y / l1 + d2y / l2),\n my = d1x / l1 + d2x / l2,\n ml = Math.hypot(mx, my);\n if (ml > 0.001) {\n nx = mx / ml;\n ny = my / ml;\n const dot = nx * (-d1y / l1) + ny * (d1x / l1);\n w = half / Math.max(0.4, Math.abs(dot));\n }\n }\n positions.push(pts[i][0] + nx * w, pts[i][1] + ny * w, z, pts[i][0] - nx * w, pts[i][1] - ny * w, z);\n uvs.push(run / TRACK_TILE, 0, run / TRACK_TILE, 1);\n if (i) {\n const b = i * 2;\n indices.push(b - 2, b - 1, b, b - 1, b + 1, b);\n }\n }\n const g = new THREE.BufferGeometry();\n g.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));\n g.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));\n g.setIndex(indices);\n return g;\n }\n // Grows the building out of the map when entering 3D so the mode switch reads as one motion.\n animateIn() {\n this.growth = 0;\n this.growthStart = performance.now();\n this.map?.triggerRepaint();\n }\n private refreshHighlight() {\n for (const child of [...this.highlight.children]) {\n const line = child as THREE.LineSegments;\n line.geometry.dispose();\n (line.material as THREE.Material).dispose();\n }\n this.highlight.clear();\n for (const [id, color] of [\n [this.hovered, this.mapStyle.hover ?? '#8d85dc'],\n [this.selected, this.mapStyle.selection ?? '#6355d4'],\n ] as const)\n if (id) {\n const line = this.batch.outline(id, color);\n if (line) this.highlight.add(line);\n }\n this.map?.triggerRepaint();\n }\n setHover(id: string | null) {\n if (id === this.hovered) return;\n this.hovered = id;\n this.refreshHighlight();\n }\n get diagnostics() {\n return {\n revision: this.revision,\n drawCalls: this.renderer?.info.render.calls ?? 0,\n geometries: this.renderer?.info.memory.geometries ?? 0,\n textures: this.renderer?.info.memory.textures ?? 0,\n animatedWater: this.hasWater,\n };\n }\n render(gl: WebGLRenderingContext | WebGL2RenderingContext, args: CustomRenderMethodInput) {\n if (!this.renderer) return;\n // The model draws over the map, and the only way to say so is to throw away the depth the map\n // has written before us.\n //\n // MapLibre gives every style layer a slice of the depth buffer by its position in the list and\n // draws its opaque fills into it; a custom layer is handed the buffer as it stands and its own\n // geometry is depth-tested against those slices. Our heights are metres above the ground, not\n // slices, so which of the two wins is a matter of camera pitch and zoom rather than of layer\n // order — and it showed: a floor plate would lose to a land-use polygon and vanish, leaving a\n // slab of flat basemap colour inside the building while the walls, whose faces happened to land\n // on the near side of the contest, stayed put. Clearing the depth buffer settles it. Everything\n // the map has drawn is behind us by construction, which is what being the last layer means.\n gl.clear(gl.DEPTH_BUFFER_BIT);\n const now = performance.now();\n if (this.hasWater) {\n this.waterTime.value = now / 1000;\n this.paintSoon();\n }\n // Capped so a backgrounded tab does not resume by teleporting every car a hundred metres.\n const elapsed = Math.min(0.1, this.lastFrame ? (now - this.lastFrame) / 1000 : 0);\n this.lastFrame = now;\n if (this.rigs.length && this.animate(elapsed)) {\n if (this.shadowsMoved) this.refreshShadows();\n // A moving part asks for the next frame, and asking every frame pins a scene of a thousand\n // draw calls at the display's refresh rate for as long as one escalator is running. Measured,\n // the rig itself costs nothing — the cost is the repaint it demands. A step band travels half\n // a metre a second, so it reads as continuous well under 60 Hz; the settling rigs (a lift car,\n // a door leaf) are short and keep the full rate. Repainting on a timer rather than immediately\n // is what hands the idle frames back.\n if (this.shadowsMoved) this.map?.triggerRepaint();\n else this.paintSoon();\n }\n if (this.growth < 1) {\n this.growth = Math.min(1, (performance.now() - this.growthStart) / 550);\n this.scene.scale.z = 0.03 + 0.97 * (1 - (1 - this.growth) ** 3);\n this.refreshShadows();\n this.map?.triggerRepaint();\n } else this.scene.scale.z = 1;\n // defaultProjectionData.mainMatrix passes through a Float32 projection path; at city zoom its\n // rounding is metres, which made the whole scene drift off the basemap at some camera poses.\n // The transform's mercatorMatrix is the same mercator→clip matrix at full float64 precision.\n const precise = (this.map as unknown as { transform?: { mercatorMatrix?: ArrayLike<number> } })?.transform\n ?.mercatorMatrix;\n this.worldToClip\n .fromArray((precise?.length === 16 ? precise : args.defaultProjectionData.mainMatrix) as number[])\n .multiply(this.transform);\n const nearPlane = this.walking ? walkNearPlane(this.worldToClip, args.nearZ, args.farZ) : args.nearZ;\n if (this.buried) {\n if (this.clipBoundsDirty) {\n this.scene.updateMatrixWorld(true);\n // Cache in scene metres, removing the current entrance-animation scale. Cage bounds\n // cover every bearing, so neither panning nor rotation needs another geometry scan.\n this.clipBounds\n .setFromObject(this.scene)\n .applyMatrix4(new THREE.Matrix4().copy(this.scene.matrixWorld).invert());\n this.clipBoundsDirty = false;\n }\n // MapLibre fits its far plane to the ground; a basement can cross that plane and lose\n // a straight slice of its floor as the camera pans. Fit the custom scene independently.\n includeSceneDepth(this.worldToClip, this.clipBounds, this.scene.scale.z, nearPlane, args.farZ);\n }\n this.clipToWorld.copy(this.worldToClip).invert();\n syncLightingCamera(this.camera, this.worldToClip, this.clipToWorld);\n if (this.passenger) {\n const forward = new THREE.Vector3(0, 0, 0).applyMatrix4(this.clipToWorld).sub(this.camera.position).normalize();\n if (this.passenger.update(this.camera.position, forward, now / 1000, elapsed)) this.paintSoon();\n this.passenger.updateMatrixWorld(true);\n }\n if (this.fixtureLights) {\n const { shadowsChanged, animate } = this.fixtureLights.update(this.camera.position, now / 1000);\n if (shadowsChanged) this.renderer.shadowMap.needsUpdate = true;\n if (animate) this.paintSoon();\n }\n // Three caches the viewport from the canvas size at construction; after the map container\n // resizes (inspector opening, fullscreen) it would keep drawing into the old rectangle,\n // shearing the scene off the basemap. Re-sync to the shared canvas every frame (pixelRatio 1).\n const canvas = this.map?.getCanvas();\n if (canvas) this.renderer.setViewport(0, 0, canvas.width, canvas.height);\n const size = canvas ? `${canvas.clientWidth}:${canvas.clientHeight}` : '';\n if (\n !this.previousProjection.equals(this.worldToClip) ||\n this.previousScale !== this.scene.scale.z ||\n this.previousSize !== size\n ) {\n this.markerCache.clear();\n this.previousProjection.copy(this.worldToClip);\n this.previousScale = this.scene.scale.z;\n this.previousSize = size;\n }\n this.cage.setBearing(this.map?.getBearing() ?? 0);\n this.renderer.resetState();\n if (this.buried) {\n // Underground inspection composites over the map. Keep its colour, but discard the\n // ground/vector depth left in our shared context; scene objects still occlude each other.\n this.renderer.state.buffers.depth.setMask(true);\n this.renderer.state.buffers.depth.setClear(1);\n this.renderer.clearDepth();\n }\n // Refraction is blurred by the water's small ripples already. Half linear resolution cuts\n // the transmission target, its MSAA resolve and mip chain to a quarter of the pixels while\n // preserving full-resolution reflections, pool geometry and the final water surface.\n this.renderer.transmissionResolutionScale = this.hasWater ? 0.5 : 1;\n this.renderer.render(this.scene, this.camera);\n this.renderer.resetState();\n }\n /** Where a point on a floor's walking surface lands on screen — the avatar marker, which is not an\n * object and has no occlusion to test. `visible` is the frustum only. */\n projectPoint(pt: Point, floorId: string | null): { x: number; y: number; visible: boolean } | null {\n if (!this.project || !this.map) return null;\n const z =\n (this.stack ? (floorIndex(this.project).floors.get(floorId ?? '')?.elevation ?? 0) : floorId ? this.rebase : 0) +\n wallBase(floorId);\n const p = new THREE.Vector3(...this.xy(pt), this.present(z) * this.scene.scale.z).applyMatrix4(this.worldToClip);\n return {\n x: ((p.x + 1) / 2) * this.map.getCanvas().clientWidth,\n y: ((1 - p.y) / 2) * this.map.getCanvas().clientHeight,\n visible: Math.abs(p.x) <= 1.05 && Math.abs(p.y) <= 1.05 && p.z < 1 && p.z > -1,\n };\n }\n\n projectObject(o: SiteObject): { x: number; y: number; visible: boolean } | null {\n if (!this.project || !this.map) return null;\n const cached = this.markerCache.get(o.id);\n if (cached) return cached;\n const xy = this.xy(objectPosition(this.project, o));\n const z =\n (this.stack\n ? (floorIndex(this.project).floors.get(o.floorId ?? '')?.elevation ?? 0)\n : o.floorId\n ? this.rebase\n : 0) +\n wallBase(o.floorId) +\n (o.kind === 'camera' ? o.height : 0.5);\n const target = new THREE.Vector3(...xy, this.present(z) * this.scene.scale.z);\n const p = target.clone().applyMatrix4(this.worldToClip);\n let visible =\n Math.abs(p.x) <= 1.05 &&\n Math.abs(p.y) <= 1.05 &&\n p.z < 1 &&\n p.z > -1 &&\n (!this.walking || this.camera.position.distanceTo(target) <= 12) &&\n (!this.buried || o.floorId !== null) &&\n (!this.stack || o.floorId === null || o.floorId === this.activeFloor);\n if (visible && (this.stack || this.walking)) {\n // Occlusion is by far the most expensive thing per marker — a ray against every pickable mesh.\n // While the camera is in motion, reuse the last verdict: markers shift by a few pixels a frame\n // and re-deriving this for hundreds of them was costing more than the rest of the frame put\n // together. It refreshes as soon as the camera stops.\n const settled = !this.map.isMoving();\n const cachedOcclusion = this.occlusionCache.get(o.id);\n // At eye level, a single step can put a wall in front of a marker. Nearby markers are few,\n // so test them on each new camera frame instead of carrying a stale visibility verdict.\n if (!this.walking && !settled && cachedOcclusion !== undefined) visible = cachedOcclusion;\n else {\n const near = new THREE.Vector3(p.x, p.y, -1).applyMatrix4(this.clipToWorld);\n const length = near.distanceTo(target);\n const clearance = (this.present(z) - this.present(z - 0.25)) * this.scene.scale.z;\n const ray = new THREE.Raycaster(near, target.clone().sub(near).normalize(), 0, Math.max(0, length - clearance));\n ray.layers.enableAll();\n visible = !ray\n .intersectObjects(this.pickables, false)\n .some(hit => hit.object instanceof THREE.Mesh && hitEntity(hit) !== o.id);\n this.occlusionCache.set(o.id, visible);\n }\n }\n const result = {\n x: ((p.x + 1) / 2) * this.map.getCanvas().clientWidth,\n y: ((1 - p.y) / 2) * this.map.getCanvas().clientHeight,\n visible,\n };\n this.markerCache.set(o.id, result);\n return result;\n }\n pick(point: { x: number; y: number }): string | null {\n if (!this.map) return null;\n const x = (point.x / this.map.getCanvas().clientWidth) * 2 - 1,\n y = 1 - (point.y / this.map.getCanvas().clientHeight) * 2;\n const near = new THREE.Vector3(x, y, -1).applyMatrix4(this.clipToWorld),\n far = new THREE.Vector3(x, y, 1).applyMatrix4(this.clipToWorld);\n const raycaster = new THREE.Raycaster(near, far.sub(near).normalize());\n raycaster.layers.enableAll();\n return raycaster.intersectObjects(this.pickables, false).map(hitEntity).find(Boolean) ?? null;\n }\n private disposeScene() {\n this.hasWater = false;\n this.passenger = undefined;\n this.fixtureLights = undefined;\n this.cage.dispose();\n this.markerCache.clear();\n this.occlusionCache.clear();\n this.pickables = [];\n this.clipBoundsDirty = true;\n const geometries = new Set<THREE.BufferGeometry>(),\n materials = new Set<THREE.Material>();\n this.scene.traverse(o => {\n if (o instanceof CabinMirror) o.getRenderTarget().dispose();\n if (o instanceof THREE.Mesh || o instanceof THREE.LineSegments) {\n geometries.add(o.geometry);\n (Array.isArray(o.material) ? o.material : [o.material]).forEach(m => {\n if (!m.userData.shared) materials.add(m);\n if (m.userData.ownedMap) (m as THREE.MeshBasicMaterial).map?.dispose();\n });\n // InstancedMesh (roof tiles) also holds instanceMatrix/instanceColor GPU buffers that only\n // its own dispose() frees — geometry/material disposal leaves them orphaned on each rebuild.\n if (o instanceof THREE.InstancedMesh) o.dispose();\n }\n if (o instanceof THREE.Light && 'shadow' in o) (o as THREE.DirectionalLight).shadow?.dispose();\n });\n geometries.forEach(g => g.dispose());\n materials.forEach(m => m.dispose());\n this.scene.clear();\n this.highlight.clear();\n this.batch.clear();\n // The track texture is not a shared material and nothing above sweeps a map off one, so it has to\n // be let go here too — a route rebuilt on every floor switch would otherwise leak a texture a time.\n this.routeTile?.dispose();\n this.routeTile = null;\n this.routeGroup = null;\n }\n onRemove() {\n clearTimeout(this.loopTimer);\n this.loopTimer = undefined;\n this.disposeScene();\n this.materials.dispose();\n this.cabinMaterials?.dispose();\n this.cabinMaterials = undefined;\n this.envCache.forEach(target => target.dispose());\n this.envCache.clear();\n // dispose() frees Three's programs/listeners; it does not lose the shared context. Never call\n // forceContextLoss(). Reset the GL bindings before handing the context back to MapLibre.\n this.renderer?.resetState();\n this.renderer?.dispose();\n this.renderer = undefined;\n this.map = undefined;\n }\n}\n"],"names":["COPLANAR_STEP","nestingLift","area","AO_RISE","AO_FLOOR","ROOM","GROUND","HEAD_CLEAR","FOCUS_SEEN","UNDER_SEEN","CASE_ALPHA","SHAFT_GHOST","sceneGround","stack","rebase","activeElevation","sceneElevation","view","walk","z","_a","walkSoffit","height","LIFT","SLAB","EYE","walkCeiling","project","floorId","active","f","floor","a","b","snapRing","ring","p","shellPlate","primary","voidOptions","index","floorIndex","zones","o","input","r","closeRing","floorOutline","merged","polygonClipping","voids","shaftVoids","rampVoids","v","largest","LOOP_FRAME","ROUTE_RIG","wallBase","boxesMeet","span","axis","lo","hi","alo","ahi","blo","bhi","STEP_GOING","STEP_RISE","PLATE_LIP","escalatorSteps","rise","incline","count","going","face","_","i","SceneLayer","__publicField","THREE","camera","REFLECTION_BODY","MaterialLibrary","SurfaceBatch","FIXED","UndergroundCage","CabinMaterials","_b","style","map","gl","evening","key","cached","canvas","c","g","x","y","radius","cloud","equirect","pmrem","target","sun","air","ambient","_c","_d","_e","beam","sunlight","_f","light","bounds","centre","size","reach","direction","shadowBounds","corner","m","MercatorCoordinate","toLngLat","result","pieces","color","shadows","tread","geometries","rings","base","shape","geometry","metricUVs","positions","center","uv","normal","ax","ay","mergeGeometries","mesh","group","id","speed","apply","loop","seconds","moving","at","next","step","material","ghost","ao","override","outdoor","interiorFace","horizontalAxis","shades","above","shade","surfaceMaterial","splitWallFace","plaster","slope","lift","thickness","rampSections","bx","by","dx","dy","len2","t","levels","exterior","finishes","fl","wallPieces","finish","position","objectPosition","rotation","objectRotation","barrier","rim","depth","frame","glass","side","offset","width","bottom","h","d","delta","rotate","rectangle","sign","panes","objectRings","COLORS","model","makeDoor","along","addPoint","angle","place","leftover","child","status","setOpen","_g","value","piece","outline","openRing","wall","start","end","barrierEnds","length","distance","ux","uy","len","nx","ny","mid","probe","pointInRing","through","wells","cabinFloorVoids","hits","own","all","flights","stairModel","near","up","down","flightsAt","drawn","flight","shared","flightRun","run","head","half","pad","topT","footT","band","riser","comb","foot","body","reading","way","running","across","steps","spare","dz","rail","stairGeometry","landing","lane","servedFloors","rel","lowest","top","cut","shell","from","to","turn","gap","elevatorDoorWidth","spin","strip","low","high","carFloor","carAt","carHeight","cabin","cabinDimensions","floorRing","detailed","car","makeElevatorCabin","elevatorWalls","carSpeed","arrived","doorsOpen","out","local","origin","door","makeCabinDoor","spiralGeometry","selected","statuses","excavation","liftSignature","settled","poolLighting","exteriorWalls","floors","buildings","barriers","preset","EXTERIOR_PRESETS","undergroundView","activeF","buried","ground","structureOverview","outlineOnly","shellBelow","sky","room","fill","belowGrade","fid","levelsBelowActive","share","transmit","ghostStrength","kase","under","over","lower","belowShell","spanningObjects","tallSpaceContext","contextFloors","atrium","walkVoidContext","connections","walkConnectionContext","connectionIds","structuralLevels","drawnLevels","punchWells","relative","floorAxes","floorAxis","mainAxis","shown","visibleObjects","rampJoins","surfaces","isVertical","reaches","spanning","planPlate","indoorFinish","activeLevel","ghosted","ghostFill","lidsOverBelow","_h","makePool","pt","makeWaterSlide","fixture","makeFixture","axisLength","edge","indoor","elevated","objectArea","plates","plate","_i","pg","ceilingFloor","soffit","lit","_j","tiled","_k","tallRoofs","openCeiling","_l","hall","roof","_m","overhead","wellHead","well","level","allPieces","_n","wallGhost","fenceGeometry","makeRoof","aboveGround","_o","_p","excavationRings","_q","split","strata","cx","n","cy","undergroundPit","stride","MAX_CAGE_LEVELS","samples","columns","widest","envelope","ringArea","topFl","_r","fixtureBase","fixtures","FixtureLights","Passenger","applyPoolCaustics","point","_s","shadowPlane","OUTSIDE","object","_t","route","activeStep","restyleOnly","visible","zOf","legStepIndices","tile","routeTrackImage","ROUTE_COLOR","TRACK_PIXELS","tracked","flush","leg","z1","z2","points","pts","q","uvs","indices","prev","w","d1x","d1y","l1","d2x","d2y","l2","mx","my","ml","dot","TRACK_TILE","line","args","now","elapsed","precise","nearPlane","walkNearPlane","includeSceneDepth","syncLightingCamera","forward","shadowsChanged","animate","xy","cachedOcclusion","clearance","ray","hit","hitEntity","far","raycaster","materials","CabinMirror"],"mappings":"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"}
|