@pascal-app/core 1.0.0-beta.5 → 1.0.0

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 (231) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +23 -0
  3. package/dist/capture/index.d.ts +3 -0
  4. package/dist/capture/index.d.ts.map +1 -0
  5. package/dist/capture/index.js +2 -0
  6. package/dist/capture/schema.d.ts +417 -0
  7. package/dist/capture/schema.d.ts.map +1 -0
  8. package/dist/capture/schema.js +348 -0
  9. package/dist/capture/source.d.ts +60 -0
  10. package/dist/capture/source.d.ts.map +1 -0
  11. package/dist/capture/source.js +254 -0
  12. package/dist/events/bus.d.ts +55 -7
  13. package/dist/events/bus.d.ts.map +1 -1
  14. package/dist/events/hidden-wall-pointer-hold.d.ts +28 -0
  15. package/dist/events/hidden-wall-pointer-hold.d.ts.map +1 -0
  16. package/dist/events/hidden-wall-pointer-hold.js +37 -0
  17. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +2785 -1
  18. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  19. package/dist/hooks/spatial-grid/spatial-grid-sync.js +132 -19
  20. package/dist/hooks/spatial-grid/support-host-patch.d.ts +45 -1
  21. package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -1
  22. package/dist/hooks/spatial-grid/support-host-patch.js +171 -6
  23. package/dist/index.d.ts +14 -6
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +16 -5
  26. package/dist/lib/asset-storage.d.ts.map +1 -1
  27. package/dist/lib/asset-storage.js +4 -1
  28. package/dist/lib/polygon-union.d.ts +4 -0
  29. package/dist/lib/polygon-union.d.ts.map +1 -0
  30. package/dist/lib/polygon-union.js +306 -0
  31. package/dist/lib/roof-overlap.d.ts +32 -0
  32. package/dist/lib/roof-overlap.d.ts.map +1 -0
  33. package/dist/lib/roof-overlap.js +72 -0
  34. package/dist/lib/slab-polygon.d.ts +35 -2
  35. package/dist/lib/slab-polygon.d.ts.map +1 -1
  36. package/dist/lib/slab-polygon.js +133 -27
  37. package/dist/lib/space-detection.d.ts +11 -0
  38. package/dist/lib/space-detection.d.ts.map +1 -1
  39. package/dist/lib/space-detection.js +42 -14
  40. package/dist/registry/handles.d.ts +24 -3
  41. package/dist/registry/handles.d.ts.map +1 -1
  42. package/dist/registry/index.d.ts +3 -4
  43. package/dist/registry/index.d.ts.map +1 -1
  44. package/dist/registry/index.js +1 -2
  45. package/dist/registry/registry.d.ts +13 -6
  46. package/dist/registry/registry.d.ts.map +1 -1
  47. package/dist/registry/registry.js +37 -4
  48. package/dist/registry/scene-api.d.ts +16 -0
  49. package/dist/registry/scene-api.d.ts.map +1 -1
  50. package/dist/registry/scene-api.js +49 -1
  51. package/dist/registry/types.d.ts +226 -13
  52. package/dist/registry/types.d.ts.map +1 -1
  53. package/dist/schema/__bench__/node-parsers.bench.d.ts +24 -0
  54. package/dist/schema/__bench__/node-parsers.bench.d.ts.map +1 -0
  55. package/dist/schema/__bench__/node-parsers.bench.js +314 -0
  56. package/dist/schema/__fixtures__/node-fixtures.d.ts +28 -0
  57. package/dist/schema/__fixtures__/node-fixtures.d.ts.map +1 -0
  58. package/dist/schema/__fixtures__/node-fixtures.js +125 -0
  59. package/dist/schema/base.d.ts +1 -1
  60. package/dist/schema/base.d.ts.map +1 -1
  61. package/dist/schema/base.js +8 -1
  62. package/dist/schema/compiled-node-parsers.d.ts +40 -0
  63. package/dist/schema/compiled-node-parsers.d.ts.map +1 -0
  64. package/dist/schema/compiled-node-parsers.js +95 -0
  65. package/dist/schema/index.d.ts +19 -15
  66. package/dist/schema/index.d.ts.map +1 -1
  67. package/dist/schema/index.js +17 -12
  68. package/dist/schema/material.d.ts +2 -1
  69. package/dist/schema/material.d.ts.map +1 -1
  70. package/dist/schema/material.js +1 -0
  71. package/dist/schema/nodes/automatic-downspout.d.ts +17 -0
  72. package/dist/schema/nodes/automatic-downspout.d.ts.map +1 -0
  73. package/dist/schema/nodes/automatic-downspout.js +237 -0
  74. package/dist/schema/nodes/block.d.ts +107 -0
  75. package/dist/schema/nodes/block.d.ts.map +1 -0
  76. package/dist/schema/nodes/block.js +207 -0
  77. package/dist/schema/nodes/box-vent.d.ts +8 -2
  78. package/dist/schema/nodes/box-vent.d.ts.map +1 -1
  79. package/dist/schema/nodes/box-vent.js +2 -0
  80. package/dist/schema/nodes/building.d.ts +1 -1
  81. package/dist/schema/nodes/cabinet.d.ts +25 -3
  82. package/dist/schema/nodes/cabinet.d.ts.map +1 -1
  83. package/dist/schema/nodes/cabinet.js +26 -5
  84. package/dist/schema/nodes/ceiling.d.ts +1 -1
  85. package/dist/schema/nodes/chimney.d.ts +2 -2
  86. package/dist/schema/nodes/column.d.ts +6 -6
  87. package/dist/schema/nodes/construction-dimension.d.ts +4 -4
  88. package/dist/schema/nodes/cupola.d.ts +9 -1
  89. package/dist/schema/nodes/cupola.d.ts.map +1 -1
  90. package/dist/schema/nodes/cupola.js +2 -0
  91. package/dist/schema/nodes/door.d.ts +1 -1
  92. package/dist/schema/nodes/dormer.d.ts +44 -1
  93. package/dist/schema/nodes/dormer.d.ts.map +1 -1
  94. package/dist/schema/nodes/dormer.js +131 -7
  95. package/dist/schema/nodes/downspout.d.ts +11 -1
  96. package/dist/schema/nodes/downspout.d.ts.map +1 -1
  97. package/dist/schema/nodes/downspout.js +24 -0
  98. package/dist/schema/nodes/duct-fitting.d.ts +18 -1
  99. package/dist/schema/nodes/duct-fitting.d.ts.map +1 -1
  100. package/dist/schema/nodes/duct-fitting.js +25 -4
  101. package/dist/schema/nodes/duct-segment.d.ts +23 -1
  102. package/dist/schema/nodes/duct-segment.d.ts.map +1 -1
  103. package/dist/schema/nodes/duct-segment.js +20 -0
  104. package/dist/schema/nodes/duct-terminal.d.ts +1 -1
  105. package/dist/schema/nodes/elevator.d.ts +1 -1
  106. package/dist/schema/nodes/eyebrow-vent.d.ts +8 -2
  107. package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -1
  108. package/dist/schema/nodes/eyebrow-vent.js +2 -0
  109. package/dist/schema/nodes/fence.d.ts +1 -1
  110. package/dist/schema/nodes/guide.d.ts +1 -1
  111. package/dist/schema/nodes/gutter.d.ts +36 -2
  112. package/dist/schema/nodes/gutter.d.ts.map +1 -1
  113. package/dist/schema/nodes/gutter.js +308 -1
  114. package/dist/schema/nodes/hanger-overrides.d.ts +7 -0
  115. package/dist/schema/nodes/hanger-overrides.d.ts.map +1 -0
  116. package/dist/schema/nodes/hanger-overrides.js +6 -0
  117. package/dist/schema/nodes/hvac-equipment.d.ts +1 -1
  118. package/dist/schema/nodes/item.d.ts +4 -3
  119. package/dist/schema/nodes/item.d.ts.map +1 -1
  120. package/dist/schema/nodes/item.js +5 -0
  121. package/dist/schema/nodes/lean-to-extension.d.ts +212 -0
  122. package/dist/schema/nodes/lean-to-extension.d.ts.map +1 -0
  123. package/dist/schema/nodes/lean-to-extension.js +114 -0
  124. package/dist/schema/nodes/level.d.ts +2 -2
  125. package/dist/schema/nodes/level.d.ts.map +1 -1
  126. package/dist/schema/nodes/lineset.d.ts +1 -1
  127. package/dist/schema/nodes/liquid-line.d.ts +1 -1
  128. package/dist/schema/nodes/measurement.d.ts +1 -1
  129. package/dist/schema/nodes/pipe-fitting.d.ts +9 -1
  130. package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -1
  131. package/dist/schema/nodes/pipe-fitting.js +6 -2
  132. package/dist/schema/nodes/pipe-segment.d.ts +23 -1
  133. package/dist/schema/nodes/pipe-segment.d.ts.map +1 -1
  134. package/dist/schema/nodes/pipe-segment.js +20 -0
  135. package/dist/schema/nodes/pipe-trap.d.ts +1 -1
  136. package/dist/schema/nodes/ridge-vent.d.ts +1 -1
  137. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
  138. package/dist/schema/nodes/ridge-vent.js +4 -1
  139. package/dist/schema/nodes/roof-segment-shape.d.ts +4 -0
  140. package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -1
  141. package/dist/schema/nodes/roof-segment-shape.js +64 -1
  142. package/dist/schema/nodes/roof-segment-walls.d.ts +3 -1
  143. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -1
  144. package/dist/schema/nodes/roof-segment-walls.js +1 -1
  145. package/dist/schema/nodes/roof-segment.d.ts +41 -1
  146. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  147. package/dist/schema/nodes/roof-segment.js +79 -2
  148. package/dist/schema/nodes/roof.d.ts +22 -1
  149. package/dist/schema/nodes/roof.d.ts.map +1 -1
  150. package/dist/schema/nodes/roof.js +14 -0
  151. package/dist/schema/nodes/scan.d.ts +19 -2
  152. package/dist/schema/nodes/scan.d.ts.map +1 -1
  153. package/dist/schema/nodes/scan.js +11 -1
  154. package/dist/schema/nodes/shelf.d.ts +2 -2
  155. package/dist/schema/nodes/site.d.ts +1 -1
  156. package/dist/schema/nodes/skylight.d.ts +1 -1
  157. package/dist/schema/nodes/slab.d.ts +1 -1
  158. package/dist/schema/nodes/solar-panel.d.ts +1 -1
  159. package/dist/schema/nodes/spawn.d.ts +1 -1
  160. package/dist/schema/nodes/stair-segment.d.ts +1 -1
  161. package/dist/schema/nodes/stair.d.ts +1 -1
  162. package/dist/schema/nodes/structural-grid.d.ts +1 -1
  163. package/dist/schema/nodes/turbine-vent.d.ts +7 -1
  164. package/dist/schema/nodes/turbine-vent.d.ts.map +1 -1
  165. package/dist/schema/nodes/turbine-vent.js +2 -0
  166. package/dist/schema/nodes/wall.d.ts +4 -4
  167. package/dist/schema/nodes/wall.d.ts.map +1 -1
  168. package/dist/schema/nodes/wall.js +7 -1
  169. package/dist/schema/nodes/window.d.ts +10 -3
  170. package/dist/schema/nodes/window.d.ts.map +1 -1
  171. package/dist/schema/nodes/window.js +4 -0
  172. package/dist/schema/nodes/zone.d.ts +2 -2
  173. package/dist/schema/nodes/zone.js +1 -1
  174. package/dist/schema/types.d.ts +484 -109
  175. package/dist/schema/types.d.ts.map +1 -1
  176. package/dist/schema/types.js +27 -1
  177. package/dist/services/hosting.d.ts +2 -2
  178. package/dist/services/hosting.d.ts.map +1 -1
  179. package/dist/services/hosting.js +4 -4
  180. package/dist/services/index.d.ts +1 -1
  181. package/dist/services/index.d.ts.map +1 -1
  182. package/dist/services/index.js +1 -1
  183. package/dist/services/system-graph.d.ts +11 -0
  184. package/dist/services/system-graph.d.ts.map +1 -1
  185. package/dist/services/system-graph.js +35 -5
  186. package/dist/store/actions/node-actions.d.ts +7 -0
  187. package/dist/store/actions/node-actions.d.ts.map +1 -1
  188. package/dist/store/actions/node-actions.js +429 -17
  189. package/dist/store/history-invalidation.d.ts +3 -0
  190. package/dist/store/history-invalidation.d.ts.map +1 -0
  191. package/dist/store/history-invalidation.js +72 -0
  192. package/dist/store/scene-hydration.d.ts +5 -0
  193. package/dist/store/scene-hydration.d.ts.map +1 -0
  194. package/dist/store/scene-hydration.js +57 -0
  195. package/dist/store/use-scene.d.ts +3 -0
  196. package/dist/store/use-scene.d.ts.map +1 -1
  197. package/dist/store/use-scene.js +332 -64
  198. package/dist/systems/roof/roof-elevation-system.d.ts +3 -0
  199. package/dist/systems/roof/roof-elevation-system.d.ts.map +1 -0
  200. package/dist/systems/roof/roof-elevation-system.js +94 -0
  201. package/dist/systems/roof/roof-elevation.d.ts +4 -0
  202. package/dist/systems/roof/roof-elevation.d.ts.map +1 -0
  203. package/dist/systems/roof/roof-elevation.js +95 -0
  204. package/dist/systems/roof/roof-footprint.d.ts +17 -0
  205. package/dist/systems/roof/roof-footprint.d.ts.map +1 -0
  206. package/dist/systems/roof/roof-footprint.js +83 -0
  207. package/dist/systems/stair/stair-flight.d.ts +17 -0
  208. package/dist/systems/stair/stair-flight.d.ts.map +1 -0
  209. package/dist/systems/stair/stair-flight.js +27 -0
  210. package/dist/systems/stair/stair-opening-preview.d.ts +1555 -1328
  211. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  212. package/dist/systems/stair/stair-opening-system.d.ts +1 -0
  213. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
  214. package/dist/systems/stair/stair-opening-system.js +93 -96
  215. package/dist/systems/stair/stair-rise.d.ts.map +1 -1
  216. package/dist/systems/stair/stair-rise.js +20 -21
  217. package/dist/systems/wall/wall-curve.d.ts +1 -0
  218. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  219. package/dist/systems/wall/wall-curve.js +73 -0
  220. package/dist/systems/wall/wall-footprint.d.ts +1 -0
  221. package/dist/systems/wall/wall-footprint.d.ts.map +1 -1
  222. package/dist/systems/wall/wall-footprint.js +1 -0
  223. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  224. package/dist/utils/clone-scene-graph.js +26 -0
  225. package/dist/validation/validate-build-json.d.ts +3 -0
  226. package/dist/validation/validate-build-json.d.ts.map +1 -1
  227. package/dist/validation/validate-build-json.js +49 -2
  228. package/package.json +10 -3
  229. package/dist/systems/elevator/elevator-runtime-system.d.ts +0 -2
  230. package/dist/systems/elevator/elevator-runtime-system.d.ts.map +0 -1
  231. package/dist/systems/elevator/elevator-runtime-system.js +0 -8
@@ -4,6 +4,18 @@ export declare const CabinetFrontStyleSchema: z.ZodEnum<{
4
4
  shaker: "shaker";
5
5
  "raised-arch": "raised-arch";
6
6
  }>;
7
+ export declare const CabinetTopFinishSchema: z.ZodEnum<{
8
+ trim: "trim";
9
+ none: "none";
10
+ "top-cabinet": "top-cabinet";
11
+ }>;
12
+ /** Canonical metric cabinet family used when no regional profile is selected. */
13
+ export declare const CABINET_METRIC_DEFAULTS: {
14
+ readonly depth: 0.6;
15
+ readonly carcassHeight: 0.8;
16
+ readonly plinthHeight: 0.1;
17
+ readonly countertopThickness: 0.02;
18
+ };
7
19
  declare const CabinetCompartment: z.ZodDiscriminatedUnion<[z.ZodObject<{
8
20
  type: z.ZodLiteral<"shelf">;
9
21
  shelfCount: z.ZodOptional<z.ZodNumber>;
@@ -123,7 +135,7 @@ export declare const CabinetNode: z.ZodObject<{
123
135
  fov: z.ZodOptional<z.ZodNumber>;
124
136
  zoom: z.ZodOptional<z.ZodNumber>;
125
137
  }, z.core.$strip>>;
126
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
138
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
127
139
  position: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
128
140
  rotation: z.ZodDefault<z.ZodNumber>;
129
141
  supportSlabId: z.ZodOptional<z.ZodString>;
@@ -145,6 +157,7 @@ export declare const CabinetNode: z.ZodObject<{
145
157
  shaker: "shaker";
146
158
  "raised-arch": "raised-arch";
147
159
  }>>;
160
+ panelReady: z.ZodDefault<z.ZodBoolean>;
148
161
  handleStyle: z.ZodDefault<z.ZodEnum<{
149
162
  none: "none";
150
163
  bar: "bar";
@@ -308,7 +321,7 @@ export declare const CabinetNode: z.ZodObject<{
308
321
  base: "base";
309
322
  tall: "tall";
310
323
  }>>;
311
- children: z.ZodDefault<z.ZodArray<z.ZodDefault<z.ZodTemplateLiteral<`cabinet-module_${string}`>>>>;
324
+ children: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodDefault<z.ZodTemplateLiteral<`cabinet-module_${string}`>>, z.ZodDefault<z.ZodTemplateLiteral<`cabinet_${string}`>>]>>>;
312
325
  barLedge: z.ZodOptional<z.ZodObject<{
313
326
  edge: z.ZodDefault<z.ZodEnum<{
314
327
  back: "back";
@@ -319,6 +332,7 @@ export declare const CabinetNode: z.ZodObject<{
319
332
  depth: z.ZodDefault<z.ZodNumber>;
320
333
  }, z.core.$strip>>;
321
334
  withWaterfall: z.ZodDefault<z.ZodBoolean>;
335
+ withFinishedEnds: z.ZodDefault<z.ZodBoolean>;
322
336
  }, z.core.$strip>;
323
337
  export declare const CabinetModuleNode: z.ZodObject<{
324
338
  object: z.ZodDefault<z.ZodLiteral<"node">>;
@@ -335,7 +349,7 @@ export declare const CabinetModuleNode: z.ZodObject<{
335
349
  fov: z.ZodOptional<z.ZodNumber>;
336
350
  zoom: z.ZodOptional<z.ZodNumber>;
337
351
  }, z.core.$strip>>;
338
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
352
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
339
353
  position: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
340
354
  rotation: z.ZodDefault<z.ZodNumber>;
341
355
  supportSlabId: z.ZodOptional<z.ZodString>;
@@ -357,6 +371,7 @@ export declare const CabinetModuleNode: z.ZodObject<{
357
371
  shaker: "shaker";
358
372
  "raised-arch": "raised-arch";
359
373
  }>>;
374
+ panelReady: z.ZodDefault<z.ZodBoolean>;
360
375
  handleStyle: z.ZodDefault<z.ZodEnum<{
361
376
  none: "none";
362
377
  bar: "bar";
@@ -529,6 +544,13 @@ export declare const CabinetModuleNode: z.ZodObject<{
529
544
  left: "left";
530
545
  }>>;
531
546
  cornerShelf: z.ZodOptional<z.ZodBoolean>;
547
+ topFinish: z.ZodDefault<z.ZodEnum<{
548
+ trim: "trim";
549
+ none: "none";
550
+ "top-cabinet": "top-cabinet";
551
+ }>>;
552
+ topFinishHeight: z.ZodDefault<z.ZodNumber>;
553
+ topFinishDepth: z.ZodDefault<z.ZodNumber>;
532
554
  }, z.core.$strip>;
533
555
  export type CabinetNode = z.infer<typeof CabinetNode>;
534
556
  export type CabinetModuleNode = z.infer<typeof CabinetModuleNode>;
@@ -1 +1 @@
1
- {"version":3,"file":"cabinet.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/cabinet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAgBvB,eAAO,MAAM,uBAAuB;;;;EAA4C,CAAA;AAMhF,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAmDtB,CAAA;AAEF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAqCzE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAiB0B,CAAA;AAElD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgB+B,CAAA;AAE7D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAA;AACrD,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
1
+ {"version":3,"file":"cabinet.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/cabinet.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAgBvB,eAAO,MAAM,uBAAuB;;;;EAA4C,CAAA;AAChF,eAAO,MAAM,sBAAsB;;;;EAA0C,CAAA;AAE7E,iFAAiF;AACjF,eAAO,MAAM,uBAAuB;;;;;CAK1B,CAAA;AAMV,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BAmDtB,CAAA;AAEF,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AA2CzE,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmB0B,CAAA;AAElD,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqB+B,CAAA;AAE7D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAA;AACrD,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAA"}
@@ -12,6 +12,14 @@ const cooktopFields = {
12
12
  cooktopShowGrate: z.boolean().optional(),
13
13
  };
14
14
  export const CabinetFrontStyleSchema = z.enum(['slab', 'shaker', 'raised-arch']);
15
+ export const CabinetTopFinishSchema = z.enum(['none', 'top-cabinet', 'trim']);
16
+ /** Canonical metric cabinet family used when no regional profile is selected. */
17
+ export const CABINET_METRIC_DEFAULTS = {
18
+ depth: 0.6,
19
+ carcassHeight: 0.8,
20
+ plinthHeight: 0.1,
21
+ countertopThickness: 0.02,
22
+ };
15
23
  // Discriminated on `type` so invalid field combinations (a drawer with a
16
24
  // pantry rack style, a fridge with burner state) are unrepresentable. New
17
25
  // compartment kinds add a variant here rather than widening a shared bag of
@@ -76,13 +84,17 @@ const cabinetBoxFields = {
76
84
  // Persisted slab-support host — see ItemNode.supportSlabId for the rules.
77
85
  supportSlabId: z.string().optional(),
78
86
  width: z.number().min(0.05).max(3).default(0.5),
79
- depth: z.number().min(0.3).max(1.2).default(0.5),
80
- carcassHeight: z.number().min(0.4).max(2.4).default(0.72),
87
+ depth: z.number().min(0.3).max(1.2).default(CABINET_METRIC_DEFAULTS.depth),
88
+ carcassHeight: z.number().min(0.4).max(2.4).default(CABINET_METRIC_DEFAULTS.carcassHeight),
81
89
  operationState: z.number().min(0).max(1).default(0),
82
- plinthHeight: z.number().min(0).max(0.3).default(0.1),
90
+ plinthHeight: z.number().min(0).max(0.3).default(CABINET_METRIC_DEFAULTS.plinthHeight),
83
91
  toeKickDepth: z.number().min(0).max(0.2).default(0.075),
84
92
  boardThickness: z.number().min(0.01).max(0.08).default(0.018),
85
- countertopThickness: z.number().min(0).max(0.08).default(0.02),
93
+ countertopThickness: z
94
+ .number()
95
+ .min(0)
96
+ .max(0.08)
97
+ .default(CABINET_METRIC_DEFAULTS.countertopThickness),
86
98
  countertopOverhang: z.number().min(0).max(0.12).default(0.02),
87
99
  // Extra slab reach off the back edge (island seating side) — up to a
88
100
  // 45 cm knee-space overhang, unlike the small uniform front/side overhang.
@@ -91,6 +103,8 @@ const cabinetBoxFields = {
91
103
  frontThickness: z.number().min(0.01).max(0.05).default(0.018),
92
104
  frontGap: z.number().min(0.001).max(0.02).default(0.003),
93
105
  frontStyle: CabinetFrontStyleSchema.default('slab'),
106
+ // Fridge-only: replace the appliance door face with a cabinet-matched panel.
107
+ panelReady: z.boolean().default(false),
94
108
  handleStyle: z.enum(['none', 'bar', 'cutout', 'hole', 'knob']).default('bar'),
95
109
  handlePosition: z.enum(['auto', 'top', 'center']).default('auto'),
96
110
  frontOverlay: z.enum(['full', 'inset']).default('full'),
@@ -106,7 +120,7 @@ export const CabinetNode = BaseNode.extend({
106
120
  id: objectId('cabinet'),
107
121
  type: nodeType('cabinet'),
108
122
  runTier: z.enum(['base', 'wall', 'tall']).default('base'),
109
- children: z.array(objectId('cabinet-module')).default([]),
123
+ children: z.array(z.union([objectId('cabinet-module'), objectId('cabinet')])).default([]),
110
124
  // Raised bar counter along one run edge: a knee wall topped by a slab at
111
125
  // bar height. Run-level because it spans modules like the countertop.
112
126
  barLedge: z
@@ -118,6 +132,8 @@ export const CabinetNode = BaseNode.extend({
118
132
  .optional(),
119
133
  // Countertop material dropping to the floor on exposed run ends.
120
134
  withWaterfall: z.boolean().default(false),
135
+ // Add matching decorative panels to ends that are not joined to another run.
136
+ withFinishedEnds: z.boolean().default(false),
121
137
  ...cabinetBoxFields,
122
138
  }).describe('Parametric modular cabinet run node');
123
139
  export const CabinetModuleNode = BaseNode.extend({
@@ -135,5 +151,10 @@ export const CabinetModuleNode = BaseNode.extend({
135
151
  // Corner-pocket fillers carry a small internal shelf so the dead corner reads
136
152
  // as reachable storage instead of an empty boxed void.
137
153
  cornerShelf: z.boolean().optional(),
154
+ // Optional upper termination for wall/tall compositions. It is deliberately
155
+ // separate from carcassHeight so the main cabinet proportions stay stable.
156
+ topFinish: CabinetTopFinishSchema.default('none'),
157
+ topFinishHeight: z.number().min(0).max(1.2).default(0.33),
158
+ topFinishDepth: z.number().min(0.15).max(1.2).default(0.32),
138
159
  ...cabinetBoxFields,
139
160
  }).describe('Parametric module inside a modular cabinet run');
@@ -14,7 +14,7 @@ export declare const CeilingNode: z.ZodObject<{
14
14
  fov: z.ZodOptional<z.ZodNumber>;
15
15
  zoom: z.ZodOptional<z.ZodNumber>;
16
16
  }, z.core.$strip>>;
17
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
17
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
18
18
  id: z.ZodDefault<z.ZodTemplateLiteral<`ceiling_${string}`>>;
19
19
  type: z.ZodDefault<z.ZodLiteral<"ceiling">>;
20
20
  children: z.ZodDefault<z.ZodArray<z.ZodDefault<z.ZodTemplateLiteral<`item_${string}`>>>>;
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  export declare const ChimneyMaterialRole: z.ZodEnum<{
3
- top: "top";
4
3
  body: "body";
4
+ top: "top";
5
5
  }>;
6
6
  export type ChimneyMaterialRole = z.infer<typeof ChimneyMaterialRole>;
7
7
  export declare const ChimneyNode: z.ZodObject<{
@@ -19,7 +19,7 @@ export declare const ChimneyNode: z.ZodObject<{
19
19
  fov: z.ZodOptional<z.ZodNumber>;
20
20
  zoom: z.ZodOptional<z.ZodNumber>;
21
21
  }, z.core.$strip>>;
22
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
22
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
23
23
  id: z.ZodDefault<z.ZodTemplateLiteral<`chimney_${string}`>>;
24
24
  type: z.ZodDefault<z.ZodLiteral<"chimney">>;
25
25
  material: z.ZodOptional<z.ZodObject<{
@@ -58,14 +58,14 @@ export declare const ColumnCapitalStyle: z.ZodEnum<{
58
58
  "wood-bracket": "wood-bracket";
59
59
  }>;
60
60
  export declare const ColumnRingPlacement: z.ZodEnum<{
61
+ top: "top";
61
62
  ends: "ends";
62
63
  even: "even";
63
- top: "top";
64
64
  bottom: "bottom";
65
65
  }>;
66
66
  export declare const ColumnCarvingPlacement: z.ZodEnum<{
67
- shaft: "shaft";
68
67
  base: "base";
68
+ shaft: "shaft";
69
69
  capital: "capital";
70
70
  all: "all";
71
71
  }>;
@@ -107,7 +107,7 @@ export declare const ColumnNode: z.ZodObject<{
107
107
  fov: z.ZodOptional<z.ZodNumber>;
108
108
  zoom: z.ZodOptional<z.ZodNumber>;
109
109
  }, z.core.$strip>>;
110
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
110
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
111
111
  id: z.ZodDefault<z.ZodTemplateLiteral<`column_${string}`>>;
112
112
  type: z.ZodDefault<z.ZodLiteral<"column">>;
113
113
  position: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
@@ -206,9 +206,9 @@ export declare const ColumnNode: z.ZodObject<{
206
206
  capitalCarvingLevel: z.ZodDefault<z.ZodNumber>;
207
207
  ringCount: z.ZodDefault<z.ZodNumber>;
208
208
  ringPlacement: z.ZodDefault<z.ZodEnum<{
209
+ top: "top";
209
210
  ends: "ends";
210
211
  even: "even";
211
- top: "top";
212
212
  bottom: "bottom";
213
213
  }>>;
214
214
  ringThickness: z.ZodDefault<z.ZodNumber>;
@@ -227,15 +227,15 @@ export declare const ColumnNode: z.ZodObject<{
227
227
  }>>;
228
228
  latheRingCount: z.ZodDefault<z.ZodNumber>;
229
229
  latheRingSpacing: z.ZodDefault<z.ZodEnum<{
230
+ top: "top";
230
231
  ends: "ends";
231
232
  even: "even";
232
- top: "top";
233
233
  bottom: "bottom";
234
234
  }>>;
235
235
  carvingLevel: z.ZodDefault<z.ZodNumber>;
236
236
  carvingPlacement: z.ZodDefault<z.ZodEnum<{
237
- shaft: "shaft";
238
237
  base: "base";
238
+ shaft: "shaft";
239
239
  capital: "capital";
240
240
  all: "all";
241
241
  }>>;
@@ -25,8 +25,8 @@ export declare const ConstructionDrawingType: z.ZodEnum<{
25
25
  "site-plan": "site-plan";
26
26
  }>;
27
27
  export declare const ConstructionDimensionDrawingPresentation: z.ZodEnum<{
28
- shown: "shown";
29
28
  omit: "omit";
29
+ shown: "shown";
30
30
  controlled: "controlled";
31
31
  }>;
32
32
  export declare const ConstructionDimensionDrawingOverride: z.ZodObject<{
@@ -38,8 +38,8 @@ export declare const ConstructionDimensionDrawingOverride: z.ZodObject<{
38
38
  "site-plan": "site-plan";
39
39
  }>;
40
40
  presentation: z.ZodEnum<{
41
- shown: "shown";
42
41
  omit: "omit";
42
+ shown: "shown";
43
43
  controlled: "controlled";
44
44
  }>;
45
45
  suppressedSegmentIndexes: z.ZodDefault<z.ZodArray<z.ZodNumber>>;
@@ -86,7 +86,7 @@ export declare const ConstructionDimensionNode: z.ZodObject<{
86
86
  fov: z.ZodOptional<z.ZodNumber>;
87
87
  zoom: z.ZodOptional<z.ZodNumber>;
88
88
  }, z.core.$strip>>;
89
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
89
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
90
90
  id: z.ZodDefault<z.ZodTemplateLiteral<`construction-dimension_${string}`>>;
91
91
  type: z.ZodDefault<z.ZodLiteral<"construction-dimension">>;
92
92
  anchors: z.ZodDefault<z.ZodArray<z.ZodUnion<readonly [z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>, z.ZodObject<{
@@ -166,8 +166,8 @@ export declare const ConstructionDimensionNode: z.ZodObject<{
166
166
  "site-plan": "site-plan";
167
167
  }>;
168
168
  presentation: z.ZodEnum<{
169
- shown: "shown";
170
169
  omit: "omit";
170
+ shown: "shown";
171
171
  controlled: "controlled";
172
172
  }>;
173
173
  suppressedSegmentIndexes: z.ZodDefault<z.ZodArray<z.ZodNumber>>;
@@ -1,4 +1,11 @@
1
1
  import { z } from 'zod';
2
+ export declare const CupolaMaterialRole: z.ZodEnum<{
3
+ body: "body";
4
+ roof: "roof";
5
+ base: "base";
6
+ louvers: "louvers";
7
+ }>;
8
+ export type CupolaMaterialRole = z.infer<typeof CupolaMaterialRole>;
2
9
  export declare const CupolaNode: z.ZodObject<{
3
10
  object: z.ZodDefault<z.ZodLiteral<"node">>;
4
11
  name: z.ZodOptional<z.ZodString>;
@@ -14,7 +21,7 @@ export declare const CupolaNode: z.ZodObject<{
14
21
  fov: z.ZodOptional<z.ZodNumber>;
15
22
  zoom: z.ZodOptional<z.ZodNumber>;
16
23
  }, z.core.$strip>>;
17
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
24
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
18
25
  id: z.ZodDefault<z.ZodTemplateLiteral<`cupola_${string}`>>;
19
26
  type: z.ZodDefault<z.ZodLiteral<"cupola">>;
20
27
  material: z.ZodOptional<z.ZodObject<{
@@ -49,6 +56,7 @@ export declare const CupolaNode: z.ZodObject<{
49
56
  scale: z.ZodOptional<z.ZodNumber>;
50
57
  }, z.core.$strip>>;
51
58
  }, z.core.$strip>>;
59
+ slots: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
52
60
  materialPreset: z.ZodDefault<z.ZodString>;
53
61
  roofSegmentId: z.ZodOptional<z.ZodString>;
54
62
  position: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
@@ -1 +1 @@
1
- {"version":3,"file":"cupola.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/cupola.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6BtB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA"}
1
+ {"version":3,"file":"cupola.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/cupola.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,kBAAkB;;;;;EAA8C,CAAA;AAC7E,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAA;AAEnE,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8BtB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA"}
@@ -2,10 +2,12 @@ import dedent from 'dedent';
2
2
  import { z } from 'zod';
3
3
  import { BaseNode, nodeType, objectId } from '../base';
4
4
  import { MaterialSchema } from '../material';
5
+ export const CupolaMaterialRole = z.enum(['base', 'body', 'roof', 'louvers']);
5
6
  export const CupolaNode = BaseNode.extend({
6
7
  id: objectId('cupola'),
7
8
  type: nodeType('cupola'),
8
9
  material: MaterialSchema.optional(),
10
+ slots: z.record(z.string(), z.string()).optional(),
9
11
  // Default to the white preset so a freshly-placed cupola reads as clean
10
12
  // painted metal and the paint inspector shows "White" (matches box-vent).
11
13
  materialPreset: z.string().default('preset-white'),
@@ -64,7 +64,7 @@ export declare const DoorNode: z.ZodObject<{
64
64
  fov: z.ZodOptional<z.ZodNumber>;
65
65
  zoom: z.ZodOptional<z.ZodNumber>;
66
66
  }, z.core.$strip>>;
67
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
67
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
68
68
  id: z.ZodDefault<z.ZodTemplateLiteral<`door_${string}`>>;
69
69
  type: z.ZodDefault<z.ZodLiteral<"door">>;
70
70
  material: z.ZodOptional<z.ZodObject<{
@@ -1,10 +1,24 @@
1
1
  import { z } from 'zod';
2
2
  import { MaterialSchema } from '../material';
3
+ import { type RoofSegmentNode } from './roof-segment';
4
+ import { WindowNode } from './window';
3
5
  export type DormerSurfaceMaterialRole = 'top' | 'side' | 'wall';
4
6
  export type DormerSurfaceMaterialSpec = {
5
7
  material?: z.infer<typeof MaterialSchema>;
6
8
  materialPreset?: string;
7
9
  };
10
+ export declare const DormerWallFace: z.ZodEnum<{
11
+ front: "front";
12
+ back: "back";
13
+ right: "right";
14
+ left: "left";
15
+ }>;
16
+ export type DormerWallFace = z.infer<typeof DormerWallFace>;
17
+ export type DormerWallFaceFrame = {
18
+ origin: [number, number, number];
19
+ yaw: number;
20
+ width: number;
21
+ };
8
22
  /**
9
23
  * Default dormer dimensions and window controls. Values match the
10
24
  * legacy archive so existing scenes don't shift visually.
@@ -44,7 +58,7 @@ export declare const DormerNode: z.ZodObject<{
44
58
  fov: z.ZodOptional<z.ZodNumber>;
45
59
  zoom: z.ZodOptional<z.ZodNumber>;
46
60
  }, z.core.$strip>>;
47
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
61
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
48
62
  id: z.ZodDefault<z.ZodTemplateLiteral<`dormer_${string}`>>;
49
63
  type: z.ZodDefault<z.ZodLiteral<"dormer">>;
50
64
  material: z.ZodOptional<z.ZodObject<{
@@ -193,8 +207,13 @@ export declare const DormerNode: z.ZodObject<{
193
207
  gambrel: "gambrel";
194
208
  dutch: "dutch";
195
209
  mansard: "mansard";
210
+ conical: "conical";
196
211
  }>>;
197
212
  roofHeight: z.ZodDefault<z.ZodNumber>;
213
+ shedHighSide: z.ZodDefault<z.ZodEnum<{
214
+ front: "front";
215
+ back: "back";
216
+ }>>;
198
217
  wallSkirtHeight: z.ZodDefault<z.ZodNumber>;
199
218
  windowWidth: z.ZodDefault<z.ZodNumber>;
200
219
  windowHeight: z.ZodDefault<z.ZodNumber>;
@@ -215,8 +234,31 @@ export declare const DormerNode: z.ZodObject<{
215
234
  windowSill: z.ZodDefault<z.ZodBoolean>;
216
235
  windowSillDepth: z.ZodDefault<z.ZodNumber>;
217
236
  windowSillThickness: z.ZodDefault<z.ZodNumber>;
237
+ children: z.ZodDefault<z.ZodArray<z.ZodDefault<z.ZodTemplateLiteral<`window_${string}`>>>>;
218
238
  }, z.core.$strip>;
219
239
  export type DormerNode = z.infer<typeof DormerNode>;
240
+ export declare function getDormerWallFaceFrame(dormer: Pick<DormerNode, 'width' | 'depth'>, face: DormerWallFace): DormerWallFaceFrame;
241
+ export declare function dormerWallFacePointToDormer(dormer: Pick<DormerNode, 'width' | 'depth'>, face: DormerWallFace, point: [number, number, number]): [number, number, number];
242
+ export declare function dormerPointToWallFace(dormer: Pick<DormerNode, 'width' | 'depth'>, face: DormerWallFace, point: [number, number, number]): [number, number, number];
243
+ export declare function getDormerWallVerticalBounds(dormer: Pick<DormerNode, 'height' | 'wallSkirtHeight'>): {
244
+ min: number;
245
+ max: number;
246
+ };
247
+ type DormerWallProfile = Pick<DormerNode, 'width' | 'depth' | 'height' | 'wallSkirtHeight' | 'roofType' | 'roofHeight' | 'shedHighSide'>;
248
+ export declare function getDormerWallOpeningVerticalBounds(dormer: DormerWallProfile, face: DormerWallFace, centerX: number, width: number): {
249
+ min: number;
250
+ max: number;
251
+ };
252
+ export declare function getDormerWallHorizontalBoundsAtHeight(dormer: DormerWallProfile, face: DormerWallFace, height: number): {
253
+ min: number;
254
+ max: number;
255
+ };
256
+ export declare function getDormerExposedFaces(dormer: Pick<DormerNode, 'depth' | 'position' | 'rotation' | 'wallSkirtHeight' | 'windowOffsetY'>, hostSegment: RoofSegmentNode): {
257
+ front: boolean;
258
+ back: boolean;
259
+ };
260
+ export declare function getDormerDefaultWindowFace(dormer: Pick<DormerNode, 'depth' | 'position' | 'rotation' | 'wallSkirtHeight' | 'windowOffsetY'>, hostSegment?: RoofSegmentNode): Extract<DormerWallFace, 'front' | 'back'>;
261
+ export declare function createDormerDefaultWindow(dormer: Pick<DormerNode, 'id' | 'width' | 'wallSkirtHeight' | 'windowWidth' | 'windowHeight' | 'windowOffsetX' | 'windowOffsetY' | 'windowFrameThickness' | 'windowFrameDepth' | 'windowColumns' | 'windowRows' | 'windowDividerThickness' | 'windowShape' | 'windowArchHeight' | 'windowCornerRadii' | 'windowSill' | 'windowSillDepth' | 'windowSillThickness'>, id: string, face?: Extract<DormerWallFace, 'front' | 'back'>): WindowNode;
220
262
  /**
221
263
  * Per-surface material resolution. Fall-through order:
222
264
  * top → topMaterial[Preset] → legacy
@@ -225,4 +267,5 @@ export type DormerNode = z.infer<typeof DormerNode>;
225
267
  * where legacy is `node.material` / `node.materialPreset`.
226
268
  */
227
269
  export declare function getEffectiveDormerSurfaceMaterial(node: DormerNode, role: DormerSurfaceMaterialRole): DormerSurfaceMaterialSpec;
270
+ export {};
228
271
  //# sourceMappingURL=dormer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"dormer.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/dormer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAG5C,MAAM,MAAM,yBAAyB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;AAC/D,MAAM,MAAM,yBAAyB,GAAG;IACtC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAA;IACzC,cAAc,CAAC,EAAE,MAAM,CAAA;CACxB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;CAmBlB,CAAA;AASV,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA4DtB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA;AAEnD;;;;;;GAMG;AACH,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,yBAAyB,GAC9B,yBAAyB,CAuB3B"}
1
+ {"version":3,"file":"dormer.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/dormer.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,9 @@ import dedent from 'dedent';
2
2
  import { z } from 'zod';
3
3
  import { BaseNode, nodeType, objectId } from '../base';
4
4
  import { MaterialSchema } from '../material';
5
- import { RoofType } from './roof-segment';
5
+ import { getRoofSegmentSurfaceY, RoofType } from './roof-segment';
6
+ import { WindowNode } from './window';
7
+ export const DormerWallFace = z.enum(['front', 'back', 'right', 'left']);
6
8
  /**
7
9
  * Default dormer dimensions and window controls. Values match the
8
10
  * legacy archive so existing scenes don't shift visually.
@@ -52,13 +54,13 @@ export const DormerNode = BaseNode.extend({
52
54
  height: z.number().default(DORMER_DEFAULTS.WALL_HEIGHT),
53
55
  roofType: RoofType.default('gable'),
54
56
  roofHeight: z.number().default(DORMER_DEFAULTS.ROOF_HEIGHT),
57
+ shedHighSide: z.enum(['back', 'front']).default('back'),
55
58
  // Height of the hung wall (the "skirt") that extends below the eave
56
59
  // into the host roof — this is the wall area the window opening is
57
60
  // cut through. Larger values let the dormer host taller windows.
58
61
  wallSkirtHeight: z.number().default(DORMER_DEFAULTS.WALL_SKIRT_HEIGHT),
59
- // Window is rendered as parametric geometry on the dormer's front
60
- // face not a child node. The fields below mirror the legacy panel
61
- // controls; geometry beyond the simple opening box is deferred.
62
+ // Legacy inline-window controls. Existing scenes are promoted to a hosted
63
+ // WindowNode during scene migration; these fields remain for archive data.
62
64
  windowWidth: z.number().default(DORMER_DEFAULTS.WINDOW_WIDTH),
63
65
  windowHeight: z.number().default(DORMER_DEFAULTS.WINDOW_HEIGHT),
64
66
  windowOffsetX: z.number().default(DORMER_DEFAULTS.WINDOW_OFFSET_X),
@@ -79,13 +81,135 @@ export const DormerNode = BaseNode.extend({
79
81
  windowSill: z.boolean().default(false),
80
82
  windowSillDepth: z.number().default(DORMER_DEFAULTS.WINDOW_SILL_DEPTH),
81
83
  windowSillThickness: z.number().default(DORMER_DEFAULTS.WINDOW_SILL_THICKNESS),
84
+ // Hosted windows use the same recursive scene-graph contract as walls and
85
+ // roof segments. Legacy window* fields above are retained for migration.
86
+ children: z.array(WindowNode.shape.id).default([]),
82
87
  }).describe(dedent `
83
88
  Dormer — a small house-shaped protrusion sitting on top of a roof
84
89
  segment. width × depth × height defines the box base; roofType and
85
- roofHeight define the dormer's own roof shape. The window opening
86
- is parametric geometry on the dormer's front face, not a hosted
87
- child node.
90
+ roofHeight define the dormer's own roof shape. shedHighSide controls
91
+ the pitch direction for shed roofs. WindowNode children are hosted on
92
+ its wall faces and use the regular window item model.
88
93
  `);
94
+ export function getDormerWallFaceFrame(dormer, face) {
95
+ switch (face) {
96
+ case 'back':
97
+ return { origin: [0, 0, -dormer.depth / 2], yaw: Math.PI, width: dormer.width };
98
+ case 'right':
99
+ return { origin: [dormer.width / 2, 0, 0], yaw: Math.PI / 2, width: dormer.depth };
100
+ case 'left':
101
+ return { origin: [-dormer.width / 2, 0, 0], yaw: -Math.PI / 2, width: dormer.depth };
102
+ default:
103
+ return { origin: [0, 0, dormer.depth / 2], yaw: 0, width: dormer.width };
104
+ }
105
+ }
106
+ export function dormerWallFacePointToDormer(dormer, face, point) {
107
+ const frame = getDormerWallFaceFrame(dormer, face);
108
+ const cos = Math.cos(frame.yaw);
109
+ const sin = Math.sin(frame.yaw);
110
+ const [x, y, z] = point;
111
+ return [
112
+ frame.origin[0] + x * cos + z * sin,
113
+ frame.origin[1] + y,
114
+ frame.origin[2] - x * sin + z * cos,
115
+ ];
116
+ }
117
+ export function dormerPointToWallFace(dormer, face, point) {
118
+ const frame = getDormerWallFaceFrame(dormer, face);
119
+ const cos = Math.cos(frame.yaw);
120
+ const sin = Math.sin(frame.yaw);
121
+ const dx = point[0] - frame.origin[0];
122
+ const dz = point[2] - frame.origin[2];
123
+ return [cos * dx - sin * dz, point[1] - frame.origin[1], sin * dx + cos * dz];
124
+ }
125
+ export function getDormerWallVerticalBounds(dormer) {
126
+ return {
127
+ min: -(dormer.wallSkirtHeight ?? DORMER_DEFAULTS.WALL_SKIRT_HEIGHT),
128
+ max: Math.max(0, dormer.height),
129
+ };
130
+ }
131
+ function getDormerWallCeilingAt(dormer, face, faceX) {
132
+ const eaveHeight = Math.max(0, dormer.height);
133
+ if (dormer.roofType !== 'shed')
134
+ return eaveHeight;
135
+ const depth = Math.max(dormer.depth, Number.EPSILON);
136
+ const [, , dormerZ] = dormerWallFacePointToDormer(dormer, face, [faceX, 0, 0]);
137
+ const frontWeight = Math.max(0, Math.min(1, dormerZ / depth + 0.5));
138
+ const highSideWeight = dormer.shedHighSide === 'front' ? frontWeight : 1 - frontWeight;
139
+ return eaveHeight + Math.max(0, dormer.roofHeight) * highSideWeight;
140
+ }
141
+ export function getDormerWallOpeningVerticalBounds(dormer, face, centerX, width) {
142
+ const halfWidth = width / 2;
143
+ return {
144
+ min: -(dormer.wallSkirtHeight ?? DORMER_DEFAULTS.WALL_SKIRT_HEIGHT),
145
+ max: Math.min(getDormerWallCeilingAt(dormer, face, centerX - halfWidth), getDormerWallCeilingAt(dormer, face, centerX + halfWidth)),
146
+ };
147
+ }
148
+ export function getDormerWallHorizontalBoundsAtHeight(dormer, face, height) {
149
+ const halfWidth = getDormerWallFaceFrame(dormer, face).width / 2;
150
+ const leftCeiling = getDormerWallCeilingAt(dormer, face, -halfWidth);
151
+ const rightCeiling = getDormerWallCeilingAt(dormer, face, halfWidth);
152
+ if (height <= Math.min(leftCeiling, rightCeiling)) {
153
+ return { min: -halfWidth, max: halfWidth };
154
+ }
155
+ if (leftCeiling === rightCeiling) {
156
+ return { min: -halfWidth, max: halfWidth };
157
+ }
158
+ const crossing = -halfWidth + ((height - leftCeiling) / (rightCeiling - leftCeiling)) * (halfWidth * 2);
159
+ if (rightCeiling > leftCeiling) {
160
+ const min = Math.min(halfWidth, crossing);
161
+ return { min, max: halfWidth };
162
+ }
163
+ const max = Math.max(-halfWidth, crossing);
164
+ return { min: -halfWidth, max };
165
+ }
166
+ const DORMER_WINDOW_CENTER_MIN_CLEARANCE = 0.01;
167
+ export function getDormerExposedFaces(dormer, hostSegment) {
168
+ const halfDepth = dormer.depth / 2;
169
+ const [dormerX, dormerY, dormerZ] = dormer.position;
170
+ const faceDX = halfDepth * Math.sin(dormer.rotation);
171
+ const faceDZ = halfDepth * Math.cos(dormer.rotation);
172
+ const windowCenterY = dormerY - dormer.wallSkirtHeight / 2 + dormer.windowOffsetY;
173
+ const clears = (faceX, faceZ) => windowCenterY - getRoofSegmentSurfaceY(hostSegment, faceX, faceZ) >
174
+ DORMER_WINDOW_CENTER_MIN_CLEARANCE;
175
+ return {
176
+ front: clears(dormerX + faceDX, dormerZ + faceDZ),
177
+ back: clears(dormerX - faceDX, dormerZ - faceDZ),
178
+ };
179
+ }
180
+ export function getDormerDefaultWindowFace(dormer, hostSegment) {
181
+ if (!hostSegment)
182
+ return 'front';
183
+ const exposed = getDormerExposedFaces(dormer, hostSegment);
184
+ return !exposed.front && exposed.back ? 'back' : 'front';
185
+ }
186
+ export function createDormerDefaultWindow(dormer, id, face = 'front') {
187
+ const skirt = dormer.wallSkirtHeight ?? DORMER_DEFAULTS.WALL_SKIRT_HEIGHT;
188
+ const equalRatios = (count) => Array.from({ length: Math.max(1, count) }, () => 1);
189
+ return WindowNode.parse({
190
+ id,
191
+ parentId: dormer.id,
192
+ dormerId: dormer.id,
193
+ dormerFace: face,
194
+ position: [dormer.windowOffsetX, -skirt / 2 + dormer.windowOffsetY, 0],
195
+ rotation: [0, 0, 0],
196
+ side: 'front',
197
+ width: dormer.windowWidth,
198
+ height: dormer.windowHeight,
199
+ openingShape: dormer.windowShape,
200
+ archHeight: dormer.windowArchHeight,
201
+ openingCornerRadii: dormer.windowCornerRadii,
202
+ frameThickness: dormer.windowFrameThickness,
203
+ frameDepth: dormer.windowFrameDepth,
204
+ columnRatios: equalRatios(dormer.windowColumns),
205
+ rowRatios: equalRatios(dormer.windowRows),
206
+ columnDividerThickness: dormer.windowDividerThickness,
207
+ rowDividerThickness: dormer.windowDividerThickness,
208
+ sill: dormer.windowSill,
209
+ sillDepth: dormer.windowSillDepth,
210
+ sillThickness: dormer.windowSillThickness,
211
+ });
212
+ }
89
213
  /**
90
214
  * Per-surface material resolution. Fall-through order:
91
215
  * top → topMaterial[Preset] → legacy
@@ -14,7 +14,7 @@ export declare const DownspoutNode: z.ZodObject<{
14
14
  fov: z.ZodOptional<z.ZodNumber>;
15
15
  zoom: z.ZodOptional<z.ZodNumber>;
16
16
  }, z.core.$strip>>;
17
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
17
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
18
18
  id: z.ZodDefault<z.ZodTemplateLiteral<`downspout_${string}`>>;
19
19
  type: z.ZodDefault<z.ZodLiteral<"downspout">>;
20
20
  material: z.ZodOptional<z.ZodObject<{
@@ -49,10 +49,15 @@ export declare const DownspoutNode: z.ZodObject<{
49
49
  scale: z.ZodOptional<z.ZodNumber>;
50
50
  }, z.core.$strip>>;
51
51
  }, z.core.$strip>>;
52
+ slots: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
52
53
  materialPreset: z.ZodDefault<z.ZodString>;
53
54
  gutterId: z.ZodOptional<z.ZodString>;
54
55
  outletId: z.ZodOptional<z.ZodString>;
55
56
  length: z.ZodDefault<z.ZodNumber>;
57
+ lengthMode: z.ZodOptional<z.ZodEnum<{
58
+ manual: "manual";
59
+ "to-ground": "to-ground";
60
+ }>>;
56
61
  diameter: z.ZodDefault<z.ZodNumber>;
57
62
  standoff: z.ZodDefault<z.ZodNumber>;
58
63
  shape: z.ZodDefault<z.ZodEnum<{
@@ -72,4 +77,9 @@ export declare const DownspoutNode: z.ZodObject<{
72
77
  }>>;
73
78
  }, z.core.$strip>;
74
79
  export type DownspoutNode = z.infer<typeof DownspoutNode>;
80
+ export declare function defaultDownspoutMetadata(): {
81
+ generatedBy: string;
82
+ };
83
+ export declare function isDefaultDownspoutNode(node: unknown, gutterId?: string): node is DownspoutNode;
84
+ export declare function usesAutomaticDownspoutLength(node: DownspoutNode): boolean;
75
85
  //# sourceMappingURL=downspout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"downspout.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/downspout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkEzB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA"}
1
+ {"version":3,"file":"downspout.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/downspout.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAMvB,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoEzB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AASzD,wBAAgB,wBAAwB;;EAEvC;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,IAAI,aAAa,CAK9F;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAKzE"}