@pascal-app/core 0.8.0 → 0.9.1

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 (272) hide show
  1. package/dist/events/bus.d.ts +39 -13
  2. package/dist/events/bus.d.ts.map +1 -1
  3. package/dist/hooks/scene-registry/scene-registry.d.ts +6 -22
  4. package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
  5. package/dist/hooks/scene-registry/scene-registry.js +33 -26
  6. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts +14 -0
  7. package/dist/hooks/spatial-grid/floor-placed-elevation.d.ts.map +1 -0
  8. package/dist/hooks/spatial-grid/floor-placed-elevation.js +51 -0
  9. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts +2 -0
  10. package/dist/hooks/spatial-grid/floor-placed-elevation.test.d.ts.map +1 -0
  11. package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +273 -0
  12. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +13 -2
  13. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  14. package/dist/hooks/spatial-grid/spatial-grid-manager.js +95 -9
  15. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +28 -1
  16. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  17. package/dist/hooks/spatial-grid/spatial-grid-sync.js +91 -18
  18. package/dist/index.d.ts +22 -4
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +19 -2
  21. package/dist/lib/polygon-relations.d.ts +10 -0
  22. package/dist/lib/polygon-relations.d.ts.map +1 -0
  23. package/dist/lib/polygon-relations.js +73 -0
  24. package/dist/lib/space-detection-pause.test.d.ts +2 -0
  25. package/dist/lib/space-detection-pause.test.d.ts.map +1 -0
  26. package/dist/lib/space-detection-pause.test.js +42 -0
  27. package/dist/lib/space-detection.d.ts +30 -1
  28. package/dist/lib/space-detection.d.ts.map +1 -1
  29. package/dist/lib/space-detection.js +215 -36
  30. package/dist/lib/space-detection.test.d.ts +2 -0
  31. package/dist/lib/space-detection.test.d.ts.map +1 -0
  32. package/dist/lib/space-detection.test.js +77 -0
  33. package/dist/material-library.d.ts +1 -1
  34. package/dist/material-library.d.ts.map +1 -1
  35. package/dist/material-library.js +1940 -143
  36. package/dist/registry/__bench__/relations-resolver.bench.d.ts +15 -0
  37. package/dist/registry/__bench__/relations-resolver.bench.d.ts.map +1 -0
  38. package/dist/registry/__bench__/relations-resolver.bench.js +170 -0
  39. package/dist/registry/handles.d.ts +321 -0
  40. package/dist/registry/handles.d.ts.map +1 -0
  41. package/dist/registry/handles.js +24 -0
  42. package/dist/registry/index.d.ts +7 -0
  43. package/dist/registry/index.d.ts.map +1 -0
  44. package/dist/registry/index.js +4 -0
  45. package/dist/registry/registry.d.ts +93 -0
  46. package/dist/registry/registry.d.ts.map +1 -0
  47. package/dist/registry/registry.js +201 -0
  48. package/dist/registry/registry.test.d.ts +2 -0
  49. package/dist/registry/registry.test.d.ts.map +1 -0
  50. package/dist/registry/registry.test.js +183 -0
  51. package/dist/registry/relations-resolver.d.ts +42 -0
  52. package/dist/registry/relations-resolver.d.ts.map +1 -0
  53. package/dist/registry/relations-resolver.js +77 -0
  54. package/dist/registry/relations-resolver.test.d.ts +2 -0
  55. package/dist/registry/relations-resolver.test.d.ts.map +1 -0
  56. package/dist/registry/relations-resolver.test.js +183 -0
  57. package/dist/registry/scene-api.d.ts +44 -0
  58. package/dist/registry/scene-api.d.ts.map +1 -0
  59. package/dist/registry/scene-api.js +111 -0
  60. package/dist/registry/scene-api.test.d.ts +2 -0
  61. package/dist/registry/scene-api.test.d.ts.map +1 -0
  62. package/dist/registry/scene-api.test.js +183 -0
  63. package/dist/registry/subtree.d.ts +67 -0
  64. package/dist/registry/subtree.d.ts.map +1 -0
  65. package/dist/registry/subtree.js +119 -0
  66. package/dist/registry/subtree.test.d.ts +2 -0
  67. package/dist/registry/subtree.test.d.ts.map +1 -0
  68. package/dist/registry/subtree.test.js +133 -0
  69. package/dist/registry/types.d.ts +1420 -0
  70. package/dist/registry/types.d.ts.map +1 -0
  71. package/dist/registry/types.js +1 -0
  72. package/dist/schema/index.d.ts +17 -2
  73. package/dist/schema/index.d.ts.map +1 -1
  74. package/dist/schema/index.js +17 -3
  75. package/dist/schema/material.d.ts +10 -0
  76. package/dist/schema/material.d.ts.map +1 -1
  77. package/dist/schema/material.js +10 -0
  78. package/dist/schema/nodes/box-vent.d.ts +74 -0
  79. package/dist/schema/nodes/box-vent.d.ts.map +1 -0
  80. package/dist/schema/nodes/box-vent.js +63 -0
  81. package/dist/schema/nodes/building.d.ts +1 -1
  82. package/dist/schema/nodes/building.d.ts.map +1 -1
  83. package/dist/schema/nodes/building.js +3 -2
  84. package/dist/schema/nodes/ceiling.d.ts +2 -0
  85. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  86. package/dist/schema/nodes/ceiling.js +1 -1
  87. package/dist/schema/nodes/chimney.d.ts +158 -0
  88. package/dist/schema/nodes/chimney.d.ts.map +1 -0
  89. package/dist/schema/nodes/chimney.js +67 -0
  90. package/dist/schema/nodes/column.d.ts +597 -5
  91. package/dist/schema/nodes/column.d.ts.map +1 -1
  92. package/dist/schema/nodes/column.js +586 -6
  93. package/dist/schema/nodes/cupola.d.ts +66 -0
  94. package/dist/schema/nodes/cupola.d.ts.map +1 -0
  95. package/dist/schema/nodes/cupola.js +28 -0
  96. package/dist/schema/nodes/dormer.d.ts +228 -0
  97. package/dist/schema/nodes/dormer.d.ts.map +1 -0
  98. package/dist/schema/nodes/dormer.js +119 -0
  99. package/dist/schema/nodes/downspout.d.ts +75 -0
  100. package/dist/schema/nodes/downspout.d.ts.map +1 -0
  101. package/dist/schema/nodes/downspout.js +63 -0
  102. package/dist/schema/nodes/elevator.d.ts +105 -0
  103. package/dist/schema/nodes/elevator.d.ts.map +1 -0
  104. package/dist/schema/nodes/elevator.js +54 -0
  105. package/dist/schema/nodes/eyebrow-vent.d.ts +68 -0
  106. package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -0
  107. package/dist/schema/nodes/eyebrow-vent.js +40 -0
  108. package/dist/schema/nodes/fence.d.ts +1 -0
  109. package/dist/schema/nodes/fence.d.ts.map +1 -1
  110. package/dist/schema/nodes/fence.js +2 -0
  111. package/dist/schema/nodes/gutter.d.ts +84 -0
  112. package/dist/schema/nodes/gutter.d.ts.map +1 -0
  113. package/dist/schema/nodes/gutter.js +76 -0
  114. package/dist/schema/nodes/item.d.ts +4 -0
  115. package/dist/schema/nodes/item.d.ts.map +1 -1
  116. package/dist/schema/nodes/item.js +9 -0
  117. package/dist/schema/nodes/level.d.ts +1 -1
  118. package/dist/schema/nodes/level.d.ts.map +1 -1
  119. package/dist/schema/nodes/level.js +2 -0
  120. package/dist/schema/nodes/ridge-vent.d.ts +67 -0
  121. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -0
  122. package/dist/schema/nodes/ridge-vent.js +30 -0
  123. package/dist/schema/nodes/roof-segment.d.ts +195 -1
  124. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  125. package/dist/schema/nodes/roof-segment.js +254 -3
  126. package/dist/schema/nodes/roof.d.ts.map +1 -1
  127. package/dist/schema/nodes/roof.js +4 -16
  128. package/dist/schema/nodes/shelf.d.ts +105 -0
  129. package/dist/schema/nodes/shelf.d.ts.map +1 -0
  130. package/dist/schema/nodes/shelf.js +84 -0
  131. package/dist/schema/nodes/site.d.ts +1 -122
  132. package/dist/schema/nodes/site.d.ts.map +1 -1
  133. package/dist/schema/nodes/site.js +2 -6
  134. package/dist/schema/nodes/skylight.d.ts +279 -0
  135. package/dist/schema/nodes/skylight.d.ts.map +1 -0
  136. package/dist/schema/nodes/skylight.js +152 -0
  137. package/dist/schema/nodes/slab.d.ts +2 -0
  138. package/dist/schema/nodes/slab.d.ts.map +1 -1
  139. package/dist/schema/nodes/slab.js +1 -1
  140. package/dist/schema/nodes/solar-panel.d.ts +117 -0
  141. package/dist/schema/nodes/solar-panel.d.ts.map +1 -0
  142. package/dist/schema/nodes/solar-panel.js +47 -0
  143. package/dist/schema/nodes/surface-hole-metadata.d.ts +2 -0
  144. package/dist/schema/nodes/surface-hole-metadata.d.ts.map +1 -1
  145. package/dist/schema/nodes/surface-hole-metadata.js +3 -1
  146. package/dist/schema/nodes/turbine-vent.d.ts +68 -0
  147. package/dist/schema/nodes/turbine-vent.d.ts.map +1 -0
  148. package/dist/schema/nodes/turbine-vent.js +41 -0
  149. package/dist/schema/types.d.ts +1325 -125
  150. package/dist/schema/types.d.ts.map +1 -1
  151. package/dist/schema/types.js +26 -0
  152. package/dist/services/alignment-anchors.d.ts +100 -0
  153. package/dist/services/alignment-anchors.d.ts.map +1 -0
  154. package/dist/services/alignment-anchors.js +283 -0
  155. package/dist/services/alignment-anchors.test.d.ts +2 -0
  156. package/dist/services/alignment-anchors.test.d.ts.map +1 -0
  157. package/dist/services/alignment-anchors.test.js +383 -0
  158. package/dist/services/alignment.d.ts +126 -0
  159. package/dist/services/alignment.d.ts.map +1 -0
  160. package/dist/services/alignment.js +169 -0
  161. package/dist/services/alignment.test.d.ts +2 -0
  162. package/dist/services/alignment.test.d.ts.map +1 -0
  163. package/dist/services/alignment.test.js +92 -0
  164. package/dist/services/drag-session.d.ts +47 -0
  165. package/dist/services/drag-session.d.ts.map +1 -0
  166. package/dist/services/drag-session.js +100 -0
  167. package/dist/services/drag-session.test.d.ts +2 -0
  168. package/dist/services/drag-session.test.d.ts.map +1 -0
  169. package/dist/services/drag-session.test.js +219 -0
  170. package/dist/services/hosting.d.ts +80 -0
  171. package/dist/services/hosting.d.ts.map +1 -0
  172. package/dist/services/hosting.js +122 -0
  173. package/dist/services/hosting.test.d.ts +2 -0
  174. package/dist/services/hosting.test.d.ts.map +1 -0
  175. package/dist/services/hosting.test.js +199 -0
  176. package/dist/services/index.d.ts +7 -0
  177. package/dist/services/index.d.ts.map +1 -0
  178. package/dist/services/index.js +6 -0
  179. package/dist/services/movement.d.ts +48 -0
  180. package/dist/services/movement.d.ts.map +1 -0
  181. package/dist/services/movement.js +65 -0
  182. package/dist/services/movement.test.d.ts +2 -0
  183. package/dist/services/movement.test.d.ts.map +1 -0
  184. package/dist/services/movement.test.js +133 -0
  185. package/dist/services/single-undo-dance.test.d.ts +2 -0
  186. package/dist/services/single-undo-dance.test.d.ts.map +1 -0
  187. package/dist/services/single-undo-dance.test.js +210 -0
  188. package/dist/services/snap.d.ts +72 -0
  189. package/dist/services/snap.d.ts.map +1 -0
  190. package/dist/services/snap.js +120 -0
  191. package/dist/services/snap.test.d.ts +2 -0
  192. package/dist/services/snap.test.d.ts.map +1 -0
  193. package/dist/services/snap.test.js +95 -0
  194. package/dist/solar-panel-presets.d.ts +17 -0
  195. package/dist/solar-panel-presets.d.ts.map +1 -0
  196. package/dist/solar-panel-presets.js +43 -0
  197. package/dist/store/actions/node-actions.d.ts +14 -2
  198. package/dist/store/actions/node-actions.d.ts.map +1 -1
  199. package/dist/store/actions/node-actions.js +492 -15
  200. package/dist/store/actions/node-mutation-sanitize.test.d.ts +2 -0
  201. package/dist/store/actions/node-mutation-sanitize.test.d.ts.map +1 -0
  202. package/dist/store/actions/node-mutation-sanitize.test.js +147 -0
  203. package/dist/store/actions/reparent.test.d.ts +2 -0
  204. package/dist/store/actions/reparent.test.d.ts.map +1 -0
  205. package/dist/store/actions/reparent.test.js +212 -0
  206. package/dist/store/use-interactive.d.ts +39 -0
  207. package/dist/store/use-interactive.d.ts.map +1 -1
  208. package/dist/store/use-interactive.js +75 -0
  209. package/dist/store/use-live-node-overrides.d.ts +22 -0
  210. package/dist/store/use-live-node-overrides.d.ts.map +1 -0
  211. package/dist/store/use-live-node-overrides.js +59 -0
  212. package/dist/store/use-scene-elevator-migration.test.d.ts +2 -0
  213. package/dist/store/use-scene-elevator-migration.test.d.ts.map +1 -0
  214. package/dist/store/use-scene-elevator-migration.test.js +109 -0
  215. package/dist/store/use-scene.d.ts +11 -0
  216. package/dist/store/use-scene.d.ts.map +1 -1
  217. package/dist/store/use-scene.js +196 -6
  218. package/dist/systems/elevator/elevator-dispatch.d.ts +12 -0
  219. package/dist/systems/elevator/elevator-dispatch.d.ts.map +1 -0
  220. package/dist/systems/elevator/elevator-dispatch.js +57 -0
  221. package/dist/systems/elevator/elevator-geometry.d.ts +15 -0
  222. package/dist/systems/elevator/elevator-geometry.d.ts.map +1 -0
  223. package/dist/systems/elevator/elevator-geometry.js +50 -0
  224. package/dist/systems/elevator/elevator-opening-sync.d.ts +6 -0
  225. package/dist/systems/elevator/elevator-opening-sync.d.ts.map +1 -0
  226. package/dist/systems/elevator/elevator-opening-sync.js +218 -0
  227. package/dist/systems/elevator/elevator-opening-sync.test.d.ts +2 -0
  228. package/dist/systems/elevator/elevator-opening-sync.test.d.ts.map +1 -0
  229. package/dist/systems/elevator/elevator-opening-sync.test.js +146 -0
  230. package/dist/systems/elevator/elevator-opening-system.d.ts +2 -0
  231. package/dist/systems/elevator/elevator-opening-system.d.ts.map +1 -0
  232. package/dist/systems/elevator/elevator-opening-system.js +48 -0
  233. package/dist/systems/elevator/elevator-runtime-system.d.ts +2 -0
  234. package/dist/systems/elevator/elevator-runtime-system.d.ts.map +1 -0
  235. package/dist/systems/elevator/elevator-runtime-system.js +8 -0
  236. package/dist/systems/elevator/elevator-runtime.d.ts +18 -0
  237. package/dist/systems/elevator/elevator-runtime.d.ts.map +1 -0
  238. package/dist/systems/elevator/elevator-runtime.js +225 -0
  239. package/dist/systems/elevator/elevator-runtime.test.d.ts +2 -0
  240. package/dist/systems/elevator/elevator-runtime.test.d.ts.map +1 -0
  241. package/dist/systems/elevator/elevator-runtime.test.js +64 -0
  242. package/dist/systems/elevator/elevator-service.d.ts +19 -0
  243. package/dist/systems/elevator/elevator-service.d.ts.map +1 -0
  244. package/dist/systems/elevator/elevator-service.js +111 -0
  245. package/dist/systems/stair/stair-footprint.d.ts +44 -0
  246. package/dist/systems/stair/stair-footprint.d.ts.map +1 -0
  247. package/dist/systems/stair/stair-footprint.js +168 -0
  248. package/dist/systems/stair/stair-opening-preview.d.ts +1777 -0
  249. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -0
  250. package/dist/systems/stair/stair-opening-preview.js +93 -0
  251. package/dist/systems/stair/stair-opening-preview.test.d.ts +2 -0
  252. package/dist/systems/stair/stair-opening-preview.test.d.ts.map +1 -0
  253. package/dist/systems/stair/stair-opening-preview.test.js +80 -0
  254. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  255. package/dist/systems/stair/stair-opening-sync.js +172 -147
  256. package/dist/systems/stair/stair-opening-sync.test.js +385 -2
  257. package/dist/systems/stair/stair-opening-system.d.ts +2 -0
  258. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -0
  259. package/dist/systems/stair/stair-opening-system.js +104 -0
  260. package/dist/systems/wall/wall-move.d.ts +48 -0
  261. package/dist/systems/wall/wall-move.d.ts.map +1 -0
  262. package/dist/systems/wall/wall-move.js +193 -0
  263. package/dist/utils/clone-scene-graph.d.ts +6 -4
  264. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  265. package/dist/utils/clone-scene-graph.js +6 -4
  266. package/dist/utils/clone-scene-graph.test.d.ts +2 -0
  267. package/dist/utils/clone-scene-graph.test.d.ts.map +1 -0
  268. package/dist/utils/clone-scene-graph.test.js +59 -0
  269. package/dist/validation/validate-build-json.d.ts +43 -0
  270. package/dist/validation/validate-build-json.d.ts.map +1 -0
  271. package/dist/validation/validate-build-json.js +227 -0
  272. package/package.json +9 -2
@@ -0,0 +1,109 @@
1
+ import { beforeEach, describe, expect, test } from 'bun:test';
2
+ import useScene from './use-scene';
3
+ describe('scene elevator migrations', () => {
4
+ beforeEach(() => {
5
+ useScene.setState({
6
+ nodes: {},
7
+ rootNodeIds: [],
8
+ dirtyNodes: new Set(),
9
+ collections: {},
10
+ });
11
+ useScene.temporal.getState().clear();
12
+ });
13
+ test('normalizes legacy level-parented elevators into building-scoped nodes', () => {
14
+ useScene.getState().setScene({
15
+ site_test: {
16
+ object: 'node',
17
+ id: 'site_test',
18
+ type: 'site',
19
+ parentId: null,
20
+ visible: true,
21
+ metadata: {},
22
+ children: ['building_test'],
23
+ },
24
+ building_test: {
25
+ object: 'node',
26
+ id: 'building_test',
27
+ type: 'building',
28
+ parentId: 'site_test',
29
+ visible: true,
30
+ metadata: {},
31
+ children: ['level_test'],
32
+ },
33
+ level_test: {
34
+ object: 'node',
35
+ id: 'level_test',
36
+ type: 'level',
37
+ parentId: 'building_test',
38
+ visible: true,
39
+ metadata: {},
40
+ children: ['elevator_test'],
41
+ level: 0,
42
+ },
43
+ elevator_test: {
44
+ object: 'node',
45
+ id: 'elevator_test',
46
+ type: 'elevator',
47
+ parentId: 'level_test',
48
+ visible: true,
49
+ metadata: {},
50
+ },
51
+ }, ['site_test']);
52
+ const nodes = useScene.getState().nodes;
53
+ const elevator = nodes.elevator_test;
54
+ const level = nodes.level_test;
55
+ const building = nodes.building_test;
56
+ expect(elevator.parentId).toBe('building_test');
57
+ expect(elevator.position).toEqual([0, 0, 0]);
58
+ expect(elevator.rotation).toBe(0);
59
+ expect(level.children).not.toContain('elevator_test');
60
+ expect(building.children).toContain('elevator_test');
61
+ });
62
+ test('migrates level-parented elevators when the level parentId is missing', () => {
63
+ useScene.getState().setScene({
64
+ site_test: {
65
+ object: 'node',
66
+ id: 'site_test',
67
+ type: 'site',
68
+ parentId: null,
69
+ visible: true,
70
+ metadata: {},
71
+ children: ['building_test'],
72
+ },
73
+ building_test: {
74
+ object: 'node',
75
+ id: 'building_test',
76
+ type: 'building',
77
+ parentId: 'site_test',
78
+ visible: true,
79
+ metadata: {},
80
+ children: ['level_test'],
81
+ },
82
+ level_test: {
83
+ object: 'node',
84
+ id: 'level_test',
85
+ type: 'level',
86
+ parentId: null,
87
+ visible: true,
88
+ metadata: {},
89
+ children: ['elevator_test'],
90
+ level: 0,
91
+ },
92
+ elevator_test: {
93
+ object: 'node',
94
+ id: 'elevator_test',
95
+ type: 'elevator',
96
+ parentId: 'level_test',
97
+ visible: true,
98
+ metadata: {},
99
+ },
100
+ }, ['site_test']);
101
+ const nodes = useScene.getState().nodes;
102
+ const elevator = nodes.elevator_test;
103
+ const level = nodes.level_test;
104
+ const building = nodes.building_test;
105
+ expect(elevator.parentId).toBe('building_test');
106
+ expect(level.children).not.toContain('elevator_test');
107
+ expect(building.children).toContain('elevator_test');
108
+ });
109
+ });
@@ -20,6 +20,17 @@ export type SceneState = {
20
20
  node: AnyNode;
21
21
  parentId?: AnyNodeId;
22
22
  }[]) => void;
23
+ applyNodeChanges: (changes: {
24
+ create?: {
25
+ node: AnyNode;
26
+ parentId?: AnyNodeId;
27
+ }[];
28
+ update?: {
29
+ id: AnyNodeId;
30
+ data: Partial<AnyNode>;
31
+ }[];
32
+ delete?: AnyNodeId[];
33
+ }) => void;
23
34
  updateNode: (id: AnyNodeId, data: Partial<AnyNode>) => void;
24
35
  updateNodes: (updates: {
25
36
  id: AnyNodeId;
@@ -1 +1 @@
1
- {"version":3,"file":"use-scene.d.ts","sourceRoot":"","sources":["../../src/store/use-scene.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAE1C,OAAO,EAAU,KAAK,QAAQ,EAAE,KAAK,aAAa,EAAE,MAAM,SAAS,CAAA;AAEnE,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAMrE,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAgZzD,MAAM,MAAM,UAAU,GAAG;IAEvB,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IAGjC,WAAW,EAAE,SAAS,EAAE,CAAA;IAGxB,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAA;IAG1B,WAAW,EAAE,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAA;IAG7C,QAAQ,EAAE,OAAO,CAAA;IACjB,WAAW,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAA;IAGxC,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,UAAU,EAAE,MAAM,IAAI,CAAA;IACtB,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,KAAK,IAAI,CAAA;IAE/E,SAAS,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IAClC,UAAU,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IAEnC,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,SAAS,KAAK,IAAI,CAAA;IACzD,WAAW,EAAE,CAAC,GAAG,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;KAAE,EAAE,KAAK,IAAI,CAAA;IAErE,UAAU,EAAE,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;IAC3D,WAAW,EAAE,CAAC,OAAO,EAAE;QAAE,EAAE,EAAE,SAAS,CAAC;QAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAAE,EAAE,KAAK,IAAI,CAAA;IAE3E,UAAU,EAAE,CAAC,EAAE,EAAE,SAAS,KAAK,IAAI,CAAA;IACnC,WAAW,EAAE,CAAC,GAAG,EAAE,SAAS,EAAE,KAAK,IAAI,CAAA;IAGvC,gBAAgB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,SAAS,EAAE,KAAK,YAAY,CAAA;IACvE,gBAAgB,EAAE,CAAC,EAAE,EAAE,YAAY,KAAK,IAAI,CAAA;IAC5C,gBAAgB,EAAE,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,CAAA;IACnF,eAAe,EAAE,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,KAAK,IAAI,CAAA;IAC9D,oBAAoB,EAAE,CAAC,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,KAAK,IAAI,CAAA;CACpE,CAAA;AAID,KAAK,aAAa,GAAG,aAAa,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,GAAG;IACzD,QAAQ,EAAE,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;CAC7F,CAAA;AAED,QAAA,MAAM,QAAQ,EAAE,aA+Of,CAAA;AAED,eAAe,QAAQ,CAAA;AAOvB,wBAAgB,iBAAiB,SAMhC"}
1
+ {"version":3,"file":"use-scene.d.ts","sourceRoot":"","sources":["../../src/store/use-scene.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,11 @@ import { temporal } from 'zundo';
3
3
  import { create } from 'zustand';
4
4
  import { BuildingNode } from '../schema';
5
5
  import { generateCollectionId } from '../schema/collections';
6
+ import { DoorNode as DoorNodeSchema } from '../schema/nodes/door';
7
+ import { ElevatorNode as ElevatorNodeSchema } from '../schema/nodes/elevator';
6
8
  import { LevelNode } from '../schema/nodes/level';
9
+ import { getPitchFromActiveRoofHeight, } from '../schema/nodes/roof-segment';
10
+ import { ShelfNode as ShelfNodeSchema } from '../schema/nodes/shelf';
7
11
  import { SiteNode } from '../schema/nodes/site';
8
12
  import { StairNode as StairNodeSchema } from '../schema/nodes/stair';
9
13
  import { StairSegmentNode as StairSegmentNodeSchema } from '../schema/nodes/stair-segment';
@@ -12,6 +16,10 @@ import { resetSceneHistoryPauseDepth } from './history-control';
12
16
  function getFiniteNumber(value, fallback) {
13
17
  return typeof value === 'number' && Number.isFinite(value) ? value : fallback;
14
18
  }
19
+ function getFiniteNumberInRange(value, fallback, min, max) {
20
+ const finite = getFiniteNumber(value, fallback);
21
+ return Math.min(Math.max(finite, min), max);
22
+ }
15
23
  function getBoolean(value, fallback) {
16
24
  return typeof value === 'boolean' ? value : fallback;
17
25
  }
@@ -19,7 +27,7 @@ function getEnumValue(value, allowed, fallback) {
19
27
  return typeof value === 'string' && allowed.includes(value) ? value : fallback;
20
28
  }
21
29
  function getNullableString(value) {
22
- return typeof value === 'string' ? value : null;
30
+ return typeof value === 'string' && value.length > 0 ? value : null;
23
31
  }
24
32
  function getStringArray(value) {
25
33
  return Array.isArray(value)
@@ -81,6 +89,99 @@ function normalizeStairSegmentNode(node) {
81
89
  const parsed = StairSegmentNodeSchema.safeParse(sanitized);
82
90
  return parsed.success ? parsed.data : null;
83
91
  }
92
+ function normalizeDoorNode(node) {
93
+ const parsed = DoorNodeSchema.safeParse(node);
94
+ return parsed.success ? { ...node, ...parsed.data } : null;
95
+ }
96
+ function normalizeShelfNode(node) {
97
+ const sanitized = {
98
+ ...node,
99
+ children: getStringArray(node.children),
100
+ position: getVector3(node.position, [0, 0, 0]),
101
+ rotation: getVector3(node.rotation, [0, 0, 0]),
102
+ width: getFiniteNumberInRange(node.width, 1.2, 0.3, 3.0),
103
+ depth: getFiniteNumberInRange(node.depth, 0.3, 0.1, 1.0),
104
+ thickness: getFiniteNumberInRange(node.thickness, 0.04, 0.01, 0.1),
105
+ height: getFiniteNumberInRange(node.height, 0.9, 0.05, 2.5),
106
+ rows: Math.round(getFiniteNumberInRange(node.rows, 1, 1, 8)),
107
+ columns: Math.round(getFiniteNumberInRange(node.columns, 1, 1, 6)),
108
+ style: getEnumValue(node.style, ['wall-shelf', 'bookshelf', 'open-rack', 'cubby'], 'wall-shelf'),
109
+ withBack: getBoolean(node.withBack, false),
110
+ withSides: getBoolean(node.withSides, true),
111
+ withBottom: getBoolean(node.withBottom, false),
112
+ bracketStyle: getEnumValue(node.bracketStyle, ['minimal', 'industrial', 'hidden'], 'minimal'),
113
+ };
114
+ const parsed = ShelfNodeSchema.safeParse(sanitized);
115
+ return parsed.success ? parsed.data : null;
116
+ }
117
+ function normalizeElevatorNode(node) {
118
+ const sanitized = {
119
+ ...node,
120
+ position: getVector3(node.position, [0, 0, 0]),
121
+ rotation: getFiniteNumber(node.rotation, 0),
122
+ width: getFiniteNumber(node.width, 1.84),
123
+ depth: getFiniteNumber(node.depth, 1.84),
124
+ shaftWidth: node.shaftWidth === undefined ? undefined : getFiniteNumber(node.shaftWidth, 1.84),
125
+ shaftDepth: node.shaftDepth === undefined ? undefined : getFiniteNumber(node.shaftDepth, 1.84),
126
+ shaftWallThickness: getFiniteNumber(node.shaftWallThickness, 0.09),
127
+ cabHeight: getFiniteNumber(node.cabHeight, 2.35),
128
+ doorWidth: getFiniteNumber(node.doorWidth, 0.95),
129
+ doorHeight: getFiniteNumber(node.doorHeight, 2.1),
130
+ fromLevelId: getNullableString(node.fromLevelId),
131
+ toLevelId: getNullableString(node.toLevelId),
132
+ servedLevelIds: node.servedLevelIds === undefined ? undefined : getStringArray(node.servedLevelIds),
133
+ disabledLevelIds: getStringArray(node.disabledLevelIds),
134
+ serviceOnlyLevelIds: getStringArray(node.serviceOnlyLevelIds),
135
+ defaultLevelId: getNullableString(node.defaultLevelId),
136
+ speed: getFiniteNumber(node.speed, 2.2),
137
+ doorDurationMs: getFiniteNumber(node.doorDurationMs, 900),
138
+ dwellMs: getFiniteNumber(node.dwellMs, 1400),
139
+ };
140
+ const parsed = ElevatorNodeSchema.safeParse(sanitized);
141
+ return parsed.success ? parsed.data : null;
142
+ }
143
+ function findBuildingIdForLevel(levelId, nodes) {
144
+ const level = nodes[levelId];
145
+ const directBuildingId = typeof level?.parentId === 'string' ? level.parentId : null;
146
+ if (directBuildingId && nodes[directBuildingId]?.type === 'building') {
147
+ return directBuildingId;
148
+ }
149
+ for (const [candidateId, candidate] of Object.entries(nodes)) {
150
+ if (candidate?.type !== 'building')
151
+ continue;
152
+ if (getStringArray(candidate.children).includes(levelId)) {
153
+ return candidateId;
154
+ }
155
+ }
156
+ return null;
157
+ }
158
+ function migrateElevatorParent(id, node, nodes) {
159
+ const parentId = typeof node.parentId === 'string' ? node.parentId : null;
160
+ if (!parentId)
161
+ return node;
162
+ const parent = parentId ? nodes[parentId] : null;
163
+ if (parent?.type !== 'level')
164
+ return node;
165
+ const buildingId = findBuildingIdForLevel(parentId, nodes);
166
+ if (!buildingId)
167
+ return node;
168
+ const building = buildingId ? nodes[buildingId] : null;
169
+ if (building?.type !== 'building')
170
+ return node;
171
+ nodes[parentId] = {
172
+ ...parent,
173
+ children: getStringArray(parent.children).filter((childId) => childId !== id),
174
+ };
175
+ const buildingChildren = getStringArray(building.children);
176
+ nodes[buildingId] = {
177
+ ...building,
178
+ children: buildingChildren.includes(id) ? buildingChildren : [...buildingChildren, id],
179
+ };
180
+ return {
181
+ ...node,
182
+ parentId: buildingId,
183
+ };
184
+ }
84
185
  function migrateWallSurfaceMaterials(node) {
85
186
  const hasInterior = node.interiorMaterial !== undefined || typeof node.interiorMaterialPreset === 'string';
86
187
  const hasExterior = node.exteriorMaterial !== undefined || typeof node.exteriorMaterialPreset === 'string';
@@ -244,6 +345,9 @@ function migrateNodes(nodes) {
244
345
  const oldRoof = node;
245
346
  const suffix = id.includes('_') ? id.split('_')[1] : Math.random().toString(36).slice(2);
246
347
  const segmentId = `rseg_${suffix}`;
348
+ const segWidth = oldRoof.length ?? 8;
349
+ const segDepth = (oldRoof.leftWidth ?? 2.2) + (oldRoof.rightWidth ?? 2.2);
350
+ const legacyRoofHeight = oldRoof.height ?? 2.5;
247
351
  const segment = {
248
352
  object: 'node',
249
353
  id: segmentId,
@@ -254,10 +358,18 @@ function migrateNodes(nodes) {
254
358
  position: [0, 0, 0],
255
359
  rotation: 0,
256
360
  roofType: 'gable',
257
- width: oldRoof.length ?? 8,
258
- depth: (oldRoof.leftWidth ?? 2.2) + (oldRoof.rightWidth ?? 2.2),
259
- wallHeight: 0,
260
- roofHeight: oldRoof.height ?? 2.5,
361
+ width: segWidth,
362
+ depth: segDepth,
363
+ // Schema default (0.5), NOT 0: a zero-height wall builds a flat,
364
+ // degenerate CSG brush → "Coplanar clip not handled" + NaN geometry, so
365
+ // the migrated legacy roof never renders. New roofs use 0.5 too.
366
+ wallHeight: 0.5,
367
+ pitch: getPitchFromActiveRoofHeight({
368
+ roofType: 'gable',
369
+ width: segWidth,
370
+ depth: segDepth,
371
+ roofHeight: legacyRoofHeight,
372
+ }),
261
373
  wallThickness: 0.1,
262
374
  deckThickness: 0.1,
263
375
  overhang: 0.3,
@@ -269,6 +381,35 @@ function migrateNodes(nodes) {
269
381
  children: [segmentId],
270
382
  };
271
383
  }
384
+ // 2b. roof-segment: guarantee a valid positive pitch (degrees).
385
+ // Saved scenes wrote `roofHeight` in metres; the schema now stores `pitch`
386
+ // in degrees. Convert the legacy field when present, and — crucially — fall
387
+ // back to the schema default for any segment that carries no usable pitch or
388
+ // roofHeight (older/partial saves). Without this, the slope-frame guard
389
+ // resolves a missing pitch to a FLAT frame, so the roof renders as a slab.
390
+ // The migration result is cast, not zod-parsed, so the schema default never
391
+ // applies on its own — this branch is the only place it lands.
392
+ if (node.type === 'roof-segment') {
393
+ const currentPitch = node.pitch;
394
+ const hasValidPitch = typeof currentPitch === 'number' && currentPitch > 0;
395
+ if (!hasValidPitch) {
396
+ const { roofHeight, ...rest } = node;
397
+ const width = typeof node.width === 'number' ? node.width : 8;
398
+ const depth = typeof node.depth === 'number' ? node.depth : 6;
399
+ const roofType = (typeof node.roofType === 'string' ? node.roofType : 'gable');
400
+ const derived = typeof roofHeight === 'number' && roofHeight > 0
401
+ ? getPitchFromActiveRoofHeight({ roofType, width, depth, roofHeight })
402
+ : 0;
403
+ // 40° matches the RoofSegmentNode schema default.
404
+ patchedNodes[id] = { ...rest, pitch: derived > 0 ? derived : 40 };
405
+ }
406
+ }
407
+ if (node.type === 'door') {
408
+ const normalized = normalizeDoorNode(node);
409
+ if (normalized) {
410
+ patchedNodes[id] = normalized;
411
+ }
412
+ }
272
413
  if (node.type === 'stair') {
273
414
  const normalized = normalizeStairNode(migrateStairSurfaceMaterials(node));
274
415
  if (normalized) {
@@ -284,9 +425,57 @@ function migrateNodes(nodes) {
284
425
  if (node.type === 'wall') {
285
426
  patchedNodes[id] = migrateWallSurfaceMaterials(patchedNodes[id]);
286
427
  }
428
+ if (node.type === 'shelf') {
429
+ const normalized = normalizeShelfNode(node);
430
+ if (normalized) {
431
+ patchedNodes[id] = normalized;
432
+ }
433
+ }
434
+ if (node.type === 'elevator') {
435
+ const parentMigrated = migrateElevatorParent(id, node, patchedNodes);
436
+ const normalized = normalizeElevatorNode(parentMigrated);
437
+ if (normalized) {
438
+ patchedNodes[id] = normalized;
439
+ }
440
+ }
441
+ // Roof-segment hosting was added in this migration cycle (the same
442
+ // pattern as shelf above). Older segments saved before the schema
443
+ // gained `children` need the field initialised so
444
+ // `createNode(chimney, segmentId)` finds an array to append to —
445
+ // without this every "Add Element" click on the roof panel results
446
+ // in an orphaned accessory (parented in scene state but never
447
+ // appended to `seg.children`, so the renderer's recursive
448
+ // `<NodeRenderer>` mount never sees it).
449
+ if (node.type === 'roof-segment' && !Array.isArray(node.children)) {
450
+ patchedNodes[id] = { ...node, children: [] };
451
+ }
287
452
  if (node.type === 'roof') {
288
453
  patchedNodes[id] = migrateRoofSurfaceMaterials(patchedNodes[id]);
289
454
  }
455
+ // Legacy: site.children used to hold nested BuildingNode / ItemNode
456
+ // objects (see the SiteNode schema before the children-as-ids fix).
457
+ // Flatten any leftover nested children into ids, and absorb the
458
+ // embedded nodes into the flat map so the rest of the loader can
459
+ // treat the site like every other parent.
460
+ if (node.type === 'site' && Array.isArray(node.children)) {
461
+ let needsFlatten = false;
462
+ const flattened = [];
463
+ for (const child of node.children) {
464
+ if (typeof child === 'string') {
465
+ flattened.push(child);
466
+ }
467
+ else if (child && typeof child === 'object' && typeof child.id === 'string') {
468
+ needsFlatten = true;
469
+ flattened.push(child.id);
470
+ if (!patchedNodes[child.id]) {
471
+ patchedNodes[child.id] = { ...child, parentId: id };
472
+ }
473
+ }
474
+ }
475
+ if (needsFlatten) {
476
+ patchedNodes[id] = { ...node, children: flattened };
477
+ }
478
+ }
290
479
  }
291
480
  return patchedNodes;
292
481
  }
@@ -417,7 +606,7 @@ const useScene = create()(temporal((set, get) => ({
417
606
  children: [level0.id],
418
607
  });
419
608
  const site = SiteNode.parse({
420
- children: [building],
609
+ children: [building.id],
421
610
  });
422
611
  // Define all nodes flat
423
612
  const nodes = {
@@ -437,6 +626,7 @@ const useScene = create()(temporal((set, get) => ({
437
626
  },
438
627
  createNodes: (ops) => nodeActions.createNodesAction(set, get, ops),
439
628
  createNode: (node, parentId) => nodeActions.createNodesAction(set, get, [{ node, parentId }]),
629
+ applyNodeChanges: (changes) => nodeActions.applyNodeChangesAction(set, get, changes),
440
630
  updateNodes: (updates) => nodeActions.updateNodesAction(set, get, updates),
441
631
  updateNode: (id, data) => nodeActions.updateNodesAction(set, get, [{ id, data }]),
442
632
  // --- DELETE ---
@@ -0,0 +1,12 @@
1
+ import type { AnyNode, AnyNodeId } from '../../schema';
2
+ import type { ElevatorInteractiveState } from '../../store/use-interactive';
3
+ type ElevatorRuntimeMap = Record<AnyNodeId, ElevatorInteractiveState>;
4
+ type ResolveElevatorDispatchTargetArgs = {
5
+ elevators: ElevatorRuntimeMap;
6
+ levelId: AnyNodeId;
7
+ nodes: Record<string, AnyNode>;
8
+ requestedElevatorId: AnyNodeId;
9
+ };
10
+ export declare function resolveElevatorDispatchTarget({ elevators, levelId, nodes, requestedElevatorId, }: ResolveElevatorDispatchTargetArgs): AnyNodeId;
11
+ export {};
12
+ //# sourceMappingURL=elevator-dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevator-dispatch.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-dispatch.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAgB,MAAM,cAAc,CAAA;AACpE,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AAG3E,KAAK,kBAAkB,GAAG,MAAM,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAA;AAErE,KAAK,iCAAiC,GAAG;IACvC,SAAS,EAAE,kBAAkB,CAAA;IAC7B,OAAO,EAAE,SAAS,CAAA;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,mBAAmB,EAAE,SAAS,CAAA;CAC/B,CAAA;AAsCD,wBAAgB,6BAA6B,CAAC,EAC5C,SAAS,EACT,OAAO,EACP,KAAK,EACL,mBAAmB,GACpB,EAAE,iCAAiC,GAAG,SAAS,CAmC/C"}
@@ -0,0 +1,57 @@
1
+ import { resolveElevatorServiceLevels } from './elevator-service';
2
+ function getRuntimeLevelId(runtime, elevator) {
3
+ return runtime?.currentLevelId ?? elevator.defaultLevelId ?? elevator.fromLevelId ?? null;
4
+ }
5
+ function scoreDispatchCandidate({ elevator, elevators, levelId, nodes, }) {
6
+ if ((elevator.disabledLevelIds ?? []).includes(levelId))
7
+ return null;
8
+ if ((elevator.serviceOnlyLevelIds ?? []).includes(levelId))
9
+ return null;
10
+ const serviceLevels = resolveElevatorServiceLevels(elevator, nodes);
11
+ const targetIndex = serviceLevels.findIndex((level) => level.id === levelId);
12
+ if (targetIndex < 0)
13
+ return null;
14
+ const runtime = elevators[elevator.id];
15
+ const runtimeLevelId = getRuntimeLevelId(runtime, elevator);
16
+ const currentIndex = runtimeLevelId
17
+ ? serviceLevels.findIndex((level) => level.id === runtimeLevelId)
18
+ : -1;
19
+ const resolvedCurrentIndex = currentIndex >= 0 ? currentIndex : 0;
20
+ const distance = Math.abs(targetIndex - resolvedCurrentIndex);
21
+ const queuePenalty = (runtime?.queue.length ?? 0) * 2 + (runtime?.targetLevelId ? 1 : 0);
22
+ const motionPenalty = runtime?.phase === 'moving' || runtime?.phase === 'closing' ? 0.5 : 0;
23
+ const openPenalty = runtime?.phase === 'open' || runtime?.phase === 'opening' ? 0.2 : 0;
24
+ return distance + queuePenalty + motionPenalty + openPenalty;
25
+ }
26
+ export function resolveElevatorDispatchTarget({ elevators, levelId, nodes, requestedElevatorId, }) {
27
+ const requestedElevator = nodes[requestedElevatorId];
28
+ if (!(requestedElevator?.type === 'elevator' && requestedElevator.parentId)) {
29
+ return requestedElevatorId;
30
+ }
31
+ const building = nodes[requestedElevator.parentId];
32
+ if (building?.type !== 'building') {
33
+ return requestedElevatorId;
34
+ }
35
+ let bestElevatorId = null;
36
+ let bestScore = Number.POSITIVE_INFINITY;
37
+ for (const childId of building.children) {
38
+ const candidate = nodes[childId];
39
+ if (!(candidate?.type === 'elevator' && candidate.visible !== false))
40
+ continue;
41
+ const score = scoreDispatchCandidate({
42
+ elevator: candidate,
43
+ elevators,
44
+ levelId,
45
+ nodes,
46
+ });
47
+ if (score === null)
48
+ continue;
49
+ const tieBreaker = candidate.id === requestedElevatorId ? -0.01 : 0;
50
+ const finalScore = score + tieBreaker;
51
+ if (finalScore < bestScore) {
52
+ bestScore = finalScore;
53
+ bestElevatorId = candidate.id;
54
+ }
55
+ }
56
+ return bestElevatorId ?? requestedElevatorId;
57
+ }
@@ -0,0 +1,15 @@
1
+ import type { ElevatorDoorPanelStyle, ElevatorDoorStyle, ElevatorNode, ElevatorShaftStyle } from '../../schema';
2
+ export type ElevatorDoorSide = 'left' | 'right';
3
+ export declare function getResolvedElevatorDoorStyle(doorStyle: ElevatorNode['doorStyle'] | undefined): ElevatorDoorStyle;
4
+ export declare function getResolvedElevatorDoorPanelStyle(doorPanelStyle: ElevatorNode['doorPanelStyle'] | undefined): ElevatorDoorPanelStyle;
5
+ export declare function getResolvedElevatorShaftStyle(shaftStyle: ElevatorNode['shaftStyle'] | undefined): ElevatorShaftStyle;
6
+ export declare function getElevatorDoorLeafSides(doorStyle: ElevatorNode['doorStyle'] | undefined): ElevatorDoorSide[];
7
+ export declare function getElevatorDoorLeafX(side: ElevatorDoorSide, openingWidth: number, doorOpen: number, doorStyle: ElevatorNode['doorStyle'] | undefined): number;
8
+ export declare function getElevatorDoorLeafWidth(openingWidth: number, doorStyle: ElevatorNode['doorStyle'] | undefined): number;
9
+ export declare function getElevatorCabWidth(node: ElevatorNode): number;
10
+ export declare function getElevatorCabDepth(node: ElevatorNode): number;
11
+ export declare function getElevatorShaftWallThickness(node: ElevatorNode): number;
12
+ export declare function getElevatorShaftWidth(node: ElevatorNode, cabWidth?: number): number;
13
+ export declare function getElevatorShaftDepth(node: ElevatorNode, cabDepth?: number): number;
14
+ export declare function getElevatorCabCenterZ(node: ElevatorNode): number;
15
+ //# sourceMappingURL=elevator-geometry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevator-geometry.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-geometry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,iBAAiB,EACjB,YAAY,EACZ,kBAAkB,EACnB,MAAM,cAAc,CAAA;AAErB,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,CAAA;AAI/C,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,GAC/C,iBAAiB,CAEnB;AAED,wBAAgB,iCAAiC,CAC/C,cAAc,EAAE,YAAY,CAAC,gBAAgB,CAAC,GAAG,SAAS,GACzD,sBAAsB,CAExB;AAED,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,YAAY,CAAC,YAAY,CAAC,GAAG,SAAS,GACjD,kBAAkB,CAEpB;AAED,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,GAC/C,gBAAgB,EAAE,CAKpB;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,gBAAgB,EACtB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,UAUjD;AAED,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,SAAS,UAKjD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,UAErD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,YAAY,UAErD;AAED,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,YAAY,UAE/D;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,SAA4B,UAE7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,EAAE,QAAQ,SAA4B,UAE7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,YAAY,UAEvD"}
@@ -0,0 +1,50 @@
1
+ const DEFAULT_ELEVATOR_SHAFT_WALL_THICKNESS = 0.09;
2
+ export function getResolvedElevatorDoorStyle(doorStyle) {
3
+ return doorStyle ?? 'center-opening';
4
+ }
5
+ export function getResolvedElevatorDoorPanelStyle(doorPanelStyle) {
6
+ return doorPanelStyle ?? 'glass-frame';
7
+ }
8
+ export function getResolvedElevatorShaftStyle(shaftStyle) {
9
+ return shaftStyle ?? 'solid';
10
+ }
11
+ export function getElevatorDoorLeafSides(doorStyle) {
12
+ const resolvedDoorStyle = getResolvedElevatorDoorStyle(doorStyle);
13
+ if (resolvedDoorStyle === 'single-left')
14
+ return ['left'];
15
+ if (resolvedDoorStyle === 'single-right')
16
+ return ['right'];
17
+ return ['left', 'right'];
18
+ }
19
+ export function getElevatorDoorLeafX(side, openingWidth, doorOpen, doorStyle) {
20
+ const resolvedDoorStyle = getResolvedElevatorDoorStyle(doorStyle);
21
+ if (resolvedDoorStyle === 'center-opening') {
22
+ const direction = side === 'left' ? -1 : 1;
23
+ return direction * (openingWidth / 4 + doorOpen * openingWidth * 0.34);
24
+ }
25
+ const direction = resolvedDoorStyle === 'single-left' ? -1 : 1;
26
+ return direction * doorOpen * openingWidth * 0.68;
27
+ }
28
+ export function getElevatorDoorLeafWidth(openingWidth, doorStyle) {
29
+ return getResolvedElevatorDoorStyle(doorStyle) === 'center-opening'
30
+ ? Math.max(openingWidth / 2 - 0.018, 0.12)
31
+ : Math.max(openingWidth - 0.018, 0.18);
32
+ }
33
+ export function getElevatorCabWidth(node) {
34
+ return Math.max(node.width, 0.8);
35
+ }
36
+ export function getElevatorCabDepth(node) {
37
+ return Math.max(node.depth, 0.8);
38
+ }
39
+ export function getElevatorShaftWallThickness(node) {
40
+ return Math.max(node.shaftWallThickness ?? DEFAULT_ELEVATOR_SHAFT_WALL_THICKNESS, 0.04);
41
+ }
42
+ export function getElevatorShaftWidth(node, cabWidth = getElevatorCabWidth(node)) {
43
+ return Math.max(node.shaftWidth ?? cabWidth, cabWidth, 0.8);
44
+ }
45
+ export function getElevatorShaftDepth(node, cabDepth = getElevatorCabDepth(node)) {
46
+ return Math.max(node.shaftDepth ?? cabDepth, cabDepth, 0.8);
47
+ }
48
+ export function getElevatorCabCenterZ(node) {
49
+ return -getElevatorShaftDepth(node) / 2 + getElevatorCabDepth(node) / 2;
50
+ }
@@ -0,0 +1,6 @@
1
+ import type { AnyNode, AnyNodeId, CeilingNode, SlabNode } from '../../schema';
2
+ export declare function syncAutoElevatorOpenings(nodes: Record<string, AnyNode>): {
3
+ id: AnyNodeId;
4
+ data: Partial<SlabNode | CeilingNode>;
5
+ }[];
6
+ //# sourceMappingURL=elevator-opening-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevator-opening-sync.d.ts","sourceRoot":"","sources":["../../../src/systems/elevator/elevator-opening-sync.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,OAAO,EACP,SAAS,EACT,WAAW,EAEX,QAAQ,EAET,MAAM,cAAc,CAAA;AA8JrB,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;QAQ1C,SAAS;UAAQ,OAAO,CAAC,QAAQ,GAAG,WAAW,CAAC;IAmG5E"}