@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.
Files changed (264) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -2
  3. package/dist/adapters/basemap.js +11 -0
  4. package/dist/adapters/basemap.js.map +1 -0
  5. package/dist/adapters/persistence.js +121 -0
  6. package/dist/adapters/persistence.js.map +1 -0
  7. package/dist/adapters/status.js +18 -0
  8. package/dist/adapters/status.js.map +1 -0
  9. package/dist/components/ElevatorPanel.js +120 -0
  10. package/dist/components/ElevatorPanel.js.map +1 -0
  11. package/dist/components/Icons.js +57 -0
  12. package/dist/components/Icons.js.map +1 -0
  13. package/dist/components/Inspector.js +1184 -0
  14. package/dist/components/Inspector.js.map +1 -0
  15. package/dist/components/NavigatePanel.js +301 -0
  16. package/dist/components/NavigatePanel.js.map +1 -0
  17. package/dist/components/NavigationGraph.js +234 -0
  18. package/dist/components/NavigationGraph.js.map +1 -0
  19. package/dist/components/StructureExplorer.js +510 -0
  20. package/dist/components/StructureExplorer.js.map +1 -0
  21. package/dist/components/StructureView.js +286 -0
  22. package/dist/components/StructureView.js.map +1 -0
  23. package/dist/components/controls.js +170 -0
  24. package/dist/components/controls.js.map +1 -0
  25. package/dist/components/graphLayout.js +27 -0
  26. package/dist/components/graphLayout.js.map +1 -0
  27. package/dist/host.js +169 -0
  28. package/dist/host.js.map +1 -0
  29. package/dist/i18n.js +88 -0
  30. package/dist/i18n.js.map +1 -0
  31. package/dist/index.js +171 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/map/CabinMaterials.js +81 -0
  34. package/dist/map/CabinMaterials.js.map +1 -0
  35. package/dist/map/CabinMirror.js +43 -0
  36. package/dist/map/CabinMirror.js.map +1 -0
  37. package/dist/map/Doors.js +80 -0
  38. package/dist/map/Doors.js.map +1 -0
  39. package/dist/map/ElevatorCabin.js +93 -0
  40. package/dist/map/ElevatorCabin.js.map +1 -0
  41. package/dist/map/FixtureLights.js +117 -0
  42. package/dist/map/FixtureLights.js.map +1 -0
  43. package/dist/map/MapCanvas.js +2161 -0
  44. package/dist/map/MapCanvas.js.map +1 -0
  45. package/dist/map/Passenger.js +69 -0
  46. package/dist/map/Passenger.js.map +1 -0
  47. package/dist/map/SceneLayer.js +1534 -0
  48. package/dist/map/SceneLayer.js.map +1 -0
  49. package/dist/map/UndergroundContext.js +153 -0
  50. package/dist/map/UndergroundContext.js.map +1 -0
  51. package/dist/map/ambience.js +194 -0
  52. package/dist/map/ambience.js.map +1 -0
  53. package/dist/map/architecture.js +305 -0
  54. package/dist/map/architecture.js.map +1 -0
  55. package/dist/map/bathMusic.js +92 -0
  56. package/dist/map/bathMusic.js.map +1 -0
  57. package/dist/map/cameraAim.js +33 -0
  58. package/dist/map/cameraAim.js.map +1 -0
  59. package/dist/map/elevators.js +56 -0
  60. package/dist/map/elevators.js.map +1 -0
  61. package/dist/map/excavation.js +52 -0
  62. package/dist/map/excavation.js.map +1 -0
  63. package/dist/map/exteriors.js +25 -0
  64. package/dist/map/exteriors.js.map +1 -0
  65. package/dist/map/features.js +218 -0
  66. package/dist/map/features.js.map +1 -0
  67. package/dist/map/fences.js +29 -0
  68. package/dist/map/fences.js.map +1 -0
  69. package/dist/map/journey.js +112 -0
  70. package/dist/map/journey.js.map +1 -0
  71. package/dist/map/levels.js +6 -0
  72. package/dist/map/levels.js.map +1 -0
  73. package/dist/map/lighting.js +142 -0
  74. package/dist/map/lighting.js.map +1 -0
  75. package/dist/map/loadBasemap.js +26 -0
  76. package/dist/map/loadBasemap.js.map +1 -0
  77. package/dist/map/materials.js +183 -0
  78. package/dist/map/materials.js.map +1 -0
  79. package/dist/map/poolLighting.js +39 -0
  80. package/dist/map/poolLighting.js.map +1 -0
  81. package/dist/map/projection.js +24 -0
  82. package/dist/map/projection.js.map +1 -0
  83. package/dist/map/rampGeometry.js +38 -0
  84. package/dist/map/rampGeometry.js.map +1 -0
  85. package/dist/map/route.js +107 -0
  86. package/dist/map/route.js.map +1 -0
  87. package/dist/map/stairSurfaces.js +115 -0
  88. package/dist/map/stairSurfaces.js.map +1 -0
  89. package/dist/map/surfaces.js +136 -0
  90. package/dist/map/surfaces.js.map +1 -0
  91. package/dist/map/textures.js +95 -0
  92. package/dist/map/textures.js.map +1 -0
  93. package/dist/map/underground.js +34 -0
  94. package/dist/map/underground.js.map +1 -0
  95. package/dist/map/walk.js +433 -0
  96. package/dist/map/walk.js.map +1 -0
  97. package/dist/map/walkContext.js +46 -0
  98. package/dist/map/walkContext.js.map +1 -0
  99. package/dist/map/walkDimensions.js +7 -0
  100. package/dist/map/walkDimensions.js.map +1 -0
  101. package/dist/map/walkJourney.js +85 -0
  102. package/dist/map/walkJourney.js.map +1 -0
  103. package/dist/map/walkSurfaces.js +106 -0
  104. package/dist/map/walkSurfaces.js.map +1 -0
  105. package/dist/map/wallJoins.js +70 -0
  106. package/dist/map/wallJoins.js.map +1 -0
  107. package/dist/map/water.js +274 -0
  108. package/dist/map/water.js.map +1 -0
  109. package/dist/model/authoring.js +80 -0
  110. package/dist/model/authoring.js.map +1 -0
  111. package/dist/model/boundaries.js +548 -0
  112. package/dist/model/boundaries.js.map +1 -0
  113. package/dist/model/coverage.js +30 -0
  114. package/dist/model/coverage.js.map +1 -0
  115. package/dist/model/document.js +52 -0
  116. package/dist/model/document.js.map +1 -0
  117. package/dist/model/doors.js +47 -0
  118. package/dist/model/doors.js.map +1 -0
  119. package/dist/model/factory.js +56 -0
  120. package/dist/model/factory.js.map +1 -0
  121. package/dist/model/geometry.js +394 -0
  122. package/dist/model/geometry.js.map +1 -0
  123. package/dist/model/inference.js +182 -0
  124. package/dist/model/inference.js.map +1 -0
  125. package/dist/model/materials.js +11 -0
  126. package/dist/model/materials.js.map +1 -0
  127. package/dist/model/mutations.js +157 -0
  128. package/dist/model/mutations.js.map +1 -0
  129. package/dist/model/navigation.js +275 -0
  130. package/dist/model/navigation.js.map +1 -0
  131. package/dist/model/ontology.js +109 -0
  132. package/dist/model/ontology.js.map +1 -0
  133. package/dist/model/passages.js +5 -0
  134. package/dist/model/passages.js.map +1 -0
  135. package/dist/model/portals.js +42 -0
  136. package/dist/model/portals.js.map +1 -0
  137. package/dist/model/precision.js +11 -0
  138. package/dist/model/precision.js.map +1 -0
  139. package/dist/model/project.js +17 -0
  140. package/dist/model/project.js.map +1 -0
  141. package/dist/model/ramps.js +10 -0
  142. package/dist/model/ramps.js.map +1 -0
  143. package/dist/model/roomNavigation.js +87 -0
  144. package/dist/model/roomNavigation.js.map +1 -0
  145. package/dist/model/routeClearance.js +72 -0
  146. package/dist/model/routeClearance.js.map +1 -0
  147. package/dist/model/spaces.js +104 -0
  148. package/dist/model/spaces.js.map +1 -0
  149. package/dist/model/stairGeometry.js +40 -0
  150. package/dist/model/stairGeometry.js.map +1 -0
  151. package/dist/model/stairTraversal.js +48 -0
  152. package/dist/model/stairTraversal.js.map +1 -0
  153. package/dist/model/topology.js +63 -0
  154. package/dist/model/topology.js.map +1 -0
  155. package/dist/model/types.js +35 -0
  156. package/dist/model/types.js.map +1 -0
  157. package/dist/model/validate.js +240 -0
  158. package/dist/model/validate.js.map +1 -0
  159. package/dist/model/vertical.js +129 -0
  160. package/dist/model/vertical.js.map +1 -0
  161. package/dist/model/walls.js +71 -0
  162. package/dist/model/walls.js.map +1 -0
  163. package/dist/styles.css +4931 -0
  164. package/dist/theme/index.js +34 -0
  165. package/dist/theme/index.js.map +1 -0
  166. package/dist/types/adapters/basemap.d.ts +2 -0
  167. package/dist/types/adapters/persistence.d.ts +29 -0
  168. package/dist/types/adapters/status.d.ts +4 -0
  169. package/dist/types/components/ElevatorPanel.d.ts +18 -0
  170. package/dist/types/components/Icons.d.ts +8 -0
  171. package/dist/types/components/Inspector.d.ts +38 -0
  172. package/dist/types/components/NavigatePanel.d.ts +27 -0
  173. package/dist/types/components/NavigationGraph.d.ts +10 -0
  174. package/dist/types/components/StructureExplorer.d.ts +8 -0
  175. package/dist/types/components/StructureView.d.ts +22 -0
  176. package/dist/types/components/controls.d.ts +52 -0
  177. package/dist/types/components/graphLayout.d.ts +9 -0
  178. package/dist/types/i18n.d.ts +85 -0
  179. package/dist/types/import/analysisPreview.d.ts +27 -0
  180. package/dist/types/import/brief.d.ts +22 -0
  181. package/dist/types/import/checkpoint.d.ts +49 -0
  182. package/dist/types/import/instructions.d.ts +7 -0
  183. package/dist/types/import/usage.d.ts +10 -0
  184. package/dist/types/map/CabinMaterials.d.ts +18 -0
  185. package/dist/types/map/CabinMirror.d.ts +13 -0
  186. package/dist/types/map/Doors.d.ts +11 -0
  187. package/dist/types/map/ElevatorCabin.d.ts +20 -0
  188. package/dist/types/map/FixtureLights.d.ts +35 -0
  189. package/dist/types/map/MapCanvas.d.ts +87 -0
  190. package/dist/types/map/Passenger.d.ts +18 -0
  191. package/dist/types/map/SceneLayer.d.ts +306 -0
  192. package/dist/types/map/UndergroundContext.d.ts +18 -0
  193. package/dist/types/map/ambience.d.ts +29 -0
  194. package/dist/types/map/architecture.d.ts +8 -0
  195. package/dist/types/map/bathMusic.d.ts +14 -0
  196. package/dist/types/map/cameraAim.d.ts +20 -0
  197. package/dist/types/map/elevators.d.ts +16 -0
  198. package/dist/types/map/excavation.d.ts +9 -0
  199. package/dist/types/map/exteriors.d.ts +3 -0
  200. package/dist/types/map/features.d.ts +33 -0
  201. package/dist/types/map/fences.d.ts +4 -0
  202. package/dist/types/map/journey.d.ts +36 -0
  203. package/dist/types/map/levels.d.ts +4 -0
  204. package/dist/types/map/lighting.d.ts +103 -0
  205. package/dist/types/map/loadBasemap.d.ts +4 -0
  206. package/dist/types/map/materials.d.ts +38 -0
  207. package/dist/types/map/poolLighting.d.ts +11 -0
  208. package/dist/types/map/projection.d.ts +9 -0
  209. package/dist/types/map/rampGeometry.d.ts +8 -0
  210. package/dist/types/map/route.d.ts +59 -0
  211. package/dist/types/map/stairSurfaces.d.ts +29 -0
  212. package/dist/types/map/surfaces.d.ts +36 -0
  213. package/dist/types/map/textures.d.ts +8 -0
  214. package/dist/types/map/underground.d.ts +30 -0
  215. package/dist/types/map/walk.d.ts +232 -0
  216. package/dist/types/map/walkContext.d.ts +11 -0
  217. package/dist/types/map/walkDimensions.d.ts +5 -0
  218. package/dist/types/map/walkJourney.d.ts +33 -0
  219. package/dist/types/map/walkSurfaces.d.ts +27 -0
  220. package/dist/types/map/wallJoins.d.ts +6 -0
  221. package/dist/types/map/water.d.ts +12 -0
  222. package/dist/types/model/authoring.d.ts +38 -0
  223. package/dist/types/model/boundaries.d.ts +41 -0
  224. package/dist/types/model/coverage.d.ts +8 -0
  225. package/dist/types/model/document.d.ts +9 -0
  226. package/dist/types/model/doors.d.ts +19 -0
  227. package/dist/types/model/factory.d.ts +5 -0
  228. package/dist/types/model/geometry.d.ts +99 -0
  229. package/dist/types/model/host.d.ts +154 -0
  230. package/dist/types/model/inference.d.ts +46 -0
  231. package/dist/types/model/live.d.ts +60 -0
  232. package/dist/types/model/materials.d.ts +28 -0
  233. package/dist/types/model/mutations.d.ts +178 -0
  234. package/dist/types/model/navigation.d.ts +70 -0
  235. package/dist/types/model/ontology.d.ts +43 -0
  236. package/dist/types/model/passages.d.ts +2 -0
  237. package/dist/types/model/portals.d.ts +9 -0
  238. package/dist/types/model/precision.d.ts +11 -0
  239. package/dist/types/model/project.d.ts +8 -0
  240. package/dist/types/model/ramps.d.ts +7 -0
  241. package/dist/types/model/roomNavigation.d.ts +15 -0
  242. package/dist/types/model/routeClearance.d.ts +11 -0
  243. package/dist/types/model/spaces.d.ts +46 -0
  244. package/dist/types/model/stairGeometry.d.ts +27 -0
  245. package/dist/types/model/stairTraversal.d.ts +8 -0
  246. package/dist/types/model/topology.d.ts +14 -0
  247. package/dist/types/model/types.d.ts +369 -0
  248. package/dist/types/model/validate.d.ts +38 -0
  249. package/dist/types/model/vertical.d.ts +145 -0
  250. package/dist/types/model/walls.d.ts +71 -0
  251. package/dist/types/schema/index.d.ts +25 -0
  252. package/dist/types/theme/index.d.ts +55 -0
  253. package/dist/types/viewer/FloorViewer.d.ts +76 -0
  254. package/dist/types/viewer/ViewerWorkspace.d.ts +2 -0
  255. package/dist/types/viewer/host.d.ts +11 -0
  256. package/dist/types/viewer/index.d.ts +2 -0
  257. package/dist/types/viewer/panels.d.ts +12 -0
  258. package/dist/viewer/FloorViewer.js +104 -0
  259. package/dist/viewer/FloorViewer.js.map +1 -0
  260. package/dist/viewer/ViewerWorkspace.js +370 -0
  261. package/dist/viewer/ViewerWorkspace.js.map +1 -0
  262. package/dist/viewer/panels.js +35 -0
  263. package/dist/viewer/panels.js.map +1 -0
  264. package/package.json +58 -4
@@ -0,0 +1,27 @@
1
+ import type { Point, ProjectDocument, Ring, SiteObject } from '../model/types';
2
+ /** Evaluate wall solids in absolute building heights. A host wall may continue through a
3
+ * mezzanine, while a low partition below it and a lintel overhead do not obstruct the walker. */
4
+ export declare function walkingWallRings(project: ProjectDocument, floorId: string | null): Ring[];
5
+ /** Build the support lookup when geometry changes, not for every walking frame. Open-air grade
6
+ * and floors without authored plates stay traversable. Higher and buried plates have real edges. */
7
+ export declare function floorSupport(project: ProjectDocument): {
8
+ supports: (at: Point, id: string | null) => boolean;
9
+ dropAt: (at: Point, id: string | null) => {
10
+ floorId: string;
11
+ distance: number;
12
+ } | undefined;
13
+ };
14
+ /** Clip a small walking step at the last supported point; never snap it onto another island. */
15
+ export declare function supportedStep(from: Point, to: Point, supports: (at: Point) => boolean): Point;
16
+ /** Keep a valid position across storeys, including a fall's landing. A floor picker can instead
17
+ * select a smaller footprint: enter it at a dry navigation point, not in the void outside it. */
18
+ export declare function floorArrival(project: ProjectDocument, floorId: string | null, at: Point): Point;
19
+ /** Only authored openings trigger a drop. Gaps outside the building, an undrawn floor, and
20
+ * overlapping areas that still provide a slab are not floor holes. */
21
+ export declare function floorDropAt(project: ProjectDocument, floorId: string | null, at: Point): {
22
+ floorId: string;
23
+ distance: number;
24
+ } | undefined;
25
+ /** Rooms which span the active storey bring the geometry inside their footprint along with them.
26
+ * The same context supplies the lower plate seen through an opening and the gallery seen from below. */
27
+ export declare function tallSpaceContext(project: ProjectDocument, floorId: string | null): SiteObject[];
@@ -0,0 +1,6 @@
1
+ import type { Point, ProjectDocument, Ring } from '../model/types';
2
+ /** Adjacent wall faces intersect once at each junction. Both walls use that same corner, so
3
+ * oblique L, T and four-way joins close without rectangular end caps protruding through them. */
4
+ export declare function wallFootprints(project: ProjectDocument): Map<string, Ring>;
5
+ /** Cut an opening across the joined footprint, retaining the mitres on the wall's outside ends. */
6
+ export declare function wallSpan(ring: Ring, origin: Point, direction: Point, start: number | null, end: number | null): Ring;
@@ -0,0 +1,12 @@
1
+ import * as THREE from 'three';
2
+ import type { Point, SiteObject } from '../model/types';
3
+ import type { MaterialLibrary } from './materials';
4
+ export declare function makePool(o: SiteObject, xy: (p: Point) => Point, base: number, materials: MaterialLibrary, time: {
5
+ value: number;
6
+ }, detailed?: boolean): THREE.Group;
7
+ export declare function makeWaterSlide(o: SiteObject, xy: (p: Point) => Point, base: number, materials: MaterialLibrary): THREE.Group<THREE.Object3DEventMap>;
8
+ /** Moving blue caustics from lit pools, restricted to their containing tiled chambers. This
9
+ * inexpensive projection approximates the focused light from small ripples; it is not ray tracing. */
10
+ export declare function applyPoolCaustics(scene: THREE.Scene, project: import('../model/types').ProjectDocument, floorId: string, xy: (point: Point) => Point, base: number, time: {
11
+ value: number;
12
+ }): void;
@@ -0,0 +1,38 @@
1
+ import type { Point, ProjectDocument, Ring } from './types';
2
+ /** Ignore double-click duplicates; reject a crossing while the last good draft is still editable. */
3
+ export declare function appendAreaPoint(draft: Ring, point: Point): {
4
+ points: Ring;
5
+ error?: string;
6
+ };
7
+ /** The wall/partition tool: divide along the endpoints actually used after welding. */
8
+ export declare function drawBarrier(project: ProjectDocument, floorId: string | null, a: Point, b: Point, kind?: 'wall' | 'fence'): import("./types").Barrier | undefined;
9
+ /** A completed stroke stops chaining when its tip meets an existing boundary, including an
10
+ * earlier segment of the same outline. Test before adding the segment: afterwards every tip
11
+ * belongs to a boundary. Use the model's joining tolerance, not the pointer's snap reach. */
12
+ export declare function endsBoundaryStroke(project: ProjectDocument, floorId: string | null, a: Point, b: Point, kind?: 'wall' | 'fence' | 'boundary'): boolean;
13
+ /** The enclose tool: creating and re-fitting use exactly the same generated outline. */
14
+ export declare function encloseRoom(project: ProjectDocument, floorId: string | null, point: Point): {
15
+ room: import("./types").SiteObject;
16
+ existing: boolean;
17
+ } | null;
18
+ export type GeometryDrag = {
19
+ kind: 'junction';
20
+ id: string;
21
+ point: Point;
22
+ } | {
23
+ kind: 'barrier';
24
+ id: string;
25
+ point: Point;
26
+ } | {
27
+ kind: 'ring';
28
+ id: string;
29
+ point: Point;
30
+ ringIndex: number;
31
+ index: number;
32
+ };
33
+ /** Apply one requested drop to a transaction draft. The editor previews snapping alone and calls
34
+ * this once on release; transact either accepts the entire move or leaves the original intact. */
35
+ export declare function applyGeometryDrag(project: ProjectDocument, move: GeometryDrag): void;
36
+ /** Optional constrained authoring operation for hosts and scripted drawing: find a valid position
37
+ * along a requested movement. Interactive editor drags use applyGeometryDrag on release instead. */
38
+ export declare function dragGeometry(project: ProjectDocument, _floorId: string | null, move: GeometryDrag): ProjectDocument;
@@ -0,0 +1,41 @@
1
+ import type { Barrier, BoundaryUse, Point, ProjectDocument, Ring, SiteObject, VirtualBoundary } from './types';
2
+ export type BoundaryEdge = Barrier | VirtualBoundary;
3
+ export interface BoundaryRegion {
4
+ loops: BoundaryUse[][];
5
+ /** Centreline polygon, including holes. Net footprints also subtract the physical wall bodies. */
6
+ rings: Ring[];
7
+ }
8
+ export declare const boundaryEdges: (p: ProjectDocument) => BoundaryEdge[];
9
+ export declare const followsBoundaries: (o: SiteObject) => boolean;
10
+ /** Keep every reference correct when a physical/virtual edge is split or replaced. */
11
+ export declare function replaceBoundaryUses(p: ProjectDocument, edgeId: string, replacement: BoundaryUse[]): void;
12
+ export declare function boundaryRings(p: ProjectDocument, loops: BoundaryUse[][], floorId: string | null): Ring[];
13
+ /** Planarize a floor: one junction at each intersection, with overlaps represented once.
14
+ * Exact calculated intersections are shared; the input grid is not applied again here. */
15
+ export declare function normalizeBoundaries(p: ProjectDocument, floorId: string | null): void;
16
+ /** Bounded faces of the shared graph. Bridges do not divide a face; nested components form holes. */
17
+ export declare function boundaryRegions(p: ProjectDocument, floorId: string | null): BoundaryRegion[];
18
+ export declare function derivedSpaceRings(p: ProjectDocument, o: SiteObject): Ring[];
19
+ export declare function bindSpaceToRegion(p: ProjectDocument, o: SiteObject, region: BoundaryRegion): void;
20
+ export declare function boundaryRegionAt(p: ProjectDocument, floorId: string | null, point: Point): BoundaryRegion | null;
21
+ export declare function addVirtualBoundary(p: ProjectDocument, floorId: string | null, a: Point, b: Point): string;
22
+ /** The drawing tool intentionally opens any collinear wall span. Ordinary addVirtualBoundary
23
+ * remains non-destructive for generated space outlines and model normalization. */
24
+ export declare function drawVirtualBoundary(p: ProjectDocument, floorId: string | null, a: Point, b: Point): string;
25
+ /** Explicit conversion: retain the drawn shape with shared virtual edges, or adopt its enclosing
26
+ * walls on request. Legacy documents remain independent until this operation is chosen. */
27
+ export declare function connectSpace(p: ProjectDocument, objectId: string, source?: 'outline' | 'walls'): void;
28
+ export declare function disconnectSpace(p: ProjectDocument, objectId: string): void;
29
+ export declare function addBoundaryHole(p: ProjectDocument, o: SiteObject, ring: Ring): void;
30
+ export declare function splitBoundarySpace(p: ProjectDocument, o: SiteObject, a: Point, b: Point, wall?: boolean): string;
31
+ /** Join centreline loops before deriving the net footprint, including the former wall's floor area. */
32
+ export declare function mergeBoundaryGeometry(p: ProjectDocument, keep: SiteObject, absorbed: SiteObject): boolean;
33
+ /** A removed wall leaves the semantic division as a virtual boundary. */
34
+ export declare function preserveBoundary(p: ProjectDocument, edge: BoundaryEdge): void;
35
+ /** Regenerate by explicit loops, subdividing identities only when a new boundary divides a space.
36
+ * No old/new footprint-overlap matching is involved in ordinary wall movements. */
37
+ export declare function refreshBoundarySpaces(p: ProjectDocument, topologyChanged?: Set<string | null>): string[];
38
+ /** One synchronization gate for UI gestures, host mutations, history and persistence. */
39
+ export declare function synchronizeGeometry(before: ProjectDocument, p: ProjectDocument): void;
40
+ /** Validate the explicit topology and its cache. Independent polygons retain their existing rules. */
41
+ export declare function validateSpaceBoundaries(p: ProjectDocument): void;
@@ -0,0 +1,8 @@
1
+ import { type ProjectDocument, type SiteObject } from './types';
2
+ export declare const DEFAULT_RANGE = 12;
3
+ export declare const DEFAULT_FOV = 70;
4
+ /** Ids of the spaces and openings inside `camera`'s cone with an unobstructed line to it.
5
+ *
6
+ * Sightlines stop at walls, with one exception: the opening being tested is itself a hole in the
7
+ * wall it sits on, so that wall cannot be what hides it. */
8
+ export declare function coverageOf(project: ProjectDocument, camera: SiteObject): string[];
@@ -0,0 +1,9 @@
1
+ import type { AssetRepository, ProjectDocument } from './types';
2
+ export declare function blobDataUrl(blob: Blob): Promise<string>;
3
+ export declare function exportProject(project: ProjectDocument, assets: AssetRepository): Promise<string>;
4
+ export declare function importProject(json: string, assets: AssetRepository): Promise<ProjectDocument>;
5
+ /** Display semantics: ids and updatedAt untouched, nothing written anywhere — unlike importProject, which rewrites both for import-for-editing. Unsupported embedded entries resolve to undefined at get time rather than throwing. */
6
+ export declare function parseExport(json: string): {
7
+ project: ProjectDocument;
8
+ assets: AssetRepository;
9
+ };
@@ -0,0 +1,19 @@
1
+ import type { Point, ProjectDocument, SiteObject } from './types';
2
+ /** One hinge and signed rotation for plan symbols, drag previews and the animated 3D leaf. */
3
+ export declare function doorGeometry(project: ProjectDocument, door: SiteObject): {
4
+ hinge: Point;
5
+ swing: number;
6
+ tip: (degrees: number) => Point;
7
+ arc: Point[];
8
+ };
9
+ /** A small dead zone retains the original side during an ordinary along-wall drag. */
10
+ export declare function draggedDoorSwing(project: ProjectDocument, door: SiteObject, pointer: Point): 1 | -1;
11
+ /** All moving leaves, shared by the plan and 3D renderer. Double doors meet in the centre. */
12
+ export declare function doorLeaves(project: ProjectDocument, door: SiteObject): {
13
+ hinge: Point;
14
+ swing: number;
15
+ tip: (degrees: number) => Point;
16
+ arc: Point[];
17
+ }[];
18
+ /** Architectural symbol (or a feed's current state), including a rail and travel arrow for sliders. */
19
+ export declare function doorSymbol(project: ProjectDocument, door: SiteObject, open?: boolean): Point[][];
@@ -0,0 +1,5 @@
1
+ import type { ObjectKind, Origin, Point, ProjectDocument, SiteObject } from './types';
2
+ /** An empty, valid single-floor project anchored at an explicit EPSG:3067 origin (with optional site bearing). */
3
+ export declare function emptyProject(origin: Origin, name?: string, datum?: string): ProjectDocument;
4
+ /** Create a site object of the given kind at a position, seeded with sensible default dimensions. */
5
+ export declare function createObject(kind: ObjectKind, position: Point, floorId: string | null, name?: string): SiteObject;
@@ -0,0 +1,99 @@
1
+ import type { Barrier, Drawing, Origin, Point, ProjectDocument, Ring, SiteObject, Slope, VirtualBoundary } from './types';
2
+ export declare const distance: (a: Point, b: Point) => number;
3
+ export declare const rotate: (p: Point, degrees: number) => Point;
4
+ export declare const geoOrigin: (lngLat: Point, bearing?: number) => Origin;
5
+ /** Shift a site anchor by a distance on the ground, in metres east and north.
6
+ *
7
+ * Nudging a building into place is a thing you do in metres — "half a metre that way" — and the
8
+ * anchor is stored in degrees, where the useful step depends on latitude and differs between the
9
+ * two axes. Deliberately NOT rotated by the site bearing: this moves the site across the world,
10
+ * and the directions that make sense for that are the compass ones, not the plan's own grid. */
11
+ export declare const moveOrigin: (origin: Origin, east: number, north: number) => Origin;
12
+ export declare const toLocal: (lngLat: Point, origin: Origin) => Point;
13
+ export declare const toLngLat: (p: Point, origin: Origin) => Point;
14
+ export declare const add: (a: Point, b: Point) => Point;
15
+ export declare const closeRing: (ring: Ring) => Ring;
16
+ export declare const openRing: (ring: Ring) => Ring;
17
+ export declare const ringArea: (ring: Ring) => number;
18
+ export declare const objectArea: (object: SiteObject) => number;
19
+ export declare const centroid: (ring: Ring) => Point;
20
+ export declare const rectangle: (center: Point, width: number, depth: number, rotation?: number) => Ring;
21
+ /** Do the two open segments cross? Used for line of sight: a wall between two points blocks it.
22
+ * Touching at an endpoint does not count — walls meet at shared junctions, and a sightline grazing
23
+ * such a corner is not obstructed by it. */
24
+ export declare function segmentsCross(a: Point, b: Point, c: Point, d: Point): boolean;
25
+ export declare function segmentProjection(p: Point, a: Point, b: Point): {
26
+ point: Point;
27
+ t: number;
28
+ distance: number;
29
+ length: number;
30
+ };
31
+ /** Elevation of a sloped area at a point: project onto the slope axis and lerp high → low. Points
32
+ * beyond either end clamp, so a footprint wider than its axis keeps flat aprons at both ends. */
33
+ export declare function slopeElevation(slope: Slope, point: Point): number;
34
+ /** The ground an object covers. Most areas carry an explicit outline; anything placed by size falls
35
+ * back to the rectangle its width, depth and rotation describe. One definition, so the model and the
36
+ * renderer cannot disagree about where a thing is. */
37
+ export declare const footprint: (o: SiteObject) => Ring[];
38
+ export declare function barrierEnds(project: ProjectDocument, barrier: Barrier | VirtualBoundary): [Point, Point];
39
+ export declare function objectPosition(project: ProjectDocument, object: SiteObject): Point;
40
+ export declare function objectRotation(project: ProjectDocument, object: SiteObject): number;
41
+ export declare function pointInRing(point: Point, ring: Ring): boolean;
42
+ /** Whether segments a–b and c–d cross or touch, endpoints included. */
43
+ export declare function intersects(a: Point, b: Point, c: Point, d: Point): boolean;
44
+ export declare function containedBy(child: Ring[], parent: Ring[]): boolean;
45
+ export declare function snapPoint(project: ProjectDocument, floorId: string | null, point: Point, tolerance: number, previous?: Point, grid?: boolean,
46
+ /** Direction the segment from `previous` is held to, with its 15° multiples. Default 0 is the site
47
+ * grid; pass `referenceAxis(...).angle` to hold to the building or to a neighbouring wall instead. */
48
+ axis?: number): {
49
+ point: Point;
50
+ label: string;
51
+ };
52
+ export declare function holdAngle(previous: Point, point: Point, axis: number, tolerance: number): {
53
+ point: Point;
54
+ degrees: number;
55
+ quarter: number;
56
+ } | null;
57
+ /** One centimetre is the model's degeneracy guard, independent of the drawing grid and zoom.
58
+ * Short returns, jambs and staggered junctions are real geometry; their screen handles spread
59
+ * apart when necessary so they remain editable. */
60
+ export declare const MIN_SEGMENT = 0.01;
61
+ /** An opening needs a valid wall AND enough length for its actual width. Kept as an exported
62
+ * base limit for callers; there is no additional one-metre restriction on narrow doors/windows. */
63
+ export declare const OPENING_MIN_SEGMENT = 0.01;
64
+ /** Automatic joins only absorb sub-millimetre coordinate noise. Interactive snapping has its
65
+ * own screen-based reach, so a deliberate centimetre-scale feature survives with snapping off. */
66
+ /** Weld a connection near the end of a wall to that end. The snap preview and the actual
67
+ * junction use the same rule, so an ordinary T-junction cannot leave an uneditable stub. */
68
+ export declare function barrierJoinPoint(project: ProjectDocument, point: Point, floorId: string | null): Point;
69
+ /** A preview can check a connection without partially splitting any walls. */
70
+ export declare function junctionIssue(project: ProjectDocument, point: Point, floorId: string | null): string | null;
71
+ /** Preflight the complete stroke, including openings crossed between its endpoints. */
72
+ export declare function barrierStrokeIssue(project: ProjectDocument, a: Point, b: Point, floorId: string | null): string | null;
73
+ export declare function joinAt(project: ProjectDocument, point: Point, floorId: string | null): string;
74
+ /** Take a wall out of the document, with everything that only existed because it was there.
75
+ *
76
+ * A wall is never alone: doors and windows hang in it, junctions exist to hold its ends, and route
77
+ * nodes may be bound to those openings. Removing the barrier alone leaves each of those pointing at
78
+ * something that is gone, and the document refuses the whole edit — so the delete appears to do
79
+ * nothing at all, which is worse than either outcome. Everything that removes a wall goes through
80
+ * here so that cannot happen in one place and not another.
81
+ *
82
+ * A junction survives if any other wall still ends there; the ontology is pruned by the caller,
83
+ * which knows whether spaces are also being merged. */
84
+ export declare function removeBarrier(project: ProjectDocument, barrierId: string): void;
85
+ export declare function addBarrier(project: ProjectDocument, a: Point, b: Point, floorId: string | null, kind: 'wall' | 'fence'): Barrier | undefined;
86
+ export declare function splitRoom(project: ProjectDocument, roomId: string, pa: Point, pb: Point,
87
+ /** Build the partition wall along the cut. False when a wall already exists there — splitting a
88
+ * space *because* someone drew a wall must not draw a second one on top of it. */
89
+ wall?: boolean): string;
90
+ /** Delete a floor and everything anchored to it. The cascade is the whole job: a floor owns junctions,
91
+ * barriers, objects and drawings, and those are in turn referenced from elsewhere — openings hang off
92
+ * barriers, cameras watch objects, lifts serve floors, nested zones name a parent, the nav graph binds
93
+ * both, a building may roof this level, and the document may open on it. Anything missed here surfaces
94
+ * later as a validation failure on load, so it is all handled up front.
95
+ * Refuses to remove the last floor: a project must always have one. Returns the ids that were removed. */
96
+ export declare function removeFloor(project: ProjectDocument, floorId: string): string[];
97
+ export declare function duplicateFloor(project: ProjectDocument, floorId: string): string;
98
+ export declare function alignDrawing(imagePoints: [Point, Point], mapPoints: [Point, Point]): Pick<Drawing, 'origin' | 'scale' | 'rotation'>;
99
+ export declare const drawingCorners: (d: Drawing) => Point[];
@@ -0,0 +1,154 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { StyleSpecification, RequestTransformFunction } from 'maplibre-gl';
3
+ import type { ProjectDocument, ProjectRepository, AssetRepository, SiteObject, Point } from './types';
4
+ import type { StatusFeed, StatusReading } from './live';
5
+ /** A named coordinate system a host offers for footprint import — converts the file's coordinates to
6
+ * lng/lat (WGS84). The core carries no projections; a host supplies these (e.g. via proj4). */
7
+ export interface ImportProjection {
8
+ label: string;
9
+ toLngLat(p: Point): Point;
10
+ }
11
+ /** Describes a basemap's vector-tile schema so the built-in adoption, 3D-city, cadastre and
12
+ * below-grade context features can read it. The library ships no schema of its own — a host names its
13
+ * tiles' layers/fields here (see the reference `mmlBasemap` for Finland's MML). Each part is optional;
14
+ * a feature is enabled only when its part is present. */
15
+ export interface BasemapVectorSchema {
16
+ /** Building footprints — powers the adopt tool and the 3D-city massing. */
17
+ footprints?: {
18
+ sourceLayer: string;
19
+ idField: string;
20
+ /** Estimated storey count from a footprint's properties (adopt seeds this many floors). */
21
+ storeys?: (props: Record<string, unknown>) => number;
22
+ /** Human name for an adopted footprint from its properties. */
23
+ name?: (props: Record<string, unknown>) => string | undefined;
24
+ /** A MapLibre expression for the 3D extrusion height (paint can't call a JS fn); omit → flat. */
25
+ heightExpression?: unknown;
26
+ };
27
+ /** Below-grade context layers (soil ghosts) drawn when viewing a basement floor. */
28
+ context?: {
29
+ waterLayer?: string;
30
+ roadLayer?: string;
31
+ buildingLayer?: string;
32
+ };
33
+ /** Cadastral parcel overlay from a separate vector tilejson. */
34
+ cadastre?: {
35
+ tilejson: string;
36
+ attribution: string;
37
+ parcelLayer: string;
38
+ boundaryLayer: string;
39
+ markLayer: string;
40
+ labelLayer: string;
41
+ labelField: string;
42
+ font: string;
43
+ };
44
+ }
45
+ export interface BasemapConfig {
46
+ style: string | StyleSpecification;
47
+ /** Last chance to adjust the style before it is handed to the map: recolour layers, drop clutter,
48
+ * swap in a dusk palette. Runs for a fetched style and an inline one alike, after relative URLs
49
+ * have been resolved, so a host can tune a published basemap without forking and maintaining it.
50
+ * Mutating the argument and returning it is fine — the style is not shared. */
51
+ styleTransform?: (style: StyleSpecification) => StyleSpecification;
52
+ transformRequest?: RequestTransformFunction;
53
+ /** Name shown for this basemap in the editor's map-settings picker (host-branded); defaults to "Map background". */
54
+ label?: string;
55
+ /** Vector-tile schema for the built-in adoption/3D-city/cadastre features (host-supplied). */
56
+ vectorSchema?: BasemapVectorSchema;
57
+ }
58
+ export interface PlannerAdapters {
59
+ projects: ProjectRepository;
60
+ assets: AssetRepository;
61
+ /** Live status readings. Optional: a host that only models premises omits it, and the editor then
62
+ * drops its monitoring surface entirely rather than showing an empty one. */
63
+ status?: StatusFeed;
64
+ basemap?: BasemapConfig;
65
+ /** Extra coordinate systems offered in the footprint-import dialog (beyond lng/lat, always available). */
66
+ importProjections?: ImportProjection[];
67
+ /** Optional server-backed AI import. Credentials and tool execution belong to the host backend. */
68
+ aiImport?: AiImportAdapter;
69
+ /** Host-side PDF page conversion. The editor never loads a PDF parser or worker. */
70
+ pdfDrawing?: PdfDrawingAdapter;
71
+ }
72
+ export interface PdfDrawingAdapter {
73
+ render(file: File, page: number): Promise<Blob>;
74
+ }
75
+ export interface AiImportAdapter {
76
+ /** Queue human instructions for the next provider turn of an already running job. */
77
+ sendInstruction?(jobId: string, instruction: import('../import/instructions').ImportInstruction): Promise<void>;
78
+ run(file: File, options: {
79
+ origin: ProjectDocument['origin'];
80
+ instructions: string;
81
+ brief?: import('../import/brief').ImportBrief;
82
+ base?: ProjectDocument;
83
+ checkpoint?: import('../import/checkpoint').ImportCheckpoint;
84
+ budget?: import('../import/checkpoint').ImportBudget;
85
+ onCheckpoint?: (checkpoint: import('../import/checkpoint').ImportCheckpoint) => void | Promise<void>;
86
+ onPause?: (pause: import('../import/checkpoint').ImportPause) => void | Promise<void>;
87
+ onAnalysis?: (preview: import('../import/analysisPreview').ImportAnalysisPreview) => void | Promise<void>;
88
+ onSession?: (jobId: string) => void | Promise<void>;
89
+ signal: AbortSignal;
90
+ onProgress: (event: {
91
+ type: 'text' | 'tool' | 'status';
92
+ detail: string;
93
+ }) => void | Promise<void>;
94
+ /** Await acceptance/persistence before consuming the next event. */
95
+ onDocument: (document: ProjectDocument) => void | Promise<void>;
96
+ /** Cumulative usage for this run; a continuation starts a new run. */
97
+ onUsage?: (usage: import('../import/usage').AiTokenUsage) => void | Promise<void>;
98
+ }): Promise<ProjectDocument>;
99
+ }
100
+ /** Map camera pose. Part of ViewState; hosts persist and restore it (e.g. encoded in a deep link). */
101
+ export interface CameraState {
102
+ center: [number, number];
103
+ zoom: number;
104
+ bearing: number;
105
+ pitch: number;
106
+ }
107
+ /** Camera + floor + mode snapshot — supplied via `initialView` and emitted through `onViewChange`; hosts persist it (e.g. as a deep link). */
108
+ export interface ViewState {
109
+ floor?: string | null;
110
+ threeD?: boolean;
111
+ stack?: boolean;
112
+ /** First-person walk-through. Implies threeD; stack is ignored while it is on. */
113
+ walk?: boolean;
114
+ camera?: CameraState;
115
+ /** Which map background to open on: the host's basemap, or the plain drawing ground. A project
116
+ * that is nowhere in particular — a sample, a fiction, a plan not yet placed — has nothing to
117
+ * gain from the city under it and pays to draw it. Absent means the host's basemap if it has one. */
118
+ basemap?: 'plan' | 'host';
119
+ /** Which surface to open on. Absent means the plan viewer — right for a link someone was sent,
120
+ * wrong for a project the host just created or imported, where the point is to start drawing. */
121
+ mode?: PlannerMode;
122
+ }
123
+ /** The editor's three surfaces: pure plan viewer, authoring editor, live monitoring. */
124
+ export type PlannerMode = 'view' | 'edit' | 'live';
125
+ /** Context for a host-rendered status panel in the inspector (controls, a simulator, a work-order link, …). */
126
+ export interface StatusPanelContext {
127
+ object: SiteObject;
128
+ status?: StatusReading;
129
+ editing: boolean;
130
+ live: boolean;
131
+ }
132
+ /** Optional host commands for passenger lifts. Readings stay transient; the host owns sequencing. */
133
+ export interface ElevatorControls {
134
+ statuses: StatusReading[];
135
+ call(feedId: string, floorId: string): void;
136
+ hold(feedId: string, open: boolean): void;
137
+ }
138
+ export interface SitePlannerProps {
139
+ /** The document to edit. The editor owns edits through its own history, so this is the *initial*
140
+ * document; pass a new one with a different `id` to load a different project (same-id updates are
141
+ * ignored). Observe edits via `onChange`. */
142
+ project: ProjectDocument;
143
+ adapters: PlannerAdapters;
144
+ onChange?: (project: ProjectDocument) => void;
145
+ onSelectionChange?: (id: string | null) => void;
146
+ onBack?: () => void;
147
+ initialView?: ViewState;
148
+ onViewChange?: (view: ViewState) => void;
149
+ /** Notified when the editor switches surface — a host can, e.g., start/stop its live feed's traffic. */
150
+ onModeChange?: (mode: PlannerMode) => void;
151
+ /** Render host-specific controls for a selected bound object (return null to show none). Keeps command/simulation vocabulary out of the library. */
152
+ renderStatusPanel?: (ctx: StatusPanelContext) => ReactNode;
153
+ elevators?: ElevatorControls;
154
+ }
@@ -0,0 +1,46 @@
1
+ import { type Point, type Portal, type ProjectDocument, type SiteObject } from './types';
2
+ export { TRAVERSABLE } from './passages';
3
+ /** Infer the portals a plan already describes: for each opening, the space on either side of the wall
4
+ * it sits in. This is the move software without a plan cannot make — it has to be told which
5
+ * doors bound an area, because none of them has a floor plan to ask.
6
+ *
7
+ * Openings whose sides cannot be resolved are skipped rather than guessed at: an unbounded or
8
+ * open-plan side is a real modelling gap, and inventing a portal there would hide it. */
9
+ export declare function inferPortals(project: ProjectDocument): Portal[];
10
+ /** Infer the portals that have no door in them: two spaces that share a boundary with nothing built
11
+ * across it. Open-plan floors are made of these — a department opening onto a gallery, a lift car
12
+ * onto its lobby — and a model that only knows about door objects cannot see any of them.
13
+ *
14
+ * Shared virtual edges give exact connectivity. For independent outlines, walk the outline and
15
+ * accumulate stretches that can step across into a neighbour without crossing a wall. */
16
+ export declare function inferOpenBoundaries(project: ProjectDocument): Portal[];
17
+ /** Re-read the portals from the plan, keeping what a person has decided.
18
+ *
19
+ * Hand-authored portals (any id inference would not mint) survive wholesale. On re-inferred ones the
20
+ * geometry is the plan's to change — which spaces, through which opening — but the semantic fields a
21
+ * person may have set (`passage`, `attests`, `name`, `metadata`) are carried onto the replacement:
22
+ * sealing a doorway or marking it monitored must survive the plan being redrawn around it. A portal
23
+ * the plan no longer describes goes, and its edits go with it — they were about a way through that
24
+ * no longer exists. */
25
+ export declare function refreshPortals(project: ProjectDocument): number;
26
+ /** Spaces the segment a→b cuts clean across: it enters and leaves, so the space really is in two
27
+ * pieces. Touching a corner or stopping halfway inside does not divide anything. */
28
+ export declare function spacesDividedBy(project: ProjectDocument, floorId: string | null, a: Point, b: Point): SiteObject[];
29
+ /** Split every space a new wall cuts across, so the plan cannot claim two walled-apart halves are one
30
+ * place. Returns the ids of the pieces created.
31
+ *
32
+ * The wall is assumed to exist already — this is called *because* one was drawn — so no partition is
33
+ * built. splitRoom would otherwise lay a second wall along the first.
34
+ *
35
+ * Splitting is safe in a way that joining is not: one space becomes two and both inherit everything,
36
+ * where merging two spaces would have to destroy one identity — its name, its feed binding, whichever
37
+ * zones it had joined. That asymmetry is why this happens automatically and merging never will. */
38
+ export declare function divideSpaces(project: ProjectDocument, floorId: string | null, a: Point, b: Point): string[];
39
+ /** Spaces that a wall was the only thing keeping apart: remove it and they are one room again.
40
+ *
41
+ * Answered before the wall goes, because afterwards the evidence is gone. Two spaces qualify when
42
+ * they share a boundary that this barrier runs along, and nothing else is built across it. */
43
+ export declare function spacesRejoinedBy(project: ProjectDocument, barrierId: string): [SiteObject, SiteObject] | null;
44
+ /** Merge `absorbed` into `keep`, uniting their footprints. The survivor keeps its own name, colour and
45
+ * bindings; that is the whole reason this is never automatic — something is always discarded. */
46
+ export declare function mergeSpaces(project: ProjectDocument, keepId: string, absorbedId: string): boolean;
@@ -0,0 +1,60 @@
1
+ import type { ProjectDocument } from './types';
2
+ export interface StatusMetrics {
3
+ occupancy?: number;
4
+ capacity?: number;
5
+ presence?: boolean;
6
+ co2?: number;
7
+ lux?: number;
8
+ temperature?: number;
9
+ }
10
+ /** Severity the viewer colours by, most-to-least urgent. Domain-neutral: `critical` is whatever the
11
+ * host deems an urgent condition (a security alarm, an offline sensor, an over-capacity space, …). */
12
+ export type StatusTone = 'critical' | 'warning' | 'normal' | 'unknown';
13
+ export interface StatusReading {
14
+ feedId: string;
15
+ /** How the viewer colours the bound object. */
16
+ tone: StatusTone;
17
+ /** Human-readable status text the viewer shows (host-authored). */
18
+ label: string;
19
+ /** Epoch-ms of the reading. Enables the viewer's staleness warning; omit to opt out. */
20
+ timestamp?: number;
21
+ /** Generic space/environment telemetry the viewer renders (occupancy rollups, etc.). */
22
+ metrics?: StatusMetrics;
23
+ /** For a door, gate or turnstile: whether the leaf is standing open right now. The plan draws it —
24
+ * an open leaf swings, a closed one sits in the frame. Distinct from `tone`, which says whether
25
+ * anyone should be worried: a door can be open and perfectly normal, or closed and in alarm.
26
+ * Omitted means unknown, and an unknown door is drawn with the architectural swing symbol. */
27
+ open?: boolean;
28
+ /** For a lift: the floor its car is standing at right now, as a floor id. The plan draws the car
29
+ * there and slides it when the value changes, which is the difference between a shaft and a lift
30
+ * you can watch. Omitted means unknown, and an unknown car rests at the lowest level it serves —
31
+ * where an idle lift really does wait. Sits beside `open`, which says whether its doors are
32
+ * standing open, for the same reason: both are what the thing is doing, not whether to worry. */
33
+ carFloorId?: string;
34
+ /** Destination while travelling; carFloorId remains the last arrived landing. */
35
+ targetFloorId?: string;
36
+ /** Expected travel duration for the current car movement, in seconds. Hosts can compress demo
37
+ * trips; absent means the renderer's ordinary 1.5 m/s. Arrival readings remain authoritative. */
38
+ carTravelSeconds?: number;
39
+ /** Travel or door movement is in progress; passengers cannot board or leave yet. */
40
+ moving?: boolean;
41
+ /** For an escalator: whether it is running right now. A stopped escalator is a stair, and the
42
+ * plan draws it as one — the steps stand still. Omitted means unknown and draws it running,
43
+ * because an escalator that is working is the ordinary case and a stopped one is the exception
44
+ * worth reporting. Sits beside `open` and `carFloorId` for the same reason: all three say what
45
+ * the thing is doing, not whether anyone should worry, which is `tone`. */
46
+ running?: boolean;
47
+ /** For an escalator that can be reversed: which way it is carrying people at this moment, which a
48
+ * station or a shopping centre flips between the morning and the evening peak. Overrides the
49
+ * object's authored `travel` for as long as the reading stands. Pass readings to findRoute's
50
+ * options to route with the current direction; the stored graph remains unchanged. */
51
+ travel?: 'up' | 'down';
52
+ /** Opaque host state, passed through untouched — the library never reads it. */
53
+ details?: Record<string, unknown>;
54
+ }
55
+ /** The live-status contract: a source of StatusReading snapshots keyed to SiteObjects by feedId.
56
+ * Deliberately minimal — just subscribe. Interactive concerns (commanding something, simulating
57
+ * traffic) are host-specific and belong to the host's own feed and UI, not this contract. */
58
+ export interface StatusFeed {
59
+ subscribe(project: ProjectDocument, listener: (statuses: StatusReading[]) => void): () => void;
60
+ }
@@ -0,0 +1,28 @@
1
+ export declare const EXTERIOR_PRESETS: {
2
+ readonly limestone: {
3
+ readonly name: "Limestone";
4
+ readonly material: "stone";
5
+ readonly color: "#e2e4e6";
6
+ };
7
+ readonly brick: {
8
+ readonly name: "Warm brick";
9
+ readonly material: "brick";
10
+ readonly color: "#9b705b";
11
+ };
12
+ readonly darkBrick: {
13
+ readonly name: "Dark brick";
14
+ readonly material: "brick";
15
+ readonly color: "#7a4636";
16
+ };
17
+ readonly plaster: {
18
+ readonly name: "Ivory render";
19
+ readonly material: "plaster";
20
+ readonly color: "#e0ddd4";
21
+ };
22
+ readonly timber: {
23
+ readonly name: "Cedar cladding";
24
+ readonly material: "timber";
25
+ readonly color: "#ab8b68";
26
+ };
27
+ };
28
+ export type ExteriorPreset = keyof typeof EXTERIOR_PRESETS;