@pascal-app/core 0.9.1 → 0.9.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 (321) hide show
  1. package/dist/events/bus.d.ts +30 -2
  2. package/dist/events/bus.d.ts.map +1 -1
  3. package/dist/hooks/scene-registry/item-clip-registry.d.ts +18 -0
  4. package/dist/hooks/scene-registry/item-clip-registry.d.ts.map +1 -0
  5. package/dist/hooks/scene-registry/item-clip-registry.js +10 -0
  6. package/dist/hooks/scene-registry/scene-registry.d.ts +8 -1
  7. package/dist/hooks/scene-registry/scene-registry.d.ts.map +1 -1
  8. package/dist/hooks/scene-registry/scene-registry.js +27 -1
  9. package/dist/hooks/scene-registry/scene-registry.test.d.ts +2 -0
  10. package/dist/hooks/scene-registry/scene-registry.test.d.ts.map +1 -0
  11. package/dist/hooks/scene-registry/scene-registry.test.js +26 -0
  12. package/dist/hooks/spatial-grid/floor-placed-elevation.test.js +93 -0
  13. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts +69 -12
  14. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  15. package/dist/hooks/spatial-grid/spatial-grid-manager.js +476 -195
  16. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  17. package/dist/hooks/spatial-grid/spatial-grid-sync.js +19 -1
  18. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts +2 -0
  19. package/dist/hooks/spatial-grid/wall-slab-overlap.test.d.ts.map +1 -0
  20. package/dist/hooks/spatial-grid/wall-slab-overlap.test.js +363 -0
  21. package/dist/index.d.ts +16 -6
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +15 -5
  24. package/dist/lib/level-name.d.ts +4 -0
  25. package/dist/lib/level-name.d.ts.map +1 -0
  26. package/dist/lib/level-name.js +10 -0
  27. package/dist/lib/measurement-geometry.d.ts +19 -0
  28. package/dist/lib/measurement-geometry.d.ts.map +1 -0
  29. package/dist/lib/measurement-geometry.js +232 -0
  30. package/dist/lib/measurement-geometry.test.d.ts +2 -0
  31. package/dist/lib/measurement-geometry.test.d.ts.map +1 -0
  32. package/dist/lib/measurement-geometry.test.js +102 -0
  33. package/dist/lib/polygon-geometry.d.ts +0 -1
  34. package/dist/lib/polygon-geometry.d.ts.map +1 -1
  35. package/dist/lib/polygon-geometry.js +0 -18
  36. package/dist/lib/selection-proxy.d.ts +4 -0
  37. package/dist/lib/selection-proxy.d.ts.map +1 -0
  38. package/dist/lib/selection-proxy.js +12 -0
  39. package/dist/lib/slab-polygon.d.ts +31 -2
  40. package/dist/lib/slab-polygon.d.ts.map +1 -1
  41. package/dist/lib/slab-polygon.js +525 -31
  42. package/dist/lib/slab-polygon.test.d.ts +2 -0
  43. package/dist/lib/slab-polygon.test.d.ts.map +1 -0
  44. package/dist/lib/slab-polygon.test.js +635 -0
  45. package/dist/lib/slots.d.ts +14 -0
  46. package/dist/lib/slots.d.ts.map +1 -0
  47. package/dist/lib/slots.js +26 -0
  48. package/dist/lib/space-detection.d.ts +25 -2
  49. package/dist/lib/space-detection.d.ts.map +1 -1
  50. package/dist/lib/space-detection.js +414 -118
  51. package/dist/lib/space-detection.test.js +301 -2
  52. package/dist/lib/wall-distance.d.ts +60 -0
  53. package/dist/lib/wall-distance.d.ts.map +1 -0
  54. package/dist/lib/wall-distance.js +85 -0
  55. package/dist/lib/zone-quantities.d.ts +21 -0
  56. package/dist/lib/zone-quantities.d.ts.map +1 -0
  57. package/dist/lib/zone-quantities.js +183 -0
  58. package/dist/lib/zone-quantities.test.d.ts +2 -0
  59. package/dist/lib/zone-quantities.test.d.ts.map +1 -0
  60. package/dist/lib/zone-quantities.test.js +82 -0
  61. package/dist/material-library.d.ts +20 -1
  62. package/dist/material-library.d.ts.map +1 -1
  63. package/dist/material-library.js +2181 -441
  64. package/dist/registry/handles.d.ts +75 -2
  65. package/dist/registry/handles.d.ts.map +1 -1
  66. package/dist/registry/index.d.ts +3 -3
  67. package/dist/registry/index.d.ts.map +1 -1
  68. package/dist/registry/index.js +1 -1
  69. package/dist/registry/registry.d.ts +46 -3
  70. package/dist/registry/registry.d.ts.map +1 -1
  71. package/dist/registry/registry.js +82 -1
  72. package/dist/registry/registry.test.js +14 -1
  73. package/dist/registry/subtree.d.ts.map +1 -1
  74. package/dist/registry/subtree.js +4 -0
  75. package/dist/registry/subtree.test.js +30 -0
  76. package/dist/registry/types.d.ts +717 -38
  77. package/dist/registry/types.d.ts.map +1 -1
  78. package/dist/schema/index.d.ts +21 -5
  79. package/dist/schema/index.d.ts.map +1 -1
  80. package/dist/schema/index.js +17 -3
  81. package/dist/schema/material.d.ts +3 -2
  82. package/dist/schema/material.d.ts.map +1 -1
  83. package/dist/schema/material.js +7 -5
  84. package/dist/schema/material.test.d.ts +2 -0
  85. package/dist/schema/material.test.d.ts.map +1 -0
  86. package/dist/schema/material.test.js +43 -0
  87. package/dist/schema/nodes/box-vent.d.ts +2 -2
  88. package/dist/schema/nodes/cabinet.d.ts +534 -0
  89. package/dist/schema/nodes/cabinet.d.ts.map +1 -0
  90. package/dist/schema/nodes/cabinet.js +137 -0
  91. package/dist/schema/nodes/ceiling.d.ts +3 -2
  92. package/dist/schema/nodes/ceiling.d.ts.map +1 -1
  93. package/dist/schema/nodes/ceiling.js +4 -0
  94. package/dist/schema/nodes/chimney.d.ts +4 -4
  95. package/dist/schema/nodes/column.d.ts +3 -2
  96. package/dist/schema/nodes/column.d.ts.map +1 -1
  97. package/dist/schema/nodes/column.js +3 -0
  98. package/dist/schema/nodes/cupola.d.ts +2 -2
  99. package/dist/schema/nodes/door.d.ts +13 -5
  100. package/dist/schema/nodes/door.d.ts.map +1 -1
  101. package/dist/schema/nodes/door.js +12 -0
  102. package/dist/schema/nodes/dormer.d.ts +8 -8
  103. package/dist/schema/nodes/dormer.js +1 -1
  104. package/dist/schema/nodes/downspout.d.ts +2 -2
  105. package/dist/schema/nodes/duct-fitting.d.ts +91 -0
  106. package/dist/schema/nodes/duct-fitting.d.ts.map +1 -0
  107. package/dist/schema/nodes/duct-fitting.js +92 -0
  108. package/dist/schema/nodes/duct-segment.d.ts +61 -0
  109. package/dist/schema/nodes/duct-segment.d.ts.map +1 -0
  110. package/dist/schema/nodes/duct-segment.js +73 -0
  111. package/dist/schema/nodes/duct-terminal.d.ts +57 -0
  112. package/dist/schema/nodes/duct-terminal.d.ts.map +1 -0
  113. package/dist/schema/nodes/duct-terminal.js +51 -0
  114. package/dist/schema/nodes/elevator.d.ts +3 -2
  115. package/dist/schema/nodes/elevator.d.ts.map +1 -1
  116. package/dist/schema/nodes/elevator.js +3 -0
  117. package/dist/schema/nodes/eyebrow-vent.d.ts +2 -2
  118. package/dist/schema/nodes/fence.d.ts +18 -2
  119. package/dist/schema/nodes/fence.d.ts.map +1 -1
  120. package/dist/schema/nodes/fence.js +25 -2
  121. package/dist/schema/nodes/gutter.d.ts +2 -2
  122. package/dist/schema/nodes/hvac-equipment.d.ts +63 -0
  123. package/dist/schema/nodes/hvac-equipment.d.ts.map +1 -0
  124. package/dist/schema/nodes/hvac-equipment.js +55 -0
  125. package/dist/schema/nodes/item.d.ts +8 -0
  126. package/dist/schema/nodes/item.d.ts.map +1 -1
  127. package/dist/schema/nodes/item.js +11 -0
  128. package/dist/schema/nodes/level.d.ts +1 -1
  129. package/dist/schema/nodes/level.d.ts.map +1 -1
  130. package/dist/schema/nodes/level.js +2 -0
  131. package/dist/schema/nodes/lineset.d.ts +42 -0
  132. package/dist/schema/nodes/lineset.d.ts.map +1 -0
  133. package/dist/schema/nodes/lineset.js +38 -0
  134. package/dist/schema/nodes/liquid-line.d.ts +34 -0
  135. package/dist/schema/nodes/liquid-line.d.ts.map +1 -0
  136. package/dist/schema/nodes/liquid-line.js +24 -0
  137. package/dist/schema/nodes/measurement.d.ts +306 -0
  138. package/dist/schema/nodes/measurement.d.ts.map +1 -0
  139. package/dist/schema/nodes/measurement.js +87 -0
  140. package/dist/schema/nodes/measurement.test.d.ts +2 -0
  141. package/dist/schema/nodes/measurement.test.d.ts.map +1 -0
  142. package/dist/schema/nodes/measurement.test.js +139 -0
  143. package/dist/schema/nodes/pipe-fitting.d.ts +56 -0
  144. package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -0
  145. package/dist/schema/nodes/pipe-fitting.js +45 -0
  146. package/dist/schema/nodes/pipe-segment.d.ts +48 -0
  147. package/dist/schema/nodes/pipe-segment.d.ts.map +1 -0
  148. package/dist/schema/nodes/pipe-segment.js +36 -0
  149. package/dist/schema/nodes/pipe-trap.d.ts +43 -0
  150. package/dist/schema/nodes/pipe-trap.d.ts.map +1 -0
  151. package/dist/schema/nodes/pipe-trap.js +36 -0
  152. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts +2 -0
  153. package/dist/schema/nodes/ridge-vent-defaults.test.d.ts.map +1 -0
  154. package/dist/schema/nodes/ridge-vent-defaults.test.js +205 -0
  155. package/dist/schema/nodes/ridge-vent.d.ts +18 -3
  156. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
  157. package/dist/schema/nodes/ridge-vent.js +221 -3
  158. package/dist/schema/nodes/roof-segment-shape.d.ts +90 -0
  159. package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -0
  160. package/dist/schema/nodes/roof-segment-shape.js +318 -0
  161. package/dist/schema/nodes/roof-segment-shape.test.d.ts +2 -0
  162. package/dist/schema/nodes/roof-segment-shape.test.d.ts.map +1 -0
  163. package/dist/schema/nodes/roof-segment-shape.test.js +175 -0
  164. package/dist/schema/nodes/roof-segment-surface.test.d.ts +2 -0
  165. package/dist/schema/nodes/roof-segment-surface.test.d.ts.map +1 -0
  166. package/dist/schema/nodes/roof-segment-surface.test.js +48 -0
  167. package/dist/schema/nodes/roof-segment-trim.test.d.ts +2 -0
  168. package/dist/schema/nodes/roof-segment-trim.test.d.ts.map +1 -0
  169. package/dist/schema/nodes/roof-segment-trim.test.js +107 -0
  170. package/dist/schema/nodes/roof-segment-walls.d.ts +101 -0
  171. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -0
  172. package/dist/schema/nodes/roof-segment-walls.js +330 -0
  173. package/dist/schema/nodes/roof-segment-walls.test.d.ts +2 -0
  174. package/dist/schema/nodes/roof-segment-walls.test.d.ts.map +1 -0
  175. package/dist/schema/nodes/roof-segment-walls.test.js +92 -0
  176. package/dist/schema/nodes/roof-segment.d.ts +84 -8
  177. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  178. package/dist/schema/nodes/roof-segment.js +290 -5
  179. package/dist/schema/nodes/roof.d.ts +8 -8
  180. package/dist/schema/nodes/shelf.d.ts +3 -2
  181. package/dist/schema/nodes/shelf.d.ts.map +1 -1
  182. package/dist/schema/nodes/shelf.js +6 -0
  183. package/dist/schema/nodes/skylight.d.ts +10 -10
  184. package/dist/schema/nodes/slab.d.ts +3 -2
  185. package/dist/schema/nodes/slab.d.ts.map +1 -1
  186. package/dist/schema/nodes/slab.js +4 -0
  187. package/dist/schema/nodes/solar-panel.d.ts +4 -4
  188. package/dist/schema/nodes/stair-segment.d.ts +4 -4
  189. package/dist/schema/nodes/stair.d.ts +13 -12
  190. package/dist/schema/nodes/stair.d.ts.map +1 -1
  191. package/dist/schema/nodes/stair.js +3 -0
  192. package/dist/schema/nodes/turbine-vent.d.ts +2 -2
  193. package/dist/schema/nodes/wall.d.ts +245 -6
  194. package/dist/schema/nodes/wall.d.ts.map +1 -1
  195. package/dist/schema/nodes/wall.js +257 -0
  196. package/dist/schema/nodes/wall.test.d.ts +2 -0
  197. package/dist/schema/nodes/wall.test.d.ts.map +1 -0
  198. package/dist/schema/nodes/wall.test.js +208 -0
  199. package/dist/schema/nodes/window.d.ts +11 -3
  200. package/dist/schema/nodes/window.d.ts.map +1 -1
  201. package/dist/schema/nodes/window.js +12 -0
  202. package/dist/schema/nodes/zone.d.ts +2 -0
  203. package/dist/schema/nodes/zone.d.ts.map +1 -1
  204. package/dist/schema/nodes/zone.js +6 -0
  205. package/dist/schema/scene-material.d.ts +41 -0
  206. package/dist/schema/scene-material.d.ts.map +1 -0
  207. package/dist/schema/scene-material.js +9 -0
  208. package/dist/schema/types.d.ts +1089 -94
  209. package/dist/schema/types.d.ts.map +1 -1
  210. package/dist/schema/types.js +23 -0
  211. package/dist/services/alignment-anchors.d.ts.map +1 -1
  212. package/dist/services/alignment-anchors.js +30 -1
  213. package/dist/services/alignment.d.ts +5 -0
  214. package/dist/services/alignment.d.ts.map +1 -1
  215. package/dist/services/alignment.js +2 -0
  216. package/dist/services/hosting.d.ts +8 -0
  217. package/dist/services/hosting.d.ts.map +1 -1
  218. package/dist/services/hosting.js +13 -4
  219. package/dist/services/hosting.test.js +32 -1
  220. package/dist/services/index.d.ts +8 -2
  221. package/dist/services/index.d.ts.map +1 -1
  222. package/dist/services/index.js +8 -2
  223. package/dist/services/level-height.d.ts +28 -0
  224. package/dist/services/level-height.d.ts.map +1 -0
  225. package/dist/services/level-height.js +62 -0
  226. package/dist/services/opening-guides.d.ts +141 -0
  227. package/dist/services/opening-guides.d.ts.map +1 -0
  228. package/dist/services/opening-guides.js +267 -0
  229. package/dist/services/opening-guides.test.d.ts +2 -0
  230. package/dist/services/opening-guides.test.d.ts.map +1 -0
  231. package/dist/services/opening-guides.test.js +208 -0
  232. package/dist/services/port-connectivity.d.ts +115 -0
  233. package/dist/services/port-connectivity.d.ts.map +1 -0
  234. package/dist/services/port-connectivity.js +300 -0
  235. package/dist/services/port-connectivity.test.d.ts +2 -0
  236. package/dist/services/port-connectivity.test.d.ts.map +1 -0
  237. package/dist/services/port-connectivity.test.js +297 -0
  238. package/dist/services/riser-diagram.d.ts +40 -0
  239. package/dist/services/riser-diagram.d.ts.map +1 -0
  240. package/dist/services/riser-diagram.js +110 -0
  241. package/dist/services/riser-diagram.test.d.ts +2 -0
  242. package/dist/services/riser-diagram.test.d.ts.map +1 -0
  243. package/dist/services/riser-diagram.test.js +66 -0
  244. package/dist/services/snap.d.ts +9 -1
  245. package/dist/services/snap.d.ts.map +1 -1
  246. package/dist/services/snap.js +21 -1
  247. package/dist/services/snap.test.js +43 -1
  248. package/dist/services/system-graph.d.ts +30 -0
  249. package/dist/services/system-graph.d.ts.map +1 -0
  250. package/dist/services/system-graph.js +164 -0
  251. package/dist/services/system-graph.test.d.ts +2 -0
  252. package/dist/services/system-graph.test.d.ts.map +1 -0
  253. package/dist/services/system-graph.test.js +138 -0
  254. package/dist/services/validate-dwv.d.ts +32 -0
  255. package/dist/services/validate-dwv.d.ts.map +1 -0
  256. package/dist/services/validate-dwv.js +118 -0
  257. package/dist/services/validate-dwv.test.d.ts +2 -0
  258. package/dist/services/validate-dwv.test.d.ts.map +1 -0
  259. package/dist/services/validate-dwv.test.js +109 -0
  260. package/dist/store/actions/node-actions.d.ts.map +1 -1
  261. package/dist/store/actions/node-actions.js +94 -1
  262. package/dist/store/actions/ridge-vent-update.test.d.ts +2 -0
  263. package/dist/store/actions/ridge-vent-update.test.d.ts.map +1 -0
  264. package/dist/store/actions/ridge-vent-update.test.js +264 -0
  265. package/dist/store/history-control.d.ts +11 -0
  266. package/dist/store/history-control.d.ts.map +1 -1
  267. package/dist/store/history-control.js +33 -0
  268. package/dist/store/use-scene-dirty-tracking.test.d.ts +2 -0
  269. package/dist/store/use-scene-dirty-tracking.test.d.ts.map +1 -0
  270. package/dist/store/use-scene-dirty-tracking.test.js +68 -0
  271. package/dist/store/use-scene-measurement-roundtrip.test.d.ts +2 -0
  272. package/dist/store/use-scene-measurement-roundtrip.test.d.ts.map +1 -0
  273. package/dist/store/use-scene-measurement-roundtrip.test.js +97 -0
  274. package/dist/store/use-scene-plugins.test.d.ts +2 -0
  275. package/dist/store/use-scene-plugins.test.d.ts.map +1 -0
  276. package/dist/store/use-scene-plugins.test.js +51 -0
  277. package/dist/store/use-scene-wall-slot-migration.test.d.ts +2 -0
  278. package/dist/store/use-scene-wall-slot-migration.test.d.ts.map +1 -0
  279. package/dist/store/use-scene-wall-slot-migration.test.js +210 -0
  280. package/dist/store/use-scene-window-migration.test.d.ts +2 -0
  281. package/dist/store/use-scene-window-migration.test.d.ts.map +1 -0
  282. package/dist/store/use-scene-window-migration.test.js +85 -0
  283. package/dist/store/use-scene.d.ts +17 -2
  284. package/dist/store/use-scene.d.ts.map +1 -1
  285. package/dist/store/use-scene.js +358 -51
  286. package/dist/systems/elevator/elevator-service.js +1 -1
  287. package/dist/systems/fence/fence-centerline.d.ts +12 -0
  288. package/dist/systems/fence/fence-centerline.d.ts.map +1 -0
  289. package/dist/systems/fence/fence-centerline.js +37 -0
  290. package/dist/systems/fence/fence-spline.d.ts +39 -0
  291. package/dist/systems/fence/fence-spline.d.ts.map +1 -0
  292. package/dist/systems/fence/fence-spline.js +196 -0
  293. package/dist/systems/fence/fence-spline.test.d.ts +2 -0
  294. package/dist/systems/fence/fence-spline.test.d.ts.map +1 -0
  295. package/dist/systems/fence/fence-spline.test.js +136 -0
  296. package/dist/systems/stair/stair-footprint.d.ts.map +1 -1
  297. package/dist/systems/stair/stair-footprint.js +21 -11
  298. package/dist/systems/stair/stair-opening-preview.d.ts +1139 -469
  299. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  300. package/dist/systems/stair/stair-opening-sync.d.ts.map +1 -1
  301. package/dist/systems/stair/stair-opening-sync.js +1 -18
  302. package/dist/systems/stair/stair-opening-sync.test.js +39 -0
  303. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  304. package/dist/systems/wall/wall-mitering.js +38 -2
  305. package/dist/systems/wall/wall-mitering.test.d.ts +2 -0
  306. package/dist/systems/wall/wall-mitering.test.d.ts.map +1 -0
  307. package/dist/systems/wall/wall-mitering.test.js +63 -0
  308. package/dist/utils/clone-scene-graph.d.ts +1 -0
  309. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  310. package/dist/utils/clone-scene-graph.js +23 -3
  311. package/dist/utils/clone-scene-graph.test.js +3 -0
  312. package/dist/utils/heal-scene-graph.d.ts +18 -0
  313. package/dist/utils/heal-scene-graph.d.ts.map +1 -0
  314. package/dist/utils/heal-scene-graph.js +90 -0
  315. package/dist/utils/heal-scene-graph.test.d.ts +2 -0
  316. package/dist/utils/heal-scene-graph.test.d.ts.map +1 -0
  317. package/dist/utils/heal-scene-graph.test.js +88 -0
  318. package/dist/validation/validate-build-json.d.ts +1 -0
  319. package/dist/validation/validate-build-json.d.ts.map +1 -1
  320. package/dist/validation/validate-build-json.js +31 -2
  321. package/package.json +3 -3
@@ -1 +1 @@
1
- {"version":3,"file":"wall.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/wall.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAK5C,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmCpB,CAAA;AACD,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAA;AAE/C,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,UAAU,CAAA;AAErD,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;IACzC,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED,KAAK,yBAAyB,GAAG;IAC/B,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;IACzC,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,gBAAgB,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;IACjD,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,gBAAgB,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;IACjD,sBAAsB,CAAC,EAAE,MAAM,CAAA;CAChC,CAAA;AAuBD,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,yBAAyB,EAC/B,IAAI,EAAE,eAAe,GACpB,uBAAuB,CAUzB;AAED,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAKrF"}
1
+ {"version":3,"file":"wall.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/wall.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,109 @@ import { MaterialSchema } from '../material';
5
5
  import { DoorNode } from './door';
6
6
  import { ItemNode } from './item';
7
7
  import { WindowNode } from './window';
8
+ export const WallTreatmentSide = z.enum(['interior', 'exterior', 'both']);
9
+ export const WallTrimProfile = z.enum([
10
+ 'flat',
11
+ 'bevel',
12
+ 'triangle',
13
+ 'cove',
14
+ 'bullnose',
15
+ 'base-modern',
16
+ 'base-colonial',
17
+ 'base-shoe',
18
+ 'base-ogee',
19
+ 'crown-cove',
20
+ 'crown-ogee',
21
+ 'crown-craftsman',
22
+ 'crown-layered',
23
+ 'rail-rounded',
24
+ 'rail-ogee',
25
+ 'rail-picture',
26
+ 'rail-stepped',
27
+ ]);
28
+ export const WallTrimConfig = z.object({
29
+ enabled: z.boolean().default(false),
30
+ sides: WallTreatmentSide.default('both'),
31
+ height: z.number().default(0.1),
32
+ proud: z.number().default(0.015),
33
+ profile: WallTrimProfile.default('flat'),
34
+ offsetY: z.number().optional(),
35
+ });
36
+ export const WALL_SKIRTING_DEFAULT = {
37
+ enabled: false,
38
+ sides: 'both',
39
+ height: 0.12,
40
+ proud: 0.02,
41
+ profile: 'flat',
42
+ };
43
+ export const WALL_CROWN_DEFAULT = {
44
+ enabled: false,
45
+ sides: 'both',
46
+ height: 0.12,
47
+ proud: 0.055,
48
+ profile: 'flat',
49
+ };
50
+ export const WALL_CHAIR_RAIL_DEFAULT = {
51
+ enabled: false,
52
+ sides: 'both',
53
+ height: 0.055,
54
+ proud: 0.026,
55
+ profile: 'flat',
56
+ offsetY: 0.9,
57
+ };
58
+ export const WALL_TRIM_DEFAULTS = {
59
+ skirting: WALL_SKIRTING_DEFAULT,
60
+ crown: WALL_CROWN_DEFAULT,
61
+ chairRail: WALL_CHAIR_RAIL_DEFAULT,
62
+ };
63
+ const WallFaceBandConfigShape = z.object({
64
+ enabled: z.boolean().default(false),
65
+ count: z.number().int().min(1).max(4).default(1),
66
+ lowerHeight: z.number().default(0.84),
67
+ middleHeight: z.number().default(0.61),
68
+ upperHeight: z.number().default(0.61),
69
+ });
70
+ export const WallFaceBandConfig = z.preprocess((value) => {
71
+ if (value && typeof value === 'object' && !Array.isArray(value) && !('count' in value)) {
72
+ const enabled = value.enabled === true;
73
+ return { ...value, count: enabled ? 3 : 1 };
74
+ }
75
+ return value;
76
+ }, WallFaceBandConfigShape);
77
+ export const WALL_FACE_BAND_DEFAULT = {
78
+ enabled: false,
79
+ count: 1,
80
+ lowerHeight: 0.84,
81
+ middleHeight: 0.61,
82
+ upperHeight: 0.61,
83
+ };
84
+ export const WALL_SKIRTING_SLOT_DEFAULT = 'library:preset-softwhite';
85
+ export const WALL_CROWN_SLOT_DEFAULT = 'library:preset-white';
86
+ export const WALL_CHAIR_RAIL_SLOT_DEFAULT = 'library:preset-cream';
87
+ export const WALL_FACE_BAND_SOLID_SLOT_DEFAULTS = {
88
+ lower: 'library:preset-white',
89
+ middle: 'library:preset-lightgrey',
90
+ upper: 'library:preset-greige',
91
+ top: 'library:preset-softwhite',
92
+ };
93
+ export const WALL_SURFACE_SLOT_DEFAULTS = {
94
+ interior: 'library:concrete-drywall',
95
+ exterior: 'library:concrete-drywall',
96
+ lowerInterior: 'library:concrete-drywall',
97
+ middleInterior: 'library:concrete-drywall',
98
+ upperInterior: 'library:concrete-drywall',
99
+ topInterior: 'library:concrete-drywall',
100
+ lowerExterior: 'library:concrete-drywall',
101
+ middleExterior: 'library:concrete-drywall',
102
+ upperExterior: 'library:concrete-drywall',
103
+ topExterior: 'library:concrete-drywall',
104
+ skirtingInterior: WALL_SKIRTING_SLOT_DEFAULT,
105
+ skirtingExterior: WALL_SKIRTING_SLOT_DEFAULT,
106
+ crownInterior: WALL_CROWN_SLOT_DEFAULT,
107
+ crownExterior: WALL_CROWN_SLOT_DEFAULT,
108
+ chairRailInterior: WALL_CHAIR_RAIL_SLOT_DEFAULT,
109
+ chairRailExterior: WALL_CHAIR_RAIL_SLOT_DEFAULT,
110
+ };
8
111
  export const WallNode = BaseNode.extend({
9
112
  id: objectId('wall'),
10
113
  type: nodeType('wall'),
@@ -19,9 +122,20 @@ export const WallNode = BaseNode.extend({
19
122
  interiorMaterialPreset: z.string().optional(),
20
123
  exteriorMaterial: MaterialSchema.optional(),
21
124
  exteriorMaterialPreset: z.string().optional(),
125
+ // Per-slot material overrides on the unified slot model, mirroring
126
+ // `SlabNode.slots`. Key = slot id (`interior` / `exterior`), value = a
127
+ // `MaterialRef` (`library:<id>` / `scene:<id>`). Absent = the declared slot
128
+ // default (`WALL_SLOT_DEFAULT`). The legacy `*Material*` fields above are
129
+ // read only by the load migration that moves them into `slots`; delete them
130
+ // in a follow-up once migrated scenes are the norm.
131
+ slots: z.record(z.string(), z.string()).optional(),
22
132
  thickness: z.number().optional(),
23
133
  height: z.number().optional(),
24
134
  curveOffset: z.number().optional(),
135
+ faceBands: WallFaceBandConfig.optional(),
136
+ skirting: WallTrimConfig.optional(),
137
+ crown: WallTrimConfig.optional(),
138
+ chairRail: WallTrimConfig.optional(),
25
139
  // e.g., start/end points for path
26
140
  start: z.tuple([z.number(), z.number()]),
27
141
  end: z.tuple([z.number(), z.number()]),
@@ -39,6 +153,149 @@ export const WallNode = BaseNode.extend({
39
153
  - frontSide: whether the front side faces interior, exterior, or unknown
40
154
  - backSide: whether the back side faces interior, exterior, or unknown
41
155
  `);
156
+ // Declared default appearance for an unpainted wall face in colored mode —
157
+ // visual parity with the retired DEFAULT_WALL_MATERIAL. Lives in core so the
158
+ // slot declaration (nodes) and the material resolver (viewer) share one value.
159
+ // May be a `#rrggbb` colour or a `library:<id>` ref. Textures-off still
160
+ // collapses to the themed wall role (the escape hatch).
161
+ export const WALL_SLOT_DEFAULT = {
162
+ interior: WALL_SURFACE_SLOT_DEFAULTS.interior,
163
+ exterior: WALL_SURFACE_SLOT_DEFAULTS.exterior,
164
+ };
165
+ export function getWallFaceBandConfig(wall) {
166
+ const wallHeight = wall.height ?? 2.5;
167
+ const raw = { ...WALL_FACE_BAND_DEFAULT, ...(wall.faceBands ?? {}) };
168
+ const count = raw.enabled ? Math.max(1, Math.min(4, Math.round(raw.count ?? 3))) : 1;
169
+ const lowerHeight = count >= 2 ? Math.max(0, Math.min(wallHeight, raw.lowerHeight)) : 0;
170
+ const middleHeight = count >= 3 ? Math.max(0, Math.min(wallHeight - lowerHeight, raw.middleHeight)) : 0;
171
+ const upperHeight = count >= 4 ? Math.max(0, Math.min(wallHeight - lowerHeight - middleHeight, raw.upperHeight)) : 0;
172
+ return {
173
+ enabled: raw.enabled && count > 1,
174
+ count,
175
+ lowerHeight,
176
+ middleHeight,
177
+ upperHeight,
178
+ lowerTop: lowerHeight,
179
+ middleTop: lowerHeight + middleHeight,
180
+ upperTop: lowerHeight + middleHeight + upperHeight,
181
+ };
182
+ }
183
+ export function getWallFaceBandForHeight(wall, y) {
184
+ const bands = getWallFaceBandConfig(wall);
185
+ if (!bands.enabled)
186
+ return 'upper';
187
+ if (y < bands.lowerTop)
188
+ return 'lower';
189
+ if (y < bands.middleTop)
190
+ return 'middle';
191
+ if (bands.count >= 4 && y < bands.upperTop)
192
+ return 'upper';
193
+ if (bands.count >= 4)
194
+ return 'top';
195
+ return 'upper';
196
+ }
197
+ export function getWallBandSlotId(side, band) {
198
+ const suffix = side === 'interior' ? 'Interior' : 'Exterior';
199
+ return `${band}${suffix}`;
200
+ }
201
+ const WALL_FACE_BAND_SLOTS_BY_SIDE = {
202
+ interior: ['lowerInterior', 'middleInterior', 'upperInterior', 'topInterior'],
203
+ exterior: ['lowerExterior', 'middleExterior', 'upperExterior', 'topExterior'],
204
+ };
205
+ function getWallFaceBandSlotsForCount(side, count) {
206
+ if (count <= 1)
207
+ return [];
208
+ if (side === 'interior') {
209
+ if (count === 2)
210
+ return ['lowerInterior', 'upperInterior'];
211
+ if (count === 3)
212
+ return ['lowerInterior', 'middleInterior', 'upperInterior'];
213
+ return ['lowerInterior', 'middleInterior', 'upperInterior', 'topInterior'];
214
+ }
215
+ if (count === 2)
216
+ return ['lowerExterior', 'upperExterior'];
217
+ if (count === 3)
218
+ return ['lowerExterior', 'middleExterior', 'upperExterior'];
219
+ return ['lowerExterior', 'middleExterior', 'upperExterior', 'topExterior'];
220
+ }
221
+ function getWallFaceBandDefaultSlot(slotId) {
222
+ if (slotId.startsWith('lower'))
223
+ return WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower;
224
+ if (slotId.startsWith('middle'))
225
+ return WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.middle;
226
+ if (slotId.startsWith('top'))
227
+ return WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.top;
228
+ return WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.upper;
229
+ }
230
+ function getWallFaceTopBandSlot(side, count) {
231
+ const slots = getWallFaceBandSlotsForCount(side, count);
232
+ return slots[slots.length - 1] ?? null;
233
+ }
234
+ export function buildWallFaceBandCountPatch(wall, count) {
235
+ const slots = { ...(wall.slots ?? {}) };
236
+ const nextCount = Math.max(1, Math.min(4, Math.round(count)));
237
+ const previousCount = wall.faceBands?.enabled
238
+ ? Math.max(1, Math.min(4, Math.round(wall.faceBands.count ?? 3)))
239
+ : 1;
240
+ for (const side of ['interior', 'exterior']) {
241
+ const nextSlots = getWallFaceBandSlotsForCount(side, nextCount);
242
+ const activeSlots = new Set(nextSlots);
243
+ const previouslyActiveSlots = new Set(getWallFaceBandSlotsForCount(side, previousCount));
244
+ const previousTopSlot = getWallFaceTopBandSlot(side, previousCount);
245
+ const nextTopSlot = getWallFaceTopBandSlot(side, nextCount);
246
+ const topMaterial = (previousTopSlot ? slots[previousTopSlot] : undefined) ??
247
+ slots[side] ??
248
+ WALL_SURFACE_SLOT_DEFAULTS[side];
249
+ for (const slotId of WALL_FACE_BAND_SLOTS_BY_SIDE[side]) {
250
+ if (activeSlots.has(slotId)) {
251
+ if (slotId === nextTopSlot) {
252
+ slots[slotId] = topMaterial;
253
+ continue;
254
+ }
255
+ const wasActive = previouslyActiveSlots.has(slotId);
256
+ const wasPreviousTop = slotId === previousTopSlot;
257
+ if (!wasActive || wasPreviousTop || !slots[slotId]) {
258
+ slots[slotId] = getWallFaceBandDefaultSlot(slotId);
259
+ }
260
+ }
261
+ else {
262
+ delete slots[slotId];
263
+ }
264
+ }
265
+ }
266
+ return {
267
+ faceBands: {
268
+ ...WALL_FACE_BAND_DEFAULT,
269
+ ...(wall.faceBands ?? {}),
270
+ enabled: nextCount > 1,
271
+ count: nextCount,
272
+ lowerHeight: wall.faceBands?.lowerHeight ?? WALL_FACE_BAND_DEFAULT.lowerHeight,
273
+ middleHeight: wall.faceBands?.middleHeight ?? WALL_FACE_BAND_DEFAULT.middleHeight,
274
+ upperHeight: wall.faceBands?.upperHeight ?? WALL_FACE_BAND_DEFAULT.upperHeight,
275
+ },
276
+ slots,
277
+ };
278
+ }
279
+ export function buildEnabledWallFaceBandPatch(wall) {
280
+ return buildWallFaceBandCountPatch(wall, 2);
281
+ }
282
+ export function getWallSurfaceSideFromBandSlot(slotId) {
283
+ if (slotId === 'interior' || slotId === 'exterior')
284
+ return slotId;
285
+ if (slotId === 'lowerInterior' ||
286
+ slotId === 'middleInterior' ||
287
+ slotId === 'upperInterior' ||
288
+ slotId === 'topInterior') {
289
+ return 'interior';
290
+ }
291
+ if (slotId === 'lowerExterior' ||
292
+ slotId === 'middleExterior' ||
293
+ slotId === 'upperExterior' ||
294
+ slotId === 'topExterior') {
295
+ return 'exterior';
296
+ }
297
+ return null;
298
+ }
42
299
  function getConfiguredWallSurfaceMaterial(wall, side) {
43
300
  if (side === 'interior') {
44
301
  return {
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=wall.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wall.test.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/wall.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,208 @@
1
+ import { describe, expect, test } from 'bun:test';
2
+ import { buildEnabledWallFaceBandPatch, buildWallFaceBandCountPatch, getWallFaceBandConfig, WALL_CHAIR_RAIL_DEFAULT, WALL_CHAIR_RAIL_SLOT_DEFAULT, WALL_CROWN_DEFAULT, WALL_CROWN_SLOT_DEFAULT, WALL_FACE_BAND_DEFAULT, WALL_FACE_BAND_SOLID_SLOT_DEFAULTS, WALL_SKIRTING_DEFAULT, WALL_SKIRTING_SLOT_DEFAULT, WALL_SURFACE_SLOT_DEFAULTS, WallFaceBandConfig, WallTrimConfig, } from './wall';
3
+ describe('wall face bands', () => {
4
+ test('defaults to one band while preserving legacy enabled scenes as three bands', () => {
5
+ expect(WALL_FACE_BAND_DEFAULT.count).toBe(1);
6
+ expect(WALL_FACE_BAND_DEFAULT.lowerHeight).toBe(0.84);
7
+ expect(WALL_FACE_BAND_DEFAULT.middleHeight).toBe(0.61);
8
+ expect(WALL_FACE_BAND_DEFAULT.upperHeight).toBe(0.61);
9
+ expect(WallFaceBandConfig.parse({})).toEqual({
10
+ enabled: false,
11
+ count: 1,
12
+ lowerHeight: 0.84,
13
+ middleHeight: 0.61,
14
+ upperHeight: 0.61,
15
+ });
16
+ expect(WallFaceBandConfig.parse({ enabled: true })).toEqual({
17
+ enabled: true,
18
+ count: 3,
19
+ lowerHeight: 0.84,
20
+ middleHeight: 0.61,
21
+ upperHeight: 0.61,
22
+ });
23
+ expect(getWallFaceBandConfig({
24
+ height: 2.5,
25
+ faceBands: {
26
+ enabled: true,
27
+ count: 3,
28
+ lowerHeight: 0.84,
29
+ middleHeight: 0.61,
30
+ upperHeight: 0.61,
31
+ },
32
+ })).toMatchObject({
33
+ count: 3,
34
+ lowerTop: 0.84,
35
+ middleTop: 1.45,
36
+ });
37
+ });
38
+ test('four bands adds an upper split below the final top band', () => {
39
+ expect(getWallFaceBandConfig({
40
+ height: 2.5,
41
+ faceBands: {
42
+ enabled: true,
43
+ count: 4,
44
+ lowerHeight: 0.5,
45
+ middleHeight: 0.6,
46
+ upperHeight: 0.7,
47
+ },
48
+ })).toMatchObject({
49
+ count: 4,
50
+ lowerTop: 0.5,
51
+ middleTop: 1.1,
52
+ upperTop: 1.8,
53
+ });
54
+ });
55
+ test('enabling bands seeds visible solid-color band slots', () => {
56
+ const patch = buildEnabledWallFaceBandPatch({
57
+ faceBands: {
58
+ enabled: false,
59
+ count: 1,
60
+ lowerHeight: 0.2,
61
+ middleHeight: 0.3,
62
+ upperHeight: 0.61,
63
+ },
64
+ slots: {
65
+ interior: 'library:interior-finish',
66
+ exterior: 'scene:exterior-finish',
67
+ lowerInterior: 'library:stale-lower',
68
+ middleExterior: 'library:stale-middle',
69
+ },
70
+ });
71
+ expect(patch.faceBands).toEqual({
72
+ enabled: true,
73
+ count: 2,
74
+ lowerHeight: 0.2,
75
+ middleHeight: 0.3,
76
+ upperHeight: 0.61,
77
+ });
78
+ expect(patch.slots).toMatchObject({
79
+ interior: 'library:interior-finish',
80
+ exterior: 'scene:exterior-finish',
81
+ lowerInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
82
+ upperInterior: 'library:interior-finish',
83
+ lowerExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
84
+ upperExterior: 'scene:exterior-finish',
85
+ });
86
+ expect(patch.slots?.middleInterior).toBeUndefined();
87
+ expect(patch.slots?.middleExterior).toBeUndefined();
88
+ });
89
+ test('band count patch enables only the active slots', () => {
90
+ const patch = buildWallFaceBandCountPatch({
91
+ faceBands: {
92
+ enabled: true,
93
+ count: 4,
94
+ lowerHeight: 0.2,
95
+ middleHeight: 0.3,
96
+ upperHeight: 0.61,
97
+ },
98
+ slots: {
99
+ interior: 'library:interior-finish',
100
+ exterior: 'scene:exterior-finish',
101
+ topInterior: 'library:stale-top',
102
+ },
103
+ }, 3);
104
+ expect(patch.faceBands).toMatchObject({ enabled: true, count: 3 });
105
+ expect(patch.slots).toMatchObject({
106
+ lowerInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
107
+ middleInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.middle,
108
+ upperInterior: 'library:stale-top',
109
+ lowerExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
110
+ middleExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.middle,
111
+ upperExterior: 'scene:exterior-finish',
112
+ });
113
+ expect(patch.slots?.topInterior).toBeUndefined();
114
+ expect(patch.slots?.topExterior).toBeUndefined();
115
+ });
116
+ test('enabling bands replaces stale inactive band slots with solid-color defaults', () => {
117
+ const patch = buildEnabledWallFaceBandPatch({
118
+ slots: {
119
+ lowerInterior: 'library:stale-lower',
120
+ middleInterior: 'library:stale-middle',
121
+ upperExterior: 'library:stale-upper',
122
+ },
123
+ });
124
+ expect(patch.slots).toEqual({
125
+ lowerInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
126
+ upperInterior: WALL_SURFACE_SLOT_DEFAULTS.interior,
127
+ lowerExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
128
+ upperExterior: WALL_SURFACE_SLOT_DEFAULTS.exterior,
129
+ });
130
+ expect(patch.slots?.middleInterior).toBeUndefined();
131
+ expect(patch.slots?.middleExterior).toBeUndefined();
132
+ });
133
+ test('increasing band count paints newly active bands with the solid palette', () => {
134
+ const patch = buildWallFaceBandCountPatch({
135
+ faceBands: {
136
+ enabled: true,
137
+ count: 2,
138
+ lowerHeight: 0.2,
139
+ middleHeight: 0.3,
140
+ upperHeight: 0.61,
141
+ },
142
+ slots: {
143
+ lowerInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
144
+ upperInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.upper,
145
+ lowerExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
146
+ upperExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.upper,
147
+ },
148
+ }, 3);
149
+ expect(patch.slots).toMatchObject({
150
+ lowerInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
151
+ middleInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.middle,
152
+ upperInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.upper,
153
+ lowerExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
154
+ middleExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.middle,
155
+ upperExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.upper,
156
+ });
157
+ });
158
+ test('increasing to four bands keeps the previous top material on the new top band', () => {
159
+ const patch = buildWallFaceBandCountPatch({
160
+ faceBands: {
161
+ enabled: true,
162
+ count: 3,
163
+ lowerHeight: 0.2,
164
+ middleHeight: 0.3,
165
+ upperHeight: 0.61,
166
+ },
167
+ slots: {
168
+ lowerInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
169
+ middleInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.middle,
170
+ upperInterior: 'scene:painted-top-interior',
171
+ lowerExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
172
+ middleExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.middle,
173
+ upperExterior: 'library:painted-top-exterior',
174
+ },
175
+ }, 4);
176
+ expect(patch.slots).toMatchObject({
177
+ lowerInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
178
+ middleInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.middle,
179
+ upperInterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.upper,
180
+ topInterior: 'scene:painted-top-interior',
181
+ lowerExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.lower,
182
+ middleExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.middle,
183
+ upperExterior: WALL_FACE_BAND_SOLID_SLOT_DEFAULTS.upper,
184
+ topExterior: 'library:painted-top-exterior',
185
+ });
186
+ });
187
+ });
188
+ describe('wall trim profiles', () => {
189
+ test('uses curated defaults while preserving legacy profile values', () => {
190
+ expect(WALL_SKIRTING_DEFAULT.profile).toBe('flat');
191
+ expect(WALL_CROWN_DEFAULT.profile).toBe('flat');
192
+ expect(WALL_CHAIR_RAIL_DEFAULT.profile).toBe('flat');
193
+ expect(WallTrimConfig.parse({ profile: 'flat' }).profile).toBe('flat');
194
+ expect(WallTrimConfig.parse({ profile: 'crown-layered' }).profile).toBe('crown-layered');
195
+ expect(WallTrimConfig.parse({ profile: 'triangle' }).profile).toBe('triangle');
196
+ });
197
+ test('declares separate default materials for each trim family', () => {
198
+ expect(WALL_SKIRTING_SLOT_DEFAULT).toBe('library:preset-softwhite');
199
+ expect(WALL_CROWN_SLOT_DEFAULT).toBe('library:preset-white');
200
+ expect(WALL_CHAIR_RAIL_SLOT_DEFAULT).toBe('library:preset-cream');
201
+ expect(WALL_SURFACE_SLOT_DEFAULTS.skirtingInterior).toBe(WALL_SKIRTING_SLOT_DEFAULT);
202
+ expect(WALL_SURFACE_SLOT_DEFAULTS.skirtingExterior).toBe(WALL_SKIRTING_SLOT_DEFAULT);
203
+ expect(WALL_SURFACE_SLOT_DEFAULTS.crownInterior).toBe(WALL_CROWN_SLOT_DEFAULT);
204
+ expect(WALL_SURFACE_SLOT_DEFAULTS.crownExterior).toBe(WALL_CROWN_SLOT_DEFAULT);
205
+ expect(WALL_SURFACE_SLOT_DEFAULTS.chairRailInterior).toBe(WALL_CHAIR_RAIL_SLOT_DEFAULT);
206
+ expect(WALL_SURFACE_SLOT_DEFAULTS.chairRailExterior).toBe(WALL_CHAIR_RAIL_SLOT_DEFAULT);
207
+ });
208
+ });
@@ -32,7 +32,7 @@ export declare const WindowNode: z.ZodObject<{
32
32
  type: z.ZodDefault<z.ZodLiteral<"window">>;
33
33
  material: z.ZodOptional<z.ZodObject<{
34
34
  id: z.ZodOptional<z.ZodString>;
35
- preset: z.ZodOptional<z.ZodEnum<{
35
+ preset: z.ZodOptional<z.ZodCatch<z.ZodEnum<{
36
36
  custom: "custom";
37
37
  white: "white";
38
38
  brick: "brick";
@@ -43,7 +43,7 @@ export declare const WindowNode: z.ZodObject<{
43
43
  plaster: "plaster";
44
44
  tile: "tile";
45
45
  marble: "marble";
46
- }>>;
46
+ }>>>;
47
47
  properties: z.ZodOptional<z.ZodObject<{
48
48
  color: z.ZodDefault<z.ZodString>;
49
49
  roughness: z.ZodDefault<z.ZodNumber>;
@@ -62,6 +62,7 @@ export declare const WindowNode: z.ZodObject<{
62
62
  scale: z.ZodOptional<z.ZodNumber>;
63
63
  }, z.core.$strip>>;
64
64
  }, z.core.$strip>>;
65
+ slots: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
65
66
  position: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
66
67
  rotation: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
67
68
  side: z.ZodOptional<z.ZodEnum<{
@@ -69,6 +70,13 @@ export declare const WindowNode: z.ZodObject<{
69
70
  back: "back";
70
71
  }>>;
71
72
  wallId: z.ZodOptional<z.ZodString>;
73
+ roofSegmentId: z.ZodOptional<z.ZodString>;
74
+ roofFace: z.ZodOptional<z.ZodEnum<{
75
+ front: "front";
76
+ back: "back";
77
+ right: "right";
78
+ left: "left";
79
+ }>>;
72
80
  width: z.ZodDefault<z.ZodNumber>;
73
81
  height: z.ZodDefault<z.ZodNumber>;
74
82
  openingKind: z.ZodDefault<z.ZodEnum<{
@@ -97,8 +105,8 @@ export declare const WindowNode: z.ZodObject<{
97
105
  single: "single";
98
106
  }>>;
99
107
  hingesSide: z.ZodDefault<z.ZodEnum<{
100
- left: "left";
101
108
  right: "right";
109
+ left: "left";
102
110
  }>>;
103
111
  openingShape: z.ZodDefault<z.ZodEnum<{
104
112
  rectangle: "rectangle";
@@ -1 +1 @@
1
- {"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/window.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,UAAU;;;;;;;;;;;EAWrB,CAAA;AACF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA;AAEnD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2DrB,CAAA;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA"}
1
+ {"version":3,"file":"window.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/window.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,UAAU;;;;;;;;;;;EAWrB,CAAA;AACF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA;AAEnD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuErB,CAAA;AAEF,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA"}
@@ -18,11 +18,23 @@ export const WindowNode = BaseNode.extend({
18
18
  id: objectId('window'),
19
19
  type: nodeType('window'),
20
20
  material: MaterialSchema.optional(),
21
+ // Per-slot material overrides on the unified slot model. Keys: `frame`,
22
+ // `glass`. Value = a `MaterialRef` (`library:<id>` / `scene:<id>`). Absent =
23
+ // the frame/glass default. Mirrors `ShelfNode.slots`.
24
+ slots: z.record(z.string(), z.string()).optional(),
21
25
  position: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
22
26
  rotation: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
23
27
  side: z.enum(['front', 'back']).optional(),
24
28
  // Wall reference
25
29
  wallId: z.string().optional(),
30
+ // Alternative host: a roof-segment's generated wall face (base wall
31
+ // under the roof or a coplanar gable end). When set, `position` is
32
+ // FACE-LOCAL — [u along the face, v height, z from the wall mid-plane]
33
+ // — exactly the wall-child convention; the renderer mounts the node
34
+ // inside the face frame (`getRoofWallFaceFrame`), which is what makes
35
+ // hosted children track segment resizes live.
36
+ roofSegmentId: z.string().optional(),
37
+ roofFace: z.enum(['front', 'back', 'right', 'left']).optional(),
26
38
  // Overall dimensions
27
39
  width: z.number().default(1.5),
28
40
  height: z.number().default(1.5),
@@ -17,6 +17,8 @@ export declare const ZoneNode: z.ZodObject<{
17
17
  type: z.ZodDefault<z.ZodLiteral<"zone">>;
18
18
  name: z.ZodString;
19
19
  polygon: z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>;
20
+ autoFromWalls: z.ZodDefault<z.ZodBoolean>;
21
+ boundaryWallIds: z.ZodDefault<z.ZodArray<z.ZodDefault<z.ZodTemplateLiteral<`wall_${string}`>>>>;
20
22
  color: z.ZodDefault<z.ZodString>;
21
23
  metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
22
24
  }, z.core.$strip>;
@@ -1 +1 @@
1
- {"version":3,"file":"zone.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/zone.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;iBAoBpB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAA"}
1
+ {"version":3,"file":"zone.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/zone.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;iBA0BpB,CAAA;AAED,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,QAAQ,CAAC,CAAA"}
@@ -7,6 +7,10 @@ export const ZoneNode = BaseNode.extend({
7
7
  name: z.string(),
8
8
  // Polygon boundary - array of [x, z] coordinates defining the zone
9
9
  polygon: z.array(z.tuple([z.number(), z.number()])),
10
+ // Procedural room zones retain the walls that prove their enclosure. The
11
+ // stored polygon remains a fallback for missing or temporarily open walls.
12
+ autoFromWalls: z.boolean().default(false),
13
+ boundaryWallIds: z.array(objectId('wall')).default([]),
10
14
  // Visual styling
11
15
  color: z.string().default('#3b82f6'), // Default blue
12
16
  metadata: z.json().optional().default({}),
@@ -17,6 +21,8 @@ export const ZoneNode = BaseNode.extend({
17
21
  - levelId: level this zone is attached to
18
22
  - name: zone name
19
23
  - polygon: array of [x, z] points defining the zone boundary
24
+ - autoFromWalls: whether the boundary follows an enclosed wall loop
25
+ - boundaryWallIds: wall ids that prove the procedural enclosure
20
26
  - color: hex color for visual styling
21
27
  - metadata: zone metadata (optional)
22
28
  `);
@@ -0,0 +1,41 @@
1
+ import { z } from 'zod';
2
+ export type SceneMaterialId = `mat_${string}`;
3
+ export declare const generateSceneMaterialId: () => SceneMaterialId;
4
+ export declare const SceneMaterial: z.ZodObject<{
5
+ id: z.ZodString;
6
+ name: z.ZodString;
7
+ material: z.ZodObject<{
8
+ id: z.ZodOptional<z.ZodString>;
9
+ preset: z.ZodOptional<z.ZodCatch<z.ZodEnum<{
10
+ custom: "custom";
11
+ white: "white";
12
+ brick: "brick";
13
+ concrete: "concrete";
14
+ wood: "wood";
15
+ glass: "glass";
16
+ metal: "metal";
17
+ plaster: "plaster";
18
+ tile: "tile";
19
+ marble: "marble";
20
+ }>>>;
21
+ properties: z.ZodOptional<z.ZodObject<{
22
+ color: z.ZodDefault<z.ZodString>;
23
+ roughness: z.ZodDefault<z.ZodNumber>;
24
+ metalness: z.ZodDefault<z.ZodNumber>;
25
+ opacity: z.ZodDefault<z.ZodNumber>;
26
+ transparent: z.ZodDefault<z.ZodBoolean>;
27
+ side: z.ZodDefault<z.ZodEnum<{
28
+ front: "front";
29
+ back: "back";
30
+ double: "double";
31
+ }>>;
32
+ }, z.core.$strip>>;
33
+ texture: z.ZodOptional<z.ZodObject<{
34
+ url: z.ZodString;
35
+ repeat: z.ZodOptional<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>;
36
+ scale: z.ZodOptional<z.ZodNumber>;
37
+ }, z.core.$strip>>;
38
+ }, z.core.$strip>;
39
+ }, z.core.$strip>;
40
+ export type SceneMaterial = z.infer<typeof SceneMaterial>;
41
+ //# sourceMappingURL=scene-material.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene-material.d.ts","sourceRoot":"","sources":["../../src/schema/scene-material.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,MAAM,MAAM,eAAe,GAAG,OAAO,MAAM,EAAE,CAAA;AAC7C,eAAO,MAAM,uBAAuB,QAAO,eAAoC,CAAA;AAE/E,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAIxB,CAAA;AACF,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA"}